libstp
Robotics library for Botball
Loading...
Searching...
No Matches
linear_motion.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <memory>
4#include <optional>
5#include <utility>
6#include <vector>
7
8#include <Eigen/Core>
9
10#include "motion/motion.hpp"
11#include "motion/motion_pid.hpp"
13#include "foundation/types.hpp"
14
15namespace libstp::motion
16{
18 enum class LinearAxis { Forward, Lateral };
19
28 {
30 double distance_m{0.0};
31 double speed_scale{1.0}; // 0-1 fraction of AxisConstraints.max_velocity
32
36 double target_heading_rad{0.0};
37
47 };
48
51 {
52 double time_s{0.0}; // elapsed since start
53 double dt{0.0}; // this cycle's dt
54 // Position
55 double target_m{0.0}; // target distance
56 double position_m{0.0}; // actual primary axis position
57 double predicted_m{0.0}; // profile setpoint position
58 double cross_track_m{0.0}; // cross-track drift
59 // Errors
60 double distance_error_m{0.0}; // target - actual
61 double actual_error_m{0.0}; // target - actual
62 double yaw_error_rad{0.0}; // heading error
63 // Velocity
65 // Commands (after clamp + scaling)
66 double cmd_vx_mps{0.0}; // final commanded vx
67 double cmd_vy_mps{0.0}; // final commanded vy
68 double cmd_wz_radps{0.0}; // final commanded omega
69 // Raw PID outputs (before clamp/scaling)
70 double pid_primary_raw{0.0}; // profiled PID raw output
71 double pid_cross_raw{0.0}; // cross-track PID raw output
72 double pid_heading_raw{0.0}; // heading PID raw output
73 // Profile state
76 // State
77 double heading_rad{0.0}; // current heading
78 double speed_scale{1.0};
79 double heading_scale{1.0};
80 bool saturated{false};
81 };
82
89 class LinearMotion final : public Motion
90 {
91 public:
93
94 void start() override;
95 void update(double dt) override;
96 [[nodiscard]] bool isFinished() const override;
97
108 void startWarm(double position_offset_m, double initial_velocity_mps);
109
111 void setSuppressHardStopOnComplete(bool suppress) { suppress_hard_stop_ = suppress; }
112
114 [[nodiscard]] bool hasReachedDistance() const;
115
117 [[nodiscard]] double getFilteredVelocity() const { return filtered_velocity_; }
118
120 [[nodiscard]] const std::vector<LinearMotionTelemetry>& getTelemetry() const { return telemetry_; }
121
124 void setOmegaOverride(double omega) { omega_override_ = omega; }
125 void clearOmegaOverride() { omega_override_.reset(); }
126
127 private:
128 void complete();
129
132 void captureInitialPose();
133
141 [[nodiscard]] std::pair<double, double> projectBodyFrame() const;
142
143 LinearMotionConfig cfg_{};
144 double max_velocity_{0.0}; // computed from speed_scale * AxisConstraints
145 std::unique_ptr<foundation::PidController> heading_pid_;
146 ProfiledPIDController profiled_pid_;
147 Eigen::Vector2d initial_position_m_{Eigen::Vector2d::Zero()};
148 double initial_heading_rad_{0.0};
149 bool finished_{false};
150 bool suppress_hard_stop_{false};
151 double position_offset_m_{0.0}; // subtracted from odometry in warm-start mode
152 double speed_scale_{1.0};
153 double heading_scale_{1.0};
154 int unsaturated_cycles_{0};
155
156 // Velocity tracking for settling detection
157 double prev_primary_position_{0.0};
158 double filtered_velocity_{0.0};
159 static constexpr double kVelocityFilterAlpha{0.3};
160 static constexpr double kSettlingVelocity{0.02}; // m/s - must be nearly stopped to declare done
161
162 // External omega override (replaces heading PID when set)
163 std::optional<double> omega_override_{};
164
165 // Slew-limit state for the internal heading-hold omega output
166 double prev_omega_cmd_{0.0};
167
168 // Telemetry
169 double elapsed_time_{0.0};
170 // At 100 Hz update rate, 30 s of motion = 3000 samples × ~80 bytes
171 // ≈ 240 KB. Capping at this size prevents long-running motions
172 // (timeouts, condition-driven drives) from leaking memory across an
173 // autonomous period. Older samples are dropped from the front; the
174 // most recent window is what's interesting for tuning anyway.
175 static constexpr size_t kMaxTelemetrySamples{3000};
176 std::vector<LinearMotionTelemetry> telemetry_;
177 };
178}
void setOmegaOverride(double omega)
const std::vector< LinearMotionTelemetry > & getTelemetry() const
LinearMotion(MotionContext ctx, LinearMotionConfig config)
void setSuppressHardStopOnComplete(bool suppress)
bool isFinished() const override
void startWarm(double position_offset_m, double initial_velocity_mps)
void update(double dt) override
Motion(MotionContext ctx)
Definition motion.hpp:35