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 bAlwaysProgressForward=false)
 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.
 

Private Attributes

diffdrive::DrivePowers m_stDrivePowers
 
std::unique_ptr< controllers::PIDControllerm_pPID
 
float m_fMinDriveEffort
 
float m_fMaxDriveEffort
 
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_fMinDriveEffort = constants::DRIVE_MIN_POWER;
37 m_fMaxDriveEffort = constants::DRIVE_MAX_POWER;
38 m_fDriveEffortMultiplier = 1.0f;
39
40 // Configure PID controller for heading hold function.
41 m_pPID = std::make_unique<controllers::PIDController>(constants::DRIVE_PID_PROPORTIONAL,
42 constants::DRIVE_PID_INTEGRAL,
43 constants::DRIVE_PID_DERIVATIVE,
44 constants::DRIVE_PID_FEEDFORWARD);
45 m_pPID->SetMaxSetpointDifference(constants::DRIVE_PID_MAX_ERROR);
46 m_pPID->SetMaxIntegralEffort(constants::DRIVE_PID_MAX_INTEGRAL_TERM);
47 m_pPID->SetOutputLimits(1.0); // Autonomy internally always uses -1.0, 1.0 for turning and drive powers.
48 m_pPID->SetOutputRampRate(constants::DRIVE_PID_MAX_RAMP_RATE);
49 m_pPID->SetOutputFilter(constants::DRIVE_PID_OUTPUT_FILTER);
50 m_pPID->SetTolerance(constants::DRIVE_PID_TOLERANCE);
51 m_pPID->SetDirection(constants::DRIVE_PID_OUTPUT_REVERSED);
52 m_pPID->EnableContinuousInput(0, 360);
53
54 // Set RoveComm callbacks.
55 if (network::g_pRoveCommUDPNode)
56 {
57 network::g_pRoveCommUDPNode->AddUDPCallback<float>(SetMaxSpeedCallback, manifest::Autonomy::COMMANDS.find("SETMAXSPEED")->second.DATA_ID);
58 }
59}
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:98

◆ ~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
69{
70 // Stop drivetrain.
71 this->SendStop();
72}
void SendStop()
Stop the drivetrain of the Rover.
Definition DriveBoard.cpp:195
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  bAlwaysProgressForward = false 
)

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
bAlwaysProgressForward- If true, the rover will always move forward or backward. Point turns will not be allowed.
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
2023-09-21
93{
94 // Calculate the drive powers from the current heading, goal heading, and goal speed.
96 dGoalHeading,
97 dActualHeading,
98 eKinematicsMethod,
99 *m_pPID,
100 bAlwaysProgressForward,
101 constants::DRIVE_SQUARE_CONTROL_INPUTS,
102 constants::DRIVE_CURVATURE_KINEMATICS_ALLOW_TURN_WHILE_STOPPED);
103
104 return stDrivePowers;
105}
DrivePowers CalculateMotorPowerFromHeading(double dGoalSpeed, double dGoalHeading, double dActualHeading, const DifferentialControlMethod eDriveMethod, controllers::PIDController &PID, const bool bAlwaysProgressForward=false, const bool bSquareControlInput=false, const bool bCurvatureDriveAllowTurningWhileStopped=true)
This function will calculate the drive powers for a given speed and absolute heading....
Definition DifferentialDrive.hpp:237
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
119{
120 // Enable or disable variable drive effort.
121 if (bEnableVariableDriveEffort)
122 {
123 float fMultiplier = VariableDriveEffort();
124 SetMaxDriveEffort(fMultiplier);
125 }
126
127 // Limit input values (-1.0 to 1.0).
128 double dLeftInput = std::clamp(stDrivePowers.dLeftDrivePower, -1.0, 1.0);
129 double dRightInput = std::clamp(stDrivePowers.dRightDrivePower, -1.0, 1.0);
130
131 // -------------------------------------------------------------------------
132 // Decouple Linear and Angular components to fix low-speed turning.
133 // -------------------------------------------------------------------------
134 // Separate Linear (Forward/Back) and Angular (Turn) power.
135 double dLinearPower = (dLeftInput + dRightInput) / 2.0;
136 double dAngularPower = (dLeftInput - dRightInput) / 2.0;
137
138 // Apply the Speed Multiplier ONLY to the Linear component.
139 // This slows down the travel speed but keeps full turning torque available.
140 // Use a shared lock to prevent data races when reading the multiplier.
141 {
142 std::shared_lock<std::shared_mutex> lkDriveEffortLock(m_muDriveEffortMutex);
143 dLinearPower *= m_fDriveEffortMultiplier;
144 }
145
146 // Reconstruct Left and Right powers.
147 double dLeftSpeed = dLinearPower + dAngularPower;
148 double dRightSpeed = dLinearPower - dAngularPower;
149
150 // Desaturate the output to preserve the turning ratio if it exceeds the max.
151 // If we commanded (1.0, 0.5) and scaled linear by 0.1, we might get (0.1, 0.05).
152 // But if turning adds significant power, we might exceed 1.0.
153 double dMaxMagnitude = std::max(std::abs(dLeftSpeed), std::abs(dRightSpeed));
154 if (dMaxMagnitude > 1.0)
155 {
156 dLeftSpeed /= dMaxMagnitude;
157 dRightSpeed /= dMaxMagnitude;
158 }
159 // -------------------------------------------------------------------------
160
161 // If the min and max drive effort have been set to 0, then just send zero powers.
162 if (m_fMinDriveEffort != 0.0 || m_fMaxDriveEffort != 0.0)
163 {
164 // Limit the power to max and min effort defined in constants (Slope Safety).
165 m_stDrivePowers.dLeftDrivePower = std::clamp(float(dLeftSpeed), m_fMinDriveEffort, m_fMaxDriveEffort);
166 m_stDrivePowers.dRightDrivePower = std::clamp(float(dRightSpeed), m_fMinDriveEffort, m_fMaxDriveEffort);
167 }
168
169 // Construct a RoveComm packet with the drive data.
170 rovecomm::RoveCommPacket<float> stPacket;
171 stPacket.unDataId = manifest::Core::COMMANDS.find("DRIVELEFTRIGHT")->second.DATA_ID;
172 stPacket.unDataCount = manifest::Core::COMMANDS.find("DRIVELEFTRIGHT")->second.DATA_COUNT;
173 stPacket.eDataType = manifest::Core::COMMANDS.find("DRIVELEFTRIGHT")->second.DATA_TYPE;
174 stPacket.vData.emplace_back(m_stDrivePowers.dLeftDrivePower);
175 stPacket.vData.emplace_back(m_stDrivePowers.dRightDrivePower);
176 // Send drive command over RoveComm to drive board.
177 if (network::g_pRoveCommUDPNode)
178 {
179 // Check if we should send packets to the SIM or board.
180 const char* cIPAddress = constants::MODE_SIM ? constants::SIM_IP_ADDRESS.c_str() : manifest::Core::IP_ADDRESS.IP_STR.c_str();
181 // Send packet.
182 network::g_pRoveCommUDPNode->SendUDPPacket(stPacket, cIPAddress, constants::ROVECOMM_OUTGOING_UDP_PORT);
183 }
184 // Submit logger message.
185 LOG_DEBUG(logging::g_qSharedLogger, "Driving at: ({}, {})", m_stDrivePowers.dLeftDrivePower, m_stDrivePowers.dRightDrivePower);
186}
void SetMaxDriveEffort(const float fMaxDriveEffortMultiplier)
Set the max power limits of the drive.
Definition DriveBoard.cpp:277
float VariableDriveEffort()
This method calculates a multiplier that is applied to SetMaxDriveEffort() to adjust the speed of the...
Definition DriveBoard.cpp:229
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
196{
197 // Update member variables with new target speeds.
198 m_stDrivePowers.dLeftDrivePower = 0.0;
199 m_stDrivePowers.dRightDrivePower = 0.0;
200
201 // Construct a RoveComm packet with the drive data.
202 rovecomm::RoveCommPacket<float> stPacket;
203 stPacket.unDataId = manifest::Core::COMMANDS.find("DRIVELEFTRIGHT")->second.DATA_ID;
204 stPacket.unDataCount = manifest::Core::COMMANDS.find("DRIVELEFTRIGHT")->second.DATA_COUNT;
205 stPacket.eDataType = manifest::Core::COMMANDS.find("DRIVELEFTRIGHT")->second.DATA_TYPE;
206 stPacket.vData.emplace_back(m_stDrivePowers.dLeftDrivePower);
207 stPacket.vData.emplace_back(m_stDrivePowers.dRightDrivePower);
208 // Check if we should send packets to the SIM or board.
209 const char* cIPAddress = constants::MODE_SIM ? constants::SIM_IP_ADDRESS.c_str() : manifest::Core::IP_ADDRESS.IP_STR.c_str();
210 // Send drive command over RoveComm to drive board.
211 if (network::g_pRoveCommUDPNode)
212 {
213 network::g_pRoveCommUDPNode->SendUDPPacket(stPacket, cIPAddress, constants::ROVECOMM_OUTGOING_UDP_PORT);
214 }
215 // Submit logger message.
216 LOG_DEBUG(logging::g_qSharedLogger, "Sent stop powers to drivetrain");
217}
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
230{
231 // Get pointer to camera.
232 std::shared_ptr<ZEDCamera> ExampleZEDCam1 = globals::g_pCameraHandler->GetZED(CameraHandler::ZEDCamName::eHeadMainCam);
233 // Declare data structures to store data in.
234 sl::SensorsData slSensorData;
235
236 // Put in a request to have our empty sensors data variable filled with the most recent data from the camera.
237 std::future<bool> fuCopyStatus = ExampleZEDCam1->RequestSensorsCopy(slSensorData);
238 float fMultiplier = 1;
239
240 // Now we are ready to use the sensors data, let's make sure we have it or wait until we do.
241 if (fuCopyStatus.get())
242 {
243 // Declare roll, pitch, yaw from sensor data
244 float fRoll = fabs(slSensorData.imu.pose.getEulerAngles(false).z);
245 float fPitch = fabs(slSensorData.imu.pose.getEulerAngles(false).x);
246 float fYaw = slSensorData.imu.pose.getEulerAngles(false).y;
247
248 // Calculate the risk factor to be applied to the linear polarization equation
249 float fTheta = fRoll * (m_fRoll_w) + fPitch * (m_fPitch_w) + fYaw * (m_fYaw_w);
250
251 // Clamp damping based on slope angle: Max damping on flat terrain, Min damping on risky terrain
252 if (fTheta <= m_fMinSlope)
253 fMultiplier = m_fMaxDamp;
254 if (fTheta >= m_fMaxSlope)
255 fMultiplier = m_fMinDamp;
256
257 // Calculate multiplier using linear polarization
258 const float fK = (m_fMaxDamp - m_fMinDamp) / (m_fMaxSlope - m_fMinSlope);
259 float fD = m_fMaxDamp - fK * (fTheta - m_fMinSlope);
260
261 // Return multiplier
262 fMultiplier = std::clamp(fD, m_fMinDamp, m_fMaxDamp);
263 }
264
265 return fMultiplier;
266}
std::shared_ptr< ZEDCamera > GetZED(ZEDCamName eCameraName)
Accessor for ZED cameras.
Definition CameraHandler.cpp:170
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
278{
279 // Clamp the multiplier to the range [0, 1].
280 float fClampedMaxDriveEffortMultiplier = std::clamp(fMaxDriveEffortMultiplier, 0.0f, constants::DRIVE_MAX_POWER);
281
282 // Update member variables.
283 m_fMinDriveEffort = constants::DRIVE_MIN_POWER * fClampedMaxDriveEffortMultiplier;
284 m_fMaxDriveEffort = constants::DRIVE_MAX_POWER * fClampedMaxDriveEffortMultiplier;
285}
Here is the caller graph for this function:

◆ 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
296{
297 // Return the current drive powers.
298 return m_stDrivePowers;
299}
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: {}", stPacket.vData[0]);
}

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
100 {
101 // Not using this.
102 (void) stdAddr;
103
104 // Clamp the incoming multiplier to [0.0, 1.0].
105 float fClampedMultiplier = std::clamp(std::fabs(stPacket.vData[0]), 0.0f, 1.0f);
106 // Update member variable.
107 {
108 std::unique_lock<std::shared_mutex> lkDriveEffortLock(m_muDriveEffortMutex);
109 m_fDriveEffortMultiplier = fClampedMultiplier;
110 }
111
112 // Submit logger message.
113 LOG_NOTICE(logging::g_qSharedLogger, "Incoming SETMAXSPEED: {}", stPacket.vData[0]);
114 };

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