Autonomy Software C++ 24.5.1
Welcome to the Autonomy Software repository of the Mars Rover Design Team (MRDT) at Missouri University of Science and Technology (Missouri S&T)! API reference contains the source code and other resources for the development of the autonomy software for our Mars rover. The Autonomy Software project aims to compete in the University Rover Challenge (URC) by demonstrating advanced autonomous capabilities and robust navigation algorithms.
Loading...
Searching...
No Matches
DriveBoard Class Reference

This class handles communication with the drive board on the rover by sending RoveComm packets over the network. More...

#include <DriveBoard.h>

Collaboration diagram for DriveBoard:

Public Member Functions

 DriveBoard ()
 Construct a new Drive Board::DriveBoard object.
 
 ~DriveBoard ()
 Destroy the Drive Board::DriveBoard object.
 
diffdrive::DrivePowers CalculateMove (const double dGoalSpeed, const double dGoalHeading, const double dActualHeading, const diffdrive::DifferentialControlMethod eKinematicsMethod=diffdrive::DifferentialControlMethod::eArcadeDrive, const bool bDriveBackwards=false, const bool bAlwaysProgressForward=false, const bool bSquareControlInput=false, const bool bCurvatureDriveAllowTurningWhileStopped=true)
 This method determines drive powers to make the Rover drive towards a given heading at a given speed.
 
void SendDrive (const diffdrive::DrivePowers &stDrivePowers, const bool bEnableVariableDriveEffort=true)
 Sets the left and right drive powers of the drive board.
 
void SendStop ()
 Stop the drivetrain of the Rover.
 
float VariableDriveEffort ()
 This method calculates a multiplier that is applied to SetMaxDriveEffort() to adjust the speed of the rover in relation to the risk of the terrain.
 
void SetMaxDriveEffort (const float fMaxDriveEffortMultiplier)
 Set the max power limits of the drive.
 
diffdrive::DrivePowers GetDrivePowers () const
 Accessor for the current drive powers of the robot.
 
float GetMaxDriveEffort () const
 Accessor for the current max drive effort multiplier.
 

Private Attributes

diffdrive::DrivePowers m_stDrivePowers
 
std::unique_ptr< controllers::PIDControllerm_pPID
 
float m_fDriveEffortMultiplier
 
std::shared_mutex m_muDriveEffortMutex
 
const float m_fMinSlope = constants::DRIVE_BOARD_MIN_SLOPE
 
const float m_fMaxSlope = constants::DRIVE_BOARD_MAX_SLOPE
 
const float m_fMinDamp = constants::DRIVE_BOARD_MIN_DAMP
 
const float m_fMaxDamp = constants::DRIVE_BOARD_MAX_DAMP
 
const float m_fRoll_w = constants::DRIVE_BOARD_ROLL_WEIGHT
 
const float m_fPitch_w = constants::DRIVE_BOARD_PITCH_WEIGHT
 
const float m_fYaw_w = constants::DRIVE_BOARD_YAW_WEIGHT
 
const std::function< void(const rovecomm::RoveCommPacket< float > &, const sockaddr_in &)> SetMaxSpeedCallback
 Callback function that is called whenever RoveComm receives a new SETMAXSPEED packet.
 

Detailed Description

This class handles communication with the drive board on the rover by sending RoveComm packets over the network.

Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2023-09-21

Constructor & Destructor Documentation

◆ DriveBoard()

DriveBoard::DriveBoard ( )

Construct a new Drive Board::DriveBoard object.

Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2023-09-21
32{
33 // Initialize member variables.
34 m_stDrivePowers.dLeftDrivePower = 0.0;
35 m_stDrivePowers.dRightDrivePower = 0.0;
36 m_fDriveEffortMultiplier = 1.0f;
37
38 // Configure PID controller for heading hold function.
39 m_pPID = std::make_unique<controllers::PIDController>(constants::DRIVE_PID_PROPORTIONAL,
40 constants::DRIVE_PID_INTEGRAL,
41 constants::DRIVE_PID_DERIVATIVE,
42 constants::DRIVE_PID_FEEDFORWARD);
43 m_pPID->SetMaxSetpointDifference(constants::DRIVE_PID_MAX_ERROR);
44 m_pPID->SetMaxIntegralEffort(constants::DRIVE_PID_MAX_INTEGRAL_TERM);
45 m_pPID->SetOutputLimits(1.0); // Autonomy internally always uses -1.0, 1.0 for turning and drive powers.
46 m_pPID->SetOutputRampRate(constants::DRIVE_PID_MAX_RAMP_RATE);
47 m_pPID->SetOutputFilter(constants::DRIVE_PID_OUTPUT_FILTER);
48 m_pPID->SetTolerance(constants::DRIVE_PID_TOLERANCE);
49 m_pPID->SetDirection(constants::DRIVE_PID_OUTPUT_REVERSED);
50 m_pPID->EnableContinuousInput(0, 360);
51
52 // Set RoveComm callbacks.
53 if (network::g_pRoveCommUDPNode)
54 {
55 network::g_pRoveCommUDPNode->AddUDPCallback<float>(SetMaxSpeedCallback, manifest::Autonomy::COMMANDS.find("SETMAXSPEED")->second.DATA_ID);
56 }
57}
const std::function< void(const rovecomm::RoveCommPacket< float > &, const sockaddr_in &)> SetMaxSpeedCallback
Callback function that is called whenever RoveComm receives a new SETMAXSPEED packet.
Definition DriveBoard.h:100

◆ ~DriveBoard()

DriveBoard::~DriveBoard ( )

Destroy the Drive Board::DriveBoard object.

Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2023-09-21
67{
68 // Stop drivetrain.
69 this->SendStop();
70}
void SendStop()
Stop the drivetrain of the Rover.
Definition DriveBoard.cpp:246
Here is the call graph for this function:

Member Function Documentation

◆ CalculateMove()

diffdrive::DrivePowers DriveBoard::CalculateMove ( const double  dGoalSpeed,
const double  dGoalHeading,
const double  dActualHeading,
const diffdrive::DifferentialControlMethod  eKinematicsMethod = diffdrive::DifferentialControlMethod::eArcadeDrive,
const bool  bDriveBackwards = false,
const bool  bPreventPointTurns = false,
const bool  bSquareControlInput = false,
const bool  bCurvatureDriveAllowTurningWhileStopped = true 
)

This method determines drive powers to make the Rover drive towards a given heading at a given speed.

Parameters
dGoalSpeed- The speed to drive at (-1 to 1)
dGoalHeading- The angle to drive towards. (0 - 360) 0 is North.
dActualHeading- The real angle that the Rover is current facing.
eKinematicsMethod- The kinematics model to use for differential drive control. Enum within DifferentialDrive.hpp
bDriveBackwards- If true, the rover will drive backwards while trying to hit the heading. This is used for the "backwards" mode of the drive control.
bPreventPointTurns- If true, the rover will always maintain linear movement (forward or backward). Point turns will not be allowed.
bSquareControlInput- If true, the control input will be squared before being applied.
bCurvatureDriveAllowTurningWhileStopped- If true, the curvature drive method will allow turning while the rover is stopped.
Returns
diffdrive::DrivePowers - A struct containing two values. (left power, right power)
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2026-04-24
97{
98 // Create instance variables.
99 diffdrive::DrivePowers stOutputPowers;
100
101 // Invert the speed if we are driving backwards
102 double dSpeed = bDriveBackwards ? -dGoalSpeed : dGoalSpeed;
103 double dTargetHeading = dGoalHeading;
104
105 // If driving backwards, we must point the rear of the rover towards the goal.
106 if (bDriveBackwards)
107 {
108 // Offset the goal heading by 180 degrees and wrap around 360 to stay in bounds.
109 dTargetHeading = std::fmod(dTargetHeading + 180.0, 360.0);
110 }
111
112 // Get control output from PID controller using our target heading.
113 double dTurnOutput = m_pPID->Calculate(dActualHeading, dTargetHeading);
114
115 // Calculate drive powers from inverse kinematics of goal speed and turning adjustment.
116 switch (eKinematicsMethod)
117 {
118 case diffdrive::DifferentialControlMethod::eArcadeDrive:
119 {
120 // Check if the rover is allowed to pivot in place.
121 if (!bPreventPointTurns)
122 {
123 // Based on our turn output, inverse-proportionally scale down our goal speed along a squared curve profile.
124 // Because we square dTurnOutput, this correctly scales down negative speeds when driving backwards as well.
125 dSpeed *= 1.0 - std::pow(dTurnOutput, 2);
126 }
127 // Calculate drive power with inverse kinematics.
128 stOutputPowers = diffdrive::CalculateArcadeDrive(dSpeed, dTurnOutput, bSquareControlInput);
129 break;
130 }
131 case diffdrive::DifferentialControlMethod::eCurvatureDrive:
132 {
133 // Check if the rover is allowed to pivot in place.
134 if (!bPreventPointTurns)
135 {
136 // Based on our turn output, inverse-proportionally scale down our goal speed along a squared curve profile.
137 dSpeed *= 1.0 - std::pow(dTurnOutput, 2);
138 }
139 // Calculate drive power with inverse kinematics.
140 stOutputPowers = diffdrive::CalculateCurvatureDrive(dSpeed, dTurnOutput, bCurvatureDriveAllowTurningWhileStopped, bSquareControlInput);
141 break;
142 }
143 default:
144 {
145 // Submit logger message.
146 LOG_ERROR(logging::g_qSharedLogger, "eTankDrive is not supported for the CalculateMotorPowerFromHeading() method!");
147 break;
148 }
149 }
150
151 // Return result powers.
152 return stOutputPowers;
153}
DrivePowers CalculateArcadeDrive(double dSpeed, double dRotation, const bool bSquareInputs=false)
Arcade drive inverse kinematics for differential drive robots.
Definition DifferentialDrive.hpp:120
DrivePowers CalculateCurvatureDrive(double dSpeed, double dRotation, const bool bAllowTurnInPlace, const bool bSquareInputs=false)
Curvature drive inverse kinematics for differential drive robots. The rotation parameter controls the...
Definition DifferentialDrive.hpp:170
This struct is used to store the left and right drive powers for the robot. Storing these values in a...
Definition DifferentialDrive.hpp:73
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SendDrive()

void DriveBoard::SendDrive ( const diffdrive::DrivePowers stDrivePowers,
const bool  bEnableVariableDriveEffort = true 
)

Sets the left and right drive powers of the drive board.

Parameters
stDrivePowers- A struct containing info about the desired drive powers. Drive powers are always in between -1.0 and 1.0 no matter what constants or RoveComm say. the -1.0 to 1.0 range is automatically mapped to the correct DriveBoard range in this method.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2023-09-21
167{
168 // Limit input values (-1.0 to 1.0).
169 double dLeftInput = std::clamp(stDrivePowers.dLeftDrivePower, -1.0, 1.0);
170 double dRightInput = std::clamp(stDrivePowers.dRightDrivePower, -1.0, 1.0);
171
172 // -------------------------------------------------------------------------
173 // Decouple Linear and Angular components to fix low-speed turning.
174 // -------------------------------------------------------------------------
175 // Separate Linear (Forward/Back) and Angular (Turn) power.
176 double dLinearPower = (dLeftInput + dRightInput) / 2.0;
177 double dAngularPower = (dLeftInput - dRightInput) / 2.0;
178
179 // Fetch the base operator-set speed multiplier safely.
180 float fCombinedMultiplier = 1.0f;
181 {
182 std::shared_lock<std::shared_mutex> lkDriveEffortLock(m_muDriveEffortMutex);
183 fCombinedMultiplier = m_fDriveEffortMultiplier;
184 }
185
186 // If variable drive effort is enabled, scale the base RoveComm multiplier further based on terrain.
187 if (bEnableVariableDriveEffort)
188 {
189 float fTerrainDampening = VariableDriveEffort();
190 fCombinedMultiplier *= fTerrainDampening;
191 }
192
193 // Apply the Combined Speed Multiplier ONLY to the Linear component.
194 // This slows down the travel speed based on operator limits AND terrain safety,
195 // but keeps full turning torque available.
196 dLinearPower *= fCombinedMultiplier;
197
198 // Reconstruct Left and Right powers.
199 double dLeftSpeed = dLinearPower + dAngularPower;
200 double dRightSpeed = dLinearPower - dAngularPower;
201
202 // Desaturate the output to preserve the turning ratio if it exceeds the max.
203 // If we commanded (1.0, 0.5) and scaled linear by 0.1, we might get (0.1, 0.05).
204 // But if turning adds significant power, we might exceed 1.0.
205 double dMaxMagnitude = std::max(std::abs(dLeftSpeed), std::abs(dRightSpeed));
206 if (dMaxMagnitude > 1.0)
207 {
208 dLeftSpeed /= dMaxMagnitude;
209 dRightSpeed /= dMaxMagnitude;
210 }
211
212 // -------------------------------------------------------------------------
213 // If the min and max drive effort have been set to 0, then just send zero powers.
214 // Limit the power to max and min effort defined in constants (Slope Safety).
215 m_stDrivePowers.dLeftDrivePower = std::clamp(float(dLeftSpeed), constants::DRIVE_MIN_POWER, constants::DRIVE_MAX_POWER);
216 m_stDrivePowers.dRightDrivePower = std::clamp(float(dRightSpeed), constants::DRIVE_MIN_POWER, constants::DRIVE_MAX_POWER);
217
218 // Construct a RoveComm packet with the drive data.
219 rovecomm::RoveCommPacket<float> stPacket;
220 stPacket.unDataId = manifest::Core::COMMANDS.find("DRIVELEFTRIGHT")->second.DATA_ID;
221 stPacket.unDataCount = manifest::Core::COMMANDS.find("DRIVELEFTRIGHT")->second.DATA_COUNT;
222 stPacket.eDataType = manifest::Core::COMMANDS.find("DRIVELEFTRIGHT")->second.DATA_TYPE;
223 stPacket.vData.emplace_back(m_stDrivePowers.dLeftDrivePower);
224 stPacket.vData.emplace_back(m_stDrivePowers.dRightDrivePower);
225
226 // Send drive command over RoveComm to drive board.
227 if (network::g_pRoveCommUDPNode)
228 {
229 // Check if we should send packets to the SIM or board.
230 const char* cIPAddress = constants::MODE_SIM ? constants::SIM_IP_ADDRESS.c_str() : manifest::Core::IP_ADDRESS.IP_STR.c_str();
231 // Send packet.
232 network::g_pRoveCommUDPNode->SendUDPPacket(stPacket, cIPAddress, constants::ROVECOMM_OUTGOING_UDP_PORT);
233 }
234
235 // Submit logger message.
236 LOG_DEBUG(logging::g_qSharedLogger, "Driving at: ({}, {})", m_stDrivePowers.dLeftDrivePower, m_stDrivePowers.dRightDrivePower);
237}
float VariableDriveEffort()
This method calculates a multiplier that is applied to SetMaxDriveEffort() to adjust the speed of the...
Definition DriveBoard.cpp:280
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SendStop()

void DriveBoard::SendStop ( )

Stop the drivetrain of the Rover.

Author
Eli Byrd (edbgk.nosp@m.k@ms.nosp@m.t.edu)
Date
2023-06-18
247{
248 // Update member variables with new target speeds.
249 m_stDrivePowers.dLeftDrivePower = 0.0;
250 m_stDrivePowers.dRightDrivePower = 0.0;
251
252 // Construct a RoveComm packet with the drive data.
253 rovecomm::RoveCommPacket<float> stPacket;
254 stPacket.unDataId = manifest::Core::COMMANDS.find("DRIVELEFTRIGHT")->second.DATA_ID;
255 stPacket.unDataCount = manifest::Core::COMMANDS.find("DRIVELEFTRIGHT")->second.DATA_COUNT;
256 stPacket.eDataType = manifest::Core::COMMANDS.find("DRIVELEFTRIGHT")->second.DATA_TYPE;
257 stPacket.vData.emplace_back(m_stDrivePowers.dLeftDrivePower);
258 stPacket.vData.emplace_back(m_stDrivePowers.dRightDrivePower);
259 // Check if we should send packets to the SIM or board.
260 const char* cIPAddress = constants::MODE_SIM ? constants::SIM_IP_ADDRESS.c_str() : manifest::Core::IP_ADDRESS.IP_STR.c_str();
261 // Send drive command over RoveComm to drive board.
262 if (network::g_pRoveCommUDPNode)
263 {
264 network::g_pRoveCommUDPNode->SendUDPPacket(stPacket, cIPAddress, constants::ROVECOMM_OUTGOING_UDP_PORT);
265 }
266 // Submit logger message.
267 LOG_DEBUG(logging::g_qSharedLogger, "Sent stop powers to drivetrain.");
268}
Here is the caller graph for this function:

◆ VariableDriveEffort()

float DriveBoard::VariableDriveEffort ( )

This method calculates a multiplier that is applied to SetMaxDriveEffort() to adjust the speed of the rover in relation to the risk of the terrain.

Returns
fMultiplier - A multiplier value between m_fMinDamp and m_fMaxDamp
Author
Hunter LeRette (hrlnp.nosp@m.c@ms.nosp@m.t.edu), Jordan Hoover (jh69n.nosp@m.@mst.nosp@m..edu), Aiden Buter (ab9hm.nosp@m.@mst.nosp@m..edu)
Date
2026-01-10
281{
282 // Get pointer to camera.
283 std::shared_ptr<ZEDCamera> ExampleZEDCam1 = globals::g_pCameraHandler->GetZED(CameraHandler::ZEDCamName::eHeadMainCam);
284 // Declare data structures to store data in.
285 sl::SensorsData slSensorData;
286
287 // Put in a request to have our empty sensors data variable filled with the most recent data from the camera.
288 std::future<bool> fuCopyStatus = ExampleZEDCam1->RequestSensorsCopy(slSensorData);
289 float fMultiplier = 1;
290
291 // Now we are ready to use the sensors data, let's make sure we have it or wait until we do.
292 if (fuCopyStatus.get())
293 {
294 // Declare roll, pitch, yaw from sensor data
295 float fRoll = fabs(slSensorData.imu.pose.getEulerAngles(false).z);
296 float fPitch = fabs(slSensorData.imu.pose.getEulerAngles(false).x);
297 float fYaw = slSensorData.imu.pose.getEulerAngles(false).y;
298
299 // Calculate the risk factor to be applied to the linear polarization equation
300 float fTheta = fRoll * (m_fRoll_w) + fPitch * (m_fPitch_w) + fYaw * (m_fYaw_w);
301
302 // Clamp damping based on slope angle: Max damping on flat terrain, Min damping on risky terrain
303 if (fTheta <= m_fMinSlope)
304 fMultiplier = m_fMaxDamp;
305 if (fTheta >= m_fMaxSlope)
306 fMultiplier = m_fMinDamp;
307
308 // Calculate multiplier using linear polarization
309 const float fK = (m_fMaxDamp - m_fMinDamp) / (m_fMaxSlope - m_fMinSlope);
310 float fD = m_fMaxDamp - fK * (fTheta - m_fMinSlope);
311
312 // Return multiplier
313 fMultiplier = std::clamp(fD, m_fMinDamp, m_fMaxDamp);
314 }
315
316 return fMultiplier;
317}
std::shared_ptr< ZEDCamera > GetZED(ZEDCamName eCameraName)
Accessor for ZED cameras.
Definition CameraHandler.cpp:215
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SetMaxDriveEffort()

void DriveBoard::SetMaxDriveEffort ( const float  fMaxDriveEffortMultiplier)

Set the max power limits of the drive.

Parameters
fMaxDriveEffortMultiplier- A multiplier from 0-1 for the max power output of the drive. Multiplier will be applied to constants::DRIVE_MIN_POWER and constants::DRIVE_MAX_POWER.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2024-03-15
329{
330 // Clamp the multiplier to the range [0, 1].
331 float fClampedMaxDriveEffortMultiplier = std::clamp(fMaxDriveEffortMultiplier, 0.0f, constants::DRIVE_MAX_POWER);
332
333 // Update member variables.
334 std::unique_lock<std::shared_mutex> lkDriveEffortLock(m_muDriveEffortMutex);
335 m_fDriveEffortMultiplier = fClampedMaxDriveEffortMultiplier;
336}

◆ GetDrivePowers()

diffdrive::DrivePowers DriveBoard::GetDrivePowers ( ) const

Accessor for the current drive powers of the robot.

Returns
diffdrive::DrivePowers - A struct containing the left and right drive power of the drivetrain.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2023-10-20
347{
348 // Return the current drive powers.
349 return m_stDrivePowers;
350}
Here is the caller graph for this function:

◆ GetMaxDriveEffort()

float DriveBoard::GetMaxDriveEffort ( ) const

Accessor for the current max drive effort multiplier.

Returns
float - The current drive effort multiplier being applied to the drive powers. This is a value between 0 and 1 that is multiplied by the constants DRIVE_MIN_POWER and DRIVE_MAX_POWER to set the current power limits of the drive.
Author
ClayJay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2026-05-17
362{
363 // Return the current max drive effort multiplier.
364 std::shared_lock<std::shared_mutex> lkDriveEffortLock(m_muDriveEffortMutex);
365 return m_fDriveEffortMultiplier;
366}
Here is the caller graph for this function:

Member Data Documentation

◆ SetMaxSpeedCallback

const std::function<void(const rovecomm::RoveCommPacket<float>&, const sockaddr_in&)> DriveBoard::SetMaxSpeedCallback
private
Initial value:
=
[this](const rovecomm::RoveCommPacket<float>& stPacket, const sockaddr_in& stdAddr)
{
(void) stdAddr;
float fClampedMultiplier = std::clamp(std::fabs(stPacket.vData[0]), 0.0f, 1.0f);
{
std::unique_lock<std::shared_mutex> lkDriveEffortLock(m_muDriveEffortMutex);
m_fDriveEffortMultiplier = fClampedMultiplier;
}
LOG_NOTICE(logging::g_qSharedLogger, "Incoming SETMAXSPEED: {}", fClampedMultiplier);
}

Callback function that is called whenever RoveComm receives a new SETMAXSPEED packet.

Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2024-03-03
102 {
103 // Not using this.
104 (void) stdAddr;
105
106 // Clamp the incoming multiplier to [0.0, 1.0].
107 float fClampedMultiplier = std::clamp(std::fabs(stPacket.vData[0]), 0.0f, 1.0f);
108 // Update member variable.
109 {
110 std::unique_lock<std::shared_mutex> lkDriveEffortLock(m_muDriveEffortMutex);
111 m_fDriveEffortMultiplier = fClampedMultiplier;
112 }
113
114 // Submit logger message.
115 LOG_NOTICE(logging::g_qSharedLogger, "Incoming SETMAXSPEED: {}", fClampedMultiplier);
116 };

The documentation for this class was generated from the following files: