7#include <sys/_intsup.h>
9#include "pros/abstract_motor.hpp"
10#include "pros/motors.h"
11#include "pros/rtos.hpp"
15Chassis::Chassis(lemlib::Drivetrain drivetrain,
16 lemlib::ControllerSettings lateralSettings,
17 lemlib::ControllerSettings angularSettings,
18 lemlib::OdomSensors sensors,
19 lemlib::DriveCurve* throttleCurve,
20 lemlib::DriveCurve* steerCurve)
21 : lemlib::Chassis(drivetrain, lateralSettings, angularSettings, sensors, throttleCurve, steerCurve),
22 drivetrain(drivetrain) {}
24Chassis::WheelPowers Chassis::desaturate(
float lateral,
float angular,
float maxSpeed) {
25 float left = lateral + angular;
26 float right = lateral - angular;
27 float maxMag = std::max(std::abs(left), std::abs(right));
28 if (maxMag > maxSpeed) {
29 left = (left / maxMag) * maxSpeed;
30 right = (right / maxMag) * maxSpeed;
35void Chassis::moveToPointRamsete(
float target_x,
float target_y,
int timeout_msec,
const VelocityControllerConfig &
config, MoveToPointParams params,
bool async) {
37 this->requestMotionStart();
38 this->distTraveled = 0;
40 auto movement_logic = [=,
this]()
mutable {
52 lemlib::PID angularPID(11, 0.001, 0);
53 lemlib::PID lateralPID(5, 0, 0);
54 lemlib::ExitCondition lateral(0.08, 100);
55 lemlib::ExitCondition longitudinal(0.08, 100);
57 float lateralGain = 0;
59 auto sign = [](
float x) {
return (x > 0) ? 1.0f : ((x < 0) ? -1.0f : 0.0f); };
60 auto sinc = [](
float x) {
return (std::abs(x) < 1e-5) ? 1.0f : std::sin(x) / x; };
63 bool is_settling =
false;
65 lemlib::Pose lastPose = this->getPose(
true,
true);
66 uint32_t startTime = pros::millis();
67 while ((pros::millis() - startTime <
static_cast<uint32_t
>(timeout_msec)) && (!lateral.getExit() || !longitudinal.getExit())) {
69 if (this->motionQueued) {
73 lemlib::Pose currentPoseRaw = this->getPose(
true,
true);
74 this->distTraveled += lastPose.distance(currentPoseRaw);
75 lastPose = currentPoseRaw;
77 lemlib::Pose currentPose = currentPoseRaw;
81 float d = std::hypot(target_x - currentPose.x, target_y - currentPose.y);
82 float dx = target_x - currentPose.x;
83 float dy = target_y - currentPose.y;
85 if (!params.forwards) {
90 float theta = currentPose.theta;
91 float localErrorX = std::cos(theta) * dx + std::sin(theta) * dy;
92 float localErrorY = -std::sin(theta) * dx + std::cos(theta) * dy;
94 float angularError = std::atan2(localErrorY, localErrorX);
95 float cosineScaling = std::cos(angularError);
104 cosineScaling = 1.0f;
105 driveError = std::cos(theta) * dx + std::sin(theta) * dy;
107 driveError = d * sign(cosineScaling);
110 if (params.minSpeed > 0 && (d < earlyExit_m || driveError < 0)) {
114 lateral.update(localErrorY);
115 longitudinal.update(localErrorX);
117 float angularOutput = angularPID.update(angularError);
118 float driveOutput = lateralPID.update(driveError);
120 driveOutput = std::clamp(driveOutput, -params.maxSpeed, params.maxSpeed);
121 driveOutput = driveOutput * std::abs(cosineScaling);
126 angularOutput += driveOutput * lateralGain * localErrorY * sinc(angularError);
129 if (!is_settling && params.minSpeed > 0 && std::abs(driveOutput) < params.minSpeed) {
130 driveOutput = params.minSpeed * sign(driveOutput);
131 if (driveOutput == 0) driveOutput = params.minSpeed;
134 angularOutput = std::clamp(angularOutput, -params.maxTurnSpeed, params.maxTurnSpeed);
136 if (!params.forwards) {
137 driveOutput = -driveOutput;
140 float leftVel = drivetrain.leftMotors->get_actual_velocity() *
rpm_to_mps_factor;
141 float rightVel = drivetrain.rightMotors->get_actual_velocity() *
rpm_to_mps_factor;
143 DrivetrainVoltages outputVoltages =
controller.update(driveOutput, angularOutput, leftVel, rightVel);
145 drivetrain.leftMotors->move_voltage(outputVoltages.leftVoltage * 1000);
146 drivetrain.rightMotors->move_voltage(outputVoltages.rightVoltage * 1000);
151 if (params.minSpeed == 0) {
152 drivetrain.leftMotors->move_voltage(0);
153 drivetrain.rightMotors->move_voltage(0);
156 this->motionRunning =
false;
160 pros::Task task(movement_logic);
166void Chassis::moveToPoseRamsete(
float targetX,
float targetY,
float targetTheta,
int timeout_msec,
const VelocityControllerConfig &
config, MoveToPoseParams params,
bool async) {
170 pros::Task task([=,
this]() {
172 moveToPoseRamsete(targetX, targetY, targetTheta, timeout_msec,
config, params,
false);
179 this->requestMotionStart();
180 this->distTraveled = 0;
193 lemlib::PID angularPID(7.5, 0.001, 26.5);
194 lemlib::PID lateralPID(5.5 , 0.001 , 27);
196 lemlib::ExitCondition lateralExit(0.08, 100);
197 lemlib::ExitCondition longitudinalExit(0.08, 100);
199 auto sign_func = [](
float x) {
return (x > 0) ? 1.0f : ((x < 0) ? -1.0f : 0.0f); };
200 auto sinc = [](
float x) {
return (std::abs(x) < 1e-5) ? 1.0f : std::sin(x) / x; };
204 float targetThetaRad = targetTheta * (M_PI / 180.0f);
205 float end_unit_x = std::sin(targetThetaRad);
206 float end_unit_y = std::cos(targetThetaRad);
207 float dir_sign = params.forwards ? 1.0f : -1.0f;
209 bool is_settling =
false;
211 lemlib::Pose lastPose = this->getPose(
true,
true);
212 uint32_t startTime = pros::millis();
214 while ((pros::millis() - startTime <
static_cast<uint32_t
>(timeout_msec)) && (!lateralExit.getExit() || !longitudinalExit.getExit())) {
217 if (this->motionQueued) {
221 lemlib::Pose currentPoseRaw = this->getPose(
true,
true);
222 this->distTraveled += lastPose.distance(currentPoseRaw);
223 lastPose = currentPoseRaw;
225 lemlib::Pose currentPose = currentPoseRaw;
228 float theta = currentPose.theta;
230 float d = std::hypot(targetX - currentPose.x, targetY - currentPose.y);
232 float true_dx = targetX - currentPose.x;
233 float true_dy = targetY - currentPose.y;
234 if (!params.forwards) {
238 float true_localErrorX = std::cos(theta) * true_dx + std::sin(theta) * true_dy;
239 float true_localErrorY = -std::sin(theta) * true_dx + std::cos(theta) * true_dy;
241 float rx = currentPose.x - targetX;
242 float ry = currentPose.y - targetY;
243 float along_track = rx * end_unit_x + ry * end_unit_y;
244 float dynamic_lookahead = d * params.lead;
245 float lookahead_m = std::max(dynamic_lookahead, 0.35f);
246 float ghost_along_track = along_track + (lookahead_m * dir_sign);
248 float carrot_x = targetX + ghost_along_track * end_unit_x;
249 float carrot_y = targetY + ghost_along_track * end_unit_y;
251 float dx = carrot_x - currentPose.x;
252 float dy = carrot_y - currentPose.y;
253 if (!params.forwards) {
258 float localErrorX = std::cos(theta) * dx + std::sin(theta) * dy;
259 float localErrorY = -std::sin(theta) * dx + std::cos(theta) * dy;
261 float heading_error_rad = std::atan2(localErrorY, localErrorX);
262 float cosine_scale = std::cos(heading_error_rad);
264 float error_norm_sq = localErrorX * localErrorX + localErrorY * localErrorY;
265 float driveError = std::sqrt((error_norm_sq + 2.0f * d * d) / 3.0f) * sign_func(cosine_scale);
266 float turnError = heading_error_rad;
268 if (d < std::max(settleRadius_m, 0.05f)) {
273 float targetThetaMath = M_PI_2 - targetThetaRad;
274 float final_error = targetThetaMath - theta;
275 final_error = std::remainder(final_error, 2.0 * M_PI);
277 turnError = final_error;
278 driveError = true_localErrorX;
282 if (params.earlyExitRange > 0 && (d < earlyExit_m || driveError < 0)) {
286 lateralExit.update(true_localErrorY);
287 longitudinalExit.update(true_localErrorX);
289 float driveOutput = lateralPID.update(driveError);
290 float turnOutput = angularPID.update(turnError);
292 driveOutput = std::clamp(driveOutput, -params.maxSpeed, params.maxSpeed);
295 float steeringVelocity = std::max(std::abs(driveOutput), 0.2f);
296 turnOutput += steeringVelocity * params.k_lat * localErrorY * sinc(heading_error_rad);
299 driveOutput = std::abs(cosine_scale) * driveOutput;
301 if (!is_settling && params.minSpeed > 0 && std::abs(driveOutput) < params.minSpeed) {
302 driveOutput = params.minSpeed * sign_func(driveOutput);
303 if (driveOutput == 0) driveOutput = params.minSpeed;
306 if (!params.forwards) {
307 driveOutput = -driveOutput;
310 turnOutput = std::clamp(turnOutput, -params.maxTurnSpeed, params.maxTurnSpeed);
312 float leftVel = drivetrain.leftMotors->get_actual_velocity() *
rpm_to_mps_factor;
313 float rightVel = drivetrain.rightMotors->get_actual_velocity() *
rpm_to_mps_factor;
315 DrivetrainVoltages outputVoltages =
controller.update(driveOutput, turnOutput, leftVel, rightVel);
317 drivetrain.leftMotors->move_voltage(outputVoltages.leftVoltage * 1000);
318 drivetrain.rightMotors->move_voltage(outputVoltages.rightVoltage * 1000);
324 if (params.minSpeed == 0) {
325 drivetrain.leftMotors->move_voltage(0);
326 drivetrain.rightMotors->move_voltage(0);
330 this->motionRunning =
false;
333void Chassis::tank(
float lin_vel,
float ang_vel,
const VelocityControllerConfig &
config,
unsigned int time)
342 u_int32_t starting_time = pros::millis();
344 while(pros::millis() - starting_time < time)
346 float leftVel = drivetrain.leftMotors->get_actual_velocity() * 0.00324173f;
347 float rightVel = drivetrain.rightMotors->get_actual_velocity() * 0.00324173f;
349 DrivetrainVoltages outputVoltages =
controller.update(lin_vel, ang_vel, leftVel, rightVel);
351 drivetrain.leftMotors->move_voltage(outputVoltages.leftVoltage * 1000);
352 drivetrain.rightMotors->move_voltage(outputVoltages.rightVoltage * 1000);
357 drivetrain.leftMotors->brake();
358 drivetrain.rightMotors->brake();
361void Chassis::brake(pros::MotorBrake brake_mode)
363 drivetrain.rightMotors->set_brake_mode(brake_mode);
364 drivetrain.leftMotors->set_brake_mode(brake_mode);
365 drivetrain.rightMotors->brake();
366 drivetrain.leftMotors->brake();
369void Chassis::tank(
int left,
int right)
371 drivetrain.rightMotors->move(right);
372 drivetrain.leftMotors->move(left);
375bool Chassis::collision_montitoring(
unsigned int time)
377 u_int32_t starting_time = pros::millis();
378 pros::Task collision_task([
this, time, starting_time]() {
380 while(pros::millis() - starting_time < time)
382 if(this->detect_collision())
385 if(stall_time >= 250)
401bool Chassis::detect_collision()
403 double right_target = std::abs(drivetrain.rightMotors->get_target_velocity());
404 double left_target = std::abs(drivetrain.leftMotors->get_target_velocity());
405 double right_actual = std::abs(drivetrain.rightMotors->get_actual_velocity());
406 double left_actual = std::abs(drivetrain.leftMotors->get_actual_velocity());
407 double right_eff = drivetrain.rightMotors->get_efficiency();
408 double left_eff = drivetrain.leftMotors->get_efficiency();
410 const double TARGET_THRESHOLD = 50.0;
411 const double VELOCITY_THRESHOLD = 5.0;
412 const double EFFICIENCY_THRESHOLD = 20.0;
413 bool right_commanded = right_target > TARGET_THRESHOLD;
414 bool left_commanded = left_target > TARGET_THRESHOLD;
415 bool right_struggling = (right_actual < VELOCITY_THRESHOLD) || (right_eff < EFFICIENCY_THRESHOLD);
416 bool left_struggling = (left_actual < VELOCITY_THRESHOLD) || (left_eff < EFFICIENCY_THRESHOLD);
418 bool right_colliding = right_commanded && right_struggling;
419 bool left_colliding = left_commanded && left_struggling;
421 if (right_colliding || left_colliding)
const VelocityControllerConfig config
pros::Controller controller(pros::E_CONTROLLER_MASTER)
static constexpr float INCH_TO_METER
static constexpr float rpm_to_mps_factor