HoloLib
High-performance holonomic (X-Drive) control library for VEX V5
Loading...
Searching...
No Matches
chassis.h
Go to the documentation of this file.
1#pragma once
2
3#include "Eigen/Core"
4#include "Eigen/Dense"
5#include "Eigen/Geometry"
6#include "PID.h"
7#include "api.h"
8#include "hololib/config.h"
11#include "hololib/obstacle.h"
12#include "hololib/path.h"
13#include "hololib/pose.h"
14#include "hololib/pose_ekf.h"
15#include "hololib/replay.h"
17#include "motion_handler.h"
18#include "pros/adi.hpp"
19#include "pros/rotation.hpp"
20#include <algorithm>
21#include <cmath>
22#include <functional>
23#include <limits>
24#include <string>
25#include <vector>
26
27/**
28 * @brief The main Chassis controller class.
29 *
30 * Integrates odometry, PID tuning via scheduling, autonomous movement APIs,
31 * driver control functions, obstacle avoidance, and path following algorithms.
32 */
33class Chassis {
34public:
35 /**
36 * @brief Construct a new Chassis object.
37 *
38 * @param fl Front left motor.
39 * @param fr Front right motor.
40 * @param bl Back left motor.
41 * @param br Back right motor.
42 * @param imu_sensor IMU sensor for heading.
43 * @param config The hardware configuration.
44 */
45 Chassis(pros::Motor fl, pros::Motor fr, pros::Motor bl, pros::Motor br,
46 pros::Imu imu_sensor, ChassisConfig config);
47
48 /**
49 * @brief Calibrates sensors (e.g. resets IMU, zeros encoders).
50 */
51 void calibrate();
52
53 /**
54 * @brief Provide scheduled gains for the X-axis translation controller.
55 *
56 * @param steps A vector of ScheduledGain objects.
57 */
58 void setXGains(std::vector<ScheduledGain> steps);
59
60 /**
61 * @brief Provide scheduled gains for the Y-axis translation controller.
62 *
63 * @param steps A vector of ScheduledGain objects.
64 */
65 void setYGains(std::vector<ScheduledGain> steps);
66
67 /**
68 * @brief Provide scheduled gains for the rotational (Theta) controller.
69 *
70 * @param steps A vector of ScheduledGain objects.
71 */
72 void setThetaGains(std::vector<ScheduledGain> steps);
73
74 /**
75 * @brief Manually reset the robot's odometry position.
76 *
77 * @param x X coordinate.
78 * @param y Y coordinate.
79 * @param theta Heading angle in degrees.
80 */
81 void setPose(float x, float y, float theta = 0.0f);
82
83 /**
84 * @brief Reset the robot's odometry position to a Pose object.
85 *
86 * @param pose The Pose object representing the new position and heading.
87 */
88 void setPose(Pose pose);
89
90 /**
91 * @brief Get the current odometry pose of the robot.
92 *
93 * @param radians True to return heading in radians, false for degrees.
94 * @return Pose The current pose.
95 */
96 Pose getPose(bool radians = false);
97
98 /**
99 * @brief Calculate the individual motor voltages for a holonomic movement
100 * command.
101 *
102 * @param vx Desired X velocity.
103 * @param vy Desired Y velocity.
104 * @param vt Desired rotational velocity.
105 * @return XDriveVoltages Structure containing the voltages for the 4 motors.
106 */
107 XDriveVoltages calculateHolonomic(float vx, float vy, float vt);
108
109 /**
110 * @brief Command the base motors with a set of voltages.
111 *
112 * @param v Struct containing voltages.
113 */
115
116 /**
117 * @brief Instructs all motors to brake using their configured brake mode.
118 */
119 void brake();
120
121 /**
122 * @brief Main driver control mapping logic.
123 *
124 * Maps forward, sideways, and rotational input to motor commands. Allows for
125 * field-centric or robot-centric control modes with customizable curves.
126 *
127 * @param forward Forward translation input (typically from a joystick).
128 * @param sideways Sideways translation input.
129 * @param rotation Rotational input.
130 * @param drivecurves Optional curves to smooth inputs.
131 * @param fieldCentric True if driver inputs map to absolute field axes
132 * instead of relative to the robot heading.
133 * @param headingOffset An offset to adjust the definition of "forward" for
134 * field-centric mode.
135 * @param correction Configuration for maintaining heading.
136 */
137 void driveControl(float forward, float sideways, float rotation,
138 DriveCurves drivecurves, bool fieldCentric,
139 float headingOffset = 0.0f,
140 DriveCorrection correction = {});
141
142 /**
143 * @brief Automatic, clockwise, or counter-clockwise rotation preference.
144 */
145 enum class CurveDirection { Auto, CW, CCW };
146
147 /**
148 * @brief Status of the Obstacle Avoidance subsystem.
149 */
150 enum class AvoidanceMode { Off, On };
151
152 /**
153 * @brief Autonomously follow a path defined by points.
154 *
155 * @param path A vector of path points to follow.
156 * @param lookahead_inches Pure-pursuit lookahead distance.
157 * @param params Movement parameters and constraints.
158 * @param headingMode Defines how the heading behaves while traversing the
159 * path.
160 * @param holdAngleDeg A specific angle to hold if `HeadingMode::HoldAngle` is
161 * selected.
162 * @param reversed If true, the robot traverses the path in reverse.
163 */
164 void followPath(const std::vector<PathPoint> &path, float lookahead_inches,
165 MoveParams params = defaultParams,
167 float holdAngleDeg = 0.0f, bool reversed = false);
168
169 /**
170 * @brief Autonomously turn the robot to face a specific heading.
171 *
172 * @param targetDeg The target heading in degrees.
173 * @param params Movement parameters.
174 */
175 void turnToHeading(float targetDeg, MoveParams params = defaultParams);
176
177 /**
178 * @brief Autonomously turn the robot to face a specific coordinate.
179 *
180 * @param tx Target X coordinate.
181 * @param ty Target Y coordinate.
182 * @param params Movement parameters.
183 */
184 void turnToPoint(float tx, float ty, MoveParams params = defaultParams);
185
186 /**
187 * @brief Autonomously drive directly to a coordinate on the field.
188 *
189 * @param tx Target X coordinate.
190 * @param ty Target Y coordinate.
191 * @param params Movement parameters.
192 * @param angleCorrection If true, actively adjusts heading to face the point
193 * while moving.
194 */
195 void moveToPoint(float tx, float ty, MoveParams params = defaultParams,
196 bool angleCorrection = true);
197
198 /**
199 * @brief Move a relative distance using X and Y offsets.
200 *
201 * @param forward Distance to move forward.
202 * @param sideways Distance to move sideways.
203 * @param params Movement parameters.
204 * @param holdHeading Actively maintain heading while translating.
205 */
206 void moveRelative(float forward, float sideways,
207 MoveParams params = defaultParams, bool holdHeading = true);
208
209 /**
210 * @brief Drive straight for a specified distance.
211 *
212 * @param distance Distance in inches.
213 * @param params Movement parameters.
214 * @param holdHeading Actively maintain heading while translating.
215 */
216 void moveDistance(float distance, MoveParams params = {},
217 bool holdHeading = true);
218
219 /**
220 * @brief Strafe for a specified distance.
221 *
222 * @param distance Distance in inches.
223 * @param params Movement parameters.
224 * @param holdHeading Actively maintain heading while translating.
225 */
226 void strafeDistance(float distance, MoveParams params = defaultParams,
227 bool holdHeading = true);
228
229 /**
230 * @brief Move the robot to an exact X, Y, and Theta simultaneously.
231 *
232 * @param tx Target X coordinate.
233 * @param ty Target Y coordinate.
234 * @param targetThetaDeg Target heading.
235 * @param params Movement parameters.
236 */
237 void moveToPose(float tx, float ty, float targetThetaDeg,
238 MoveParams params = defaultParams);
239
240 /**
241 * @brief Drive in a circular arc until reaching a specified heading.
242 *
243 * @param targetThetaDeg The final heading of the arc.
244 * @param radius The radius of the curved path.
245 * @param params Movement parameters.
246 * @param direction Whether to turn clockwise or counter-clockwise.
247 */
248 void curveCircle(float targetThetaDeg, float radius,
249 MoveParams params = defaultParams,
251
252 /**
253 * @brief Blocks the current thread until the current motion is finished.
254 */
256
257 /**
258 * @brief Halts all running background motions in the motion handler queue.
259 */
261
262 MotionHandler motion; /**< Background task handler instance */
263
264 /**
265 * @brief Infinite loop function typically passed to a background PROS task to
266 * update position continuously.
267 */
269
270 /**
271 * @brief Retrieves the total distance traveled during a motion segment.
272 *
273 * @param convertToMeters If true, returns value in meters rather than inches.
274 * @return float Distance traveled.
275 */
276 float getDistanceTraveled(bool convertToMeters = false);
277
278 /**
279 * @brief Cancels the currently executing autonomous motion.
280 */
282
283 /**
284 * @brief Wait until a certain linear distance has been covered during a
285 * motion command.
286 *
287 * Useful for triggering events mid-way through a path or `moveToPoint` call.
288 *
289 * @param distance The distance threshold.
290 */
291 void waitUntil(float distance);
292
293 /**
294 * @brief Set specific internal Extended Kalman Filter variables manually.
295 *
296 * @param xProcessNoise Noise in the X dimension.
297 * @param yProcessNoise Noise in the Y dimension.
298 * @param thetaProcessNoise Noise in heading dimension.
299 * @param measurementNoise IMU noise characteristic.
300 */
301 void setEKFGains(float xProcessNoise, float yProcessNoise,
302 float thetaProcessNoise, float measurementNoise);
303
304 /**
305 * @brief Toggles whether to calculate velocities via odometry
306 * (computationally heavier).
307 *
308 * @param state True to enable.
309 */
310 void setVelocityCalculations(bool state);
311
312 /**
313 * @brief Detect sudden impact indicating a potential collision using
314 * acceleration delta.
315 *
316 * @return true if collision detected.
317 */
319
320 /**
321 * @brief Apply direct open-loop power to the drivetrain without PID.
322 *
323 * @param forward Linear power.
324 * @param sideways Strafe power.
325 * @param rotation Rotational power.
326 */
327 void openLoop(float forward, float sideways, float rotation);
328
329 /**
330 * @brief Add an obstacle to the avoidance system.
331 *
332 * @param x X coordinate.
333 * @param y Y coordinate.
334 * @param radius Avoidance radius.
335 */
336 void addObstacle(float x, float y, float radius);
337
338 /**
339 * @brief Remove an obstacle by index.
340 *
341 * @param index The index.
342 */
343 void removeObstacle(size_t index);
344
345 /**
346 * @brief Clears all current obstacles from memory.
347 */
349
350 /**
351 * @brief Enables or disables the obstacle avoidance system globally.
352 *
353 * @param mode `AvoidanceMode::On` or `AvoidanceMode::Off`.
354 */
356
357 /**
358 * @brief Tunes the obstacle avoidance distance thresholds.
359 *
360 * @param safetyMargin Padding to treat the obstacle as larger than its
361 * radius.
362 * @param clearance Required distance from the padded radius.
363 */
364 void setAvoidanceParams(float safetyMargin, float clearance);
365
366 /**
367 * @brief Configures Artificial Potential Field parameters.
368 *
369 * @param ka Attraction to goal.
370 * @param kr Repulsion from obstacles.
371 * @param influenceRadius Distance at which an obstacle begins pushing the
372 * robot away.
373 */
374 void setPotentialFieldParams(float ka, float kr, float influenceRadius);
375
376 /**
377 * @brief Set robot dimensions used specifically for avoidance calculations.
378 *
379 * @param width Robot width.
380 * @param height Robot height.
381 */
382 void setRobotDimensionsAvoidance(float width, float height);
383
384 /**
385 * @brief Utility: Convert Radians to Degrees.
386 *
387 * @param rad Radians.
388 * @return float Degrees.
389 */
390 float radToDeg(float rad);
391
392 /**
393 * @brief Utility: Convert Degrees to Radians.
394 *
395 * @param deg Degrees.
396 * @return float Radians.
397 */
398 float degToRad(float deg);
399
400 /**
401 * @brief Toggle the internal EKF feature entirely.
402 *
403 * @param state True to run EKF, false for raw basic odometry.
404 */
405 void setEKFstate(bool state);
406
407 /**
408 * @brief Register a tracking wheel with the odometry module.
409 *
410 * @param config The hardware configuration for the tracking wheel.
411 */
413
414 /**
415 * @brief Unregisters all external tracking wheels.
416 */
418
419 /**
420 * @brief Generic templated loop to accept external calculation functions.
421 *
422 * @tparam F Lambda type.
423 * @param updateFunction The function doing calculations and returning motor
424 * voltages.
425 * @param params Movement boundaries.
426 * @param fieldCentric Treat update inputs as field centric.
427 * @param headingOffset Global heading offset.
428 * @param correction Correction params.
429 */
430 template <typename F>
431 void move(F updateFunction, MoveParams params = defaultParams,
432 bool fieldCentric = true, float headingOffset = 0.0f,
433 DriveCorrection correction = {}) {}
434
435 /**
436 * @brief Sets global default move parameters.
437 *
438 * @param params Parameters to use as default.
439 */
441
442 /**
443 * @brief Determines which side to lock during a swing turn.
444 */
445 enum class SwingSide { Right, Left };
446
447 /**
448 * @brief Execute a swing turn where one side of the robot is held stationary.
449 *
450 * @param targetThetaDeg The target heading.
451 * @param lockedSide Which side of the drive train to hold zero power to.
452 * @param params Movement parameters.
453 */
454 void swingTurn(float targetThetaDeg, SwingSide lockedSide,
455 MoveParams params = defaultParams);
456
457 /**
458 * @brief Reads inputs from the standard PROS controller into the drive
459 * control method.
460 *
461 * @param master The PROS Controller object.
462 */
463 void getControllerInput(pros::Controller master);
464
465 /**
466 * @brief Logs the driver's movements in real time to enable playback
467 * features.
468 *
469 * @param master The controller to read from.
470 * @param timeout_ms Interval to poll and log.
471 */
472 void logReplayData(pros::Controller master, int timeout_ms = 50);
473
474 /**
475 * @brief Stops driver motion logging.
476 */
478
479 /**
480 * @brief Playback previously recorded driver inputs autonomously.
481 *
482 * @param data Recorded sequence of PathPoints or equivalent macro.
483 * @param lookahead Follow lookahead parameter for smoothing playback
484 * tracking.
485 */
486 void runDriverReplay(std::vector<PathPoint> data, float lookahead);
487
488private:
489 pros::Motor frontLeft, frontRight, backLeft, backRight;
490 std::vector<pros::Motor> motors{frontLeft, frontRight, backLeft, backRight};
491 pros::Imu imu;
492 ChassisConfig config;
493 static MoveParams defaultParams;
494 GainScheduler xSched, ySched, thetaSched;
495
496 Pose currentPose{0, 0, 0};
497 pros::Mutex poseMutex;
498 PoseEKF ekf{0, 0, 0};
499 EncoderKalmanFilter kf_fl, kf_fr, kf_bl, kf_br;
500 float prev_fl = 0, prev_fr = 0, prev_bl = 0, prev_br = 0;
501 float prev_heading = 0;
502 float targetHeadingDriveControl = 0;
503 friend void odomTaskTrampoline(void *);
504 float motionDistTraveled = 0.0f;
505 float xProcessNoise = 0.001f, yProcessNoise = 0.001f,
506 thetaProcessNoise = 0.003f, measurementNoise = 0.0001f;
507 bool velocityCalculationsOn = false;
508
509 ObstacleManager obstacles;
510 AvoidanceMode avoidanceMode = AvoidanceMode::Off;
511 float avoidanceSafetyMargin = 4.0f;
512 float avoidanceClearance = 8.0f;
513 float pf_ka = 5.0f;
514 float pf_kr = 50.0f;
515 float pf_influence_radius = 15.0f;
516
517 GainScheduler savedXSched, savedYSched, savedThetaSched;
518
519 uint32_t last_collision_check_time = 0;
520 uint32_t stall_accumulator_ms = 0;
521
522 std::vector<TrackingWheelConfig> trackingWheelConfigs;
523 std::vector<pros::Rotation> trackingWheelSensors;
524 std::vector<float> prevTrackingPositions;
525 bool useTrackingWheels = false;
526 float trackingWheelMeasNoise = 0.0005f;
527};
The main Chassis controller class.
Definition chassis.h:33
void logReplayData(pros::Controller master, int timeout_ms=50)
Logs the driver's movements in real time to enable playback features.
Pose getPose(bool radians=false)
Get the current odometry pose of the robot.
friend void odomTaskTrampoline(void *)
float degToRad(float deg)
Utility: Convert Degrees to Radians.
void openLoop(float forward, float sideways, float rotation)
Apply direct open-loop power to the drivetrain without PID.
void addTrackingWheel(TrackingWheelConfig config)
Register a tracking wheel with the odometry module.
void waitUntil(float distance)
Wait until a certain linear distance has been covered during a motion command.
void odometryTask()
Infinite loop function typically passed to a background PROS task to update position continuously.
void setYGains(std::vector< ScheduledGain > steps)
Provide scheduled gains for the Y-axis translation controller.
void setVelocityCalculations(bool state)
Toggles whether to calculate velocities via odometry (computationally heavier).
void getControllerInput(pros::Controller master)
Reads inputs from the standard PROS controller into the drive control method.
void disableReplayDataLogging()
Stops driver motion logging.
void setRobotDimensionsAvoidance(float width, float height)
Set robot dimensions used specifically for avoidance calculations.
void curveCircle(float targetThetaDeg, float radius, MoveParams params=defaultParams, CurveDirection direction=CurveDirection::Auto)
Drive in a circular arc until reaching a specified heading.
void moveRelative(float forward, float sideways, MoveParams params=defaultParams, bool holdHeading=true)
Move a relative distance using X and Y offsets.
XDriveVoltages calculateHolonomic(float vx, float vy, float vt)
Calculate the individual motor voltages for a holonomic movement command.
MotionHandler motion
Background task handler instance.
Definition chassis.h:262
void removeObstacle(size_t index)
Remove an obstacle by index.
void calibrate()
Calibrates sensors (e.g.
void brake()
Instructs all motors to brake using their configured brake mode.
void swingTurn(float targetThetaDeg, SwingSide lockedSide, MoveParams params=defaultParams)
Execute a swing turn where one side of the robot is held stationary.
void setXGains(std::vector< ScheduledGain > steps)
Provide scheduled gains for the X-axis translation controller.
void runDriverReplay(std::vector< PathPoint > data, float lookahead)
Playback previously recorded driver inputs autonomously.
void addObstacle(float x, float y, float radius)
Add an obstacle to the avoidance system.
float radToDeg(float rad)
Utility: Convert Radians to Degrees.
void setEKFGains(float xProcessNoise, float yProcessNoise, float thetaProcessNoise, float measurementNoise)
Set specific internal Extended Kalman Filter variables manually.
void setAvoidanceParams(float safetyMargin, float clearance)
Tunes the obstacle avoidance distance thresholds.
void clearTrackingWheels()
Unregisters all external tracking wheels.
Chassis(pros::Motor fl, pros::Motor fr, pros::Motor bl, pros::Motor br, pros::Imu imu_sensor, ChassisConfig config)
Construct a new Chassis object.
void moveDistance(float distance, MoveParams params={}, bool holdHeading=true)
Drive straight for a specified distance.
void setMotorVoltages(XDriveVoltages v)
Command the base motors with a set of voltages.
void cancelAllMotions()
Halts all running background motions in the motion handler queue.
void strafeDistance(float distance, MoveParams params=defaultParams, bool holdHeading=true)
Strafe for a specified distance.
void turnToPoint(float tx, float ty, MoveParams params=defaultParams)
Autonomously turn the robot to face a specific coordinate.
void cancelMotion()
Cancels the currently executing autonomous motion.
void setPose(Pose pose)
Reset the robot's odometry position to a Pose object.
void setPose(float x, float y, float theta=0.0f)
Manually reset the robot's odometry position.
void waitUntilDone()
Blocks the current thread until the current motion is finished.
SwingSide
Determines which side to lock during a swing turn.
Definition chassis.h:445
void setEKFstate(bool state)
Toggle the internal EKF feature entirely.
void followPath(const std::vector< PathPoint > &path, float lookahead_inches, MoveParams params=defaultParams, HeadingMode headingMode=HeadingMode::FollowPath, float holdAngleDeg=0.0f, bool reversed=false)
Autonomously follow a path defined by points.
void driveControl(float forward, float sideways, float rotation, DriveCurves drivecurves, bool fieldCentric, float headingOffset=0.0f, DriveCorrection correction={})
Main driver control mapping logic.
void setMoveParams(MoveParams params)
Sets global default move parameters.
void setPotentialFieldParams(float ka, float kr, float influenceRadius)
Configures Artificial Potential Field parameters.
void clearObstacles()
Clears all current obstacles from memory.
void turnToHeading(float targetDeg, MoveParams params=defaultParams)
Autonomously turn the robot to face a specific heading.
AvoidanceMode
Status of the Obstacle Avoidance subsystem.
Definition chassis.h:150
float getDistanceTraveled(bool convertToMeters=false)
Retrieves the total distance traveled during a motion segment.
void moveToPoint(float tx, float ty, MoveParams params=defaultParams, bool angleCorrection=true)
Autonomously drive directly to a coordinate on the field.
void move(F updateFunction, MoveParams params=defaultParams, bool fieldCentric=true, float headingOffset=0.0f, DriveCorrection correction={})
Generic templated loop to accept external calculation functions.
Definition chassis.h:431
void setThetaGains(std::vector< ScheduledGain > steps)
Provide scheduled gains for the rotational (Theta) controller.
CurveDirection
Automatic, clockwise, or counter-clockwise rotation preference.
Definition chassis.h:145
bool detectCollision()
Detect sudden impact indicating a potential collision using acceleration delta.
void setAvoidanceMode(AvoidanceMode mode)
Enables or disables the obstacle avoidance system globally.
void moveToPose(float tx, float ty, float targetThetaDeg, MoveParams params=defaultParams)
Move the robot to an exact X, Y, and Theta simultaneously.
Standard 1D Kalman filter for smoothing raw motor encoder values.
A scheduler that interpolates and selects PID gains based on the current error.
Manages the execution of motion commands asynchronously.
Manages a collection of obstacles and provides avoidance computations.
Definition obstacle.h:22
Extended Kalman Filter implementation for maintaining the robot's pose.
Definition pose_ekf.h:16
HeadingMode
Specifies the heading behavior during path following.
Definition path.h:18
Core constants to configure the chassis dimensions and hardware.
Definition config.h:8
Configuration for active heading correction during driver control.
Definition config.h:39
Holds the drive curves for movement and rotation inputs.
Definition config.h:31
Parameters defining bounds and conditions for autonomous movements.
Definition config.h:50
Contains global coordinates and velocity.
Definition pose.h:15
Configuration parameters for a tracking wheel.
Holonomic target voltages for a 4-motor X-drive or mecanum base.
Definition pose.h:25