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
statemachine::StuckState Class Reference

The StuckState class implements the Stuck state for the Autonomy State Machine. More...

#include <StuckState.h>

Inheritance diagram for statemachine::StuckState:
Collaboration diagram for statemachine::StuckState:

Public Member Functions

 StuckState ()
 Construct a new State object.
 
void Run () override
 Run the state machine. Returns the next state.
 
States TriggerEvent (Event eEvent) override
 Trigger an event in the state machine. Returns the next state.
 
- Public Member Functions inherited from statemachine::State
 State (States eState)
 Construct a new State object.
 
virtual ~State ()=default
 Destroy the State object.
 
States GetState () const
 Accessor for the State private member.
 
virtual std::string ToString () const
 Accessor for the State private member. Returns the state as a string.
 
virtual bool operator== (const State &other) const
 Checks to see if the current state is equal to the passed state.
 
virtual bool operator!= (const State &other) const
 Checks to see if the current state is not equal to the passed state.
 

Protected Member Functions

void Start () override
 This method is called when the state is first started. It is used to initialize the state.
 
void Exit () override
 This method is called when the state is exited. It is used to clean up the state.
 

Private Types

enum class  AttemptType { eReverseCurrentHeading , eReverseLeft , eReverseRight , eGiveUp }
 

Private Member Functions

bool SamePosition (const geoops::GPSCoordinate &stOriginalPosition, const geoops::GPSCoordinate &stCurrPosition)
 Checks if the rover is approximately in the same position.
 

Private Attributes

bool m_bInitialized
 
States m_eTriggeringState
 
AttemptType m_eAttemptType
 
geoops::GPSCoordinate m_stOriginalPosition
 
double m_dOriginalHeading
 
bool m_bIsCurrentlyAligning
 
std::chrono::system_clock::time_point m_tmStuckStartTime
 
std::chrono::system_clock::time_point m_tmAlignStartTime
 

Detailed Description

The StuckState class implements the Stuck state for the Autonomy State Machine.

Author
Eli Byrd (edbgk.nosp@m.k@ms.nosp@m.t.edu), Jason Pittman (jspen.nosp@m.cerp.nosp@m.ittma.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2024-01-17

Member Enumeration Documentation

◆ AttemptType

enum class statemachine::StuckState::AttemptType
strongprivate
45 {
46 eReverseCurrentHeading,
47 eReverseLeft,
48 eReverseRight,
49 eGiveUp
50 };

Constructor & Destructor Documentation

◆ StuckState()

statemachine::StuckState::StuckState ( )

Construct a new State object.

Author
Eli Byrd (edbgk.nosp@m.k@ms.nosp@m.t.edu)
Date
2024-01-17
78 : State(States::eStuck)
79 {
80 LOG_INFO(logging::g_qConsoleLogger, "Entering State: {}", ToString());
81
82 m_bInitialized = false;
83
84 if (!m_bInitialized)
85 {
86 Start();
87 m_bInitialized = true;
88 }
89 }
virtual std::string ToString() const
Accessor for the State private member. Returns the state as a string.
Definition State.hpp:207
State(States eState)
Construct a new State object.
Definition State.hpp:150
void Start() override
This method is called when the state is first started. It is used to initialize the state.
Definition StuckState.cpp:33
Here is the call graph for this function:

Member Function Documentation

◆ SamePosition()

bool statemachine::StuckState::SamePosition ( const geoops::GPSCoordinate stOriginalPosition,
const geoops::GPSCoordinate stCurrPosition 
)
private

Checks if the rover is approximately in the same position.

Note
The threshold that defines how far away we need to be from the original point to be considered a different position is constants::STUCK_SAME_POINT_PROXIMITY.
Parameters
stLastPosition- Original position the rover was located.
stCurrPosition- Current position the rover is located.
Returns
true - The rover is in the same position.
false - The rover is in a different position.
Author
Jason Pittman (jspen.nosp@m.cerp.nosp@m.ittma.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2024-02-14
365 {
366 double dDistance = geoops::CalculateGeoMeasurement(stOriginalPosition, stCurrPosition).dDistanceMeters;
367 return dDistance <= constants::STUCK_SAME_POINT_PROXIMITY;
368 }
GeoMeasurement CalculateGeoMeasurement(const GPSCoordinate &stCoord1, const GPSCoordinate &stCoord2)
The shortest path between two points on an ellipsoid at (lat1, lon1) and (lat2, lon2) is called the g...
Definition GeospatialOperations.hpp:445
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Start()

void statemachine::StuckState::Start ( )
overrideprotectedvirtual

This method is called when the state is first started. It is used to initialize the state.

Author
Eli Byrd (edbgk.nosp@m.k@ms.nosp@m.t.edu)
Date
2024-01-17

Reimplemented from statemachine::State.

34 {
35 // Schedule the next run of the state's logic
36 LOG_INFO(logging::g_qSharedLogger, "StuckState: Scheduling next run of state logic.");
37
38 // Initialize member variables.
39 m_dOriginalHeading = 0;
40 m_bIsCurrentlyAligning = false;
41 m_eAttemptType = AttemptType::eReverseCurrentHeading;
42
43 // Store the state that got stuck and triggered a stuck event.
44 m_eTriggeringState = globals::g_pStateMachineHandler->GetPreviousState();
45
46 // Store the postion and heading where the rover get stuck.
47 geoops::RoverPose stStartRoverPose = globals::g_pWaypointHandler->SmartRetrieveRoverPose();
48 m_stOriginalPosition = stStartRoverPose.GetGPSCoordinate();
49 m_dOriginalHeading = stStartRoverPose.GetCompassHeading();
50 // Get state start time.
51 m_tmStuckStartTime = std::chrono::system_clock::now();
52
53 // Stop drivetrain.
54 globals::g_pDriveBoard->SendStop();
55 }
void SendStop()
Stop the drivetrain of the Rover.
Definition DriveBoard.cpp:162
statemachine::States GetPreviousState() const
Accessor for the Previous State private member.
Definition StateMachineHandler.cpp:407
geoops::RoverPose SmartRetrieveRoverPose(bool bVIOTracking=false)
Retrieve the rover's current position and heading. Automatically picks between getting the position/h...
Definition WaypointHandler.cpp:738
This struct is used by the WaypointHandler to provide an easy way to store all pose data about the ro...
Definition GeospatialOperations.hpp:674
const geoops::GPSCoordinate & GetGPSCoordinate() const
Accessor for the geoops::GPSCoordinate member variable.
Definition GeospatialOperations.hpp:722
double GetCompassHeading() const
Accessor for the Compass Heading private member.
Definition GeospatialOperations.hpp:743
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Exit()

void statemachine::StuckState::Exit ( )
overrideprotectedvirtual

This method is called when the state is exited. It is used to clean up the state.

Author
Eli Byrd (edbgk.nosp@m.k@ms.nosp@m.t.edu)
Date
2024-01-17

Reimplemented from statemachine::State.

66 {
67 // Clean up the state before exiting
68 LOG_INFO(logging::g_qSharedLogger, "StuckState: Exiting state.");
69 }
Here is the caller graph for this function:

◆ Run()

void statemachine::StuckState::Run ( )
overridevirtual

Run the state machine. Returns the next state.

Author
Eli Byrd (edbgk.nosp@m.k@ms.nosp@m.t.edu), Jason Pittman (jspen.nosp@m.cerp.nosp@m.ittma.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om), clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2024-01-17

Implements statemachine::State.

98 {
99 // Submit logger message.
100 LOG_DEBUG(logging::g_qSharedLogger, "StuckState: Running state-specific behavior.");
101
102 // Store the current postion and heading.
103 geoops::RoverPose stCurrentRoverPose = globals::g_pWaypointHandler->SmartRetrieveRoverPose();
104 // Get current time.
105 std::chrono::system_clock::time_point tmCurrentTime = std::chrono::system_clock::now();
106
107 // Check if we are unstuck from our starting spot.
108 if (!this->SamePosition(m_stOriginalPosition, stCurrentRoverPose.GetGPSCoordinate()))
109 {
110 // Submit logger message.
111 LOG_NOTICE(logging::g_qSharedLogger,
112 "StuckState: Rover has successfully unstuckith itself! A total of {} seconds was wasted being stuck.",
113 std::chrono::duration_cast<std::chrono::seconds>(tmCurrentTime - m_tmStuckStartTime).count());
114 // Handing unstuck event. Destroy this unstuck state.
115 globals::g_pStateMachineHandler->HandleEvent(Event::eUnstuck, false);
116 }
117 else
118 {
119 // Perform unstuck logic.
120 switch (m_eAttemptType)
121 {
122 // On the first attempt we use the rover's original heading so alignment would already be completed.
123 case AttemptType::eReverseCurrentHeading:
124 {
125 // Submit logger message.
126 LOG_INFO(logging::g_qSharedLogger, "StuckState: Maintaining current heading and reversing...");
127 // Update stuck type enum for if we are still stuck after reversing.
128 m_eAttemptType = AttemptType::eReverseLeft;
129 // Handle reversing event. Save current state.
130 globals::g_pStateMachineHandler->HandleEvent(Event::eReverse, true);
131 break;
132 }
133 // On the second attempt align the rover constants::STUCK_ALIGN_DEGREES degrees to the right of the original heading instead.
134 case AttemptType::eReverseLeft:
135 {
136 // Check if we are already realigning.
137 if (!m_bIsCurrentlyAligning)
138 {
139 // Submit logger message.
140 LOG_INFO(logging::g_qSharedLogger, "StuckState: Aligning rover heading {} degrees clockwise...", constants::STUCK_ALIGN_DEGREES);
141 // Set aligning toggle.
142 m_bIsCurrentlyAligning = true;
143 // Update start heading.
144 m_dOriginalHeading = stCurrentRoverPose.GetCompassHeading();
145 // Update start time.
146 m_tmAlignStartTime = std::chrono::system_clock::now();
147 }
148 else
149 {
150 // Calculate time elapsed since realignment was started.
151 double dTimeElapsed = std::chrono::duration_cast<std::chrono::seconds>(tmCurrentTime - m_tmAlignStartTime).count();
152 // Calculate the goal realignment heading.
153 double dGoalHeading = numops::InputAngleModulus<double>(m_dOriginalHeading + constants::STUCK_ALIGN_DEGREES, 0, 360);
154 // Calculate total rotation degrees so far.
155 double dRealignmentDegrees = numops::AngularDifference<double>(stCurrentRoverPose.GetCompassHeading(), dGoalHeading);
156
157 // Align drivetrain to a certain heading with 0 forward/reverse power.
158 diffdrive::DrivePowers stTurnPowers = globals::g_pDriveBoard->CalculateMove(0.0,
159 dGoalHeading,
160 stCurrentRoverPose.GetCompassHeading(),
161 diffdrive::DifferentialControlMethod::eArcadeDrive);
162 // Send drive powers.
163 globals::g_pDriveBoard->SendDrive(stTurnPowers);
164
165 // Check if we have successfully realigned.
166 if (dRealignmentDegrees <= constants::STUCK_ALIGN_TOLERANCE)
167 {
168 // Submit logger message.
169 LOG_INFO(logging::g_qSharedLogger, "StuckState: Realignment complete! Reversing...");
170 // Update stuck type enum for if we are still stuck after reversing.
171 m_eAttemptType = AttemptType::eReverseRight;
172 // Reset currently aligning toggle.
173 m_bIsCurrentlyAligning = false;
174 // Handle reversing event.
175 globals::g_pStateMachineHandler->HandleEvent(Event::eReverse, true);
176 }
177 // If not aligned yet, check if we hit the timeout.
178 else if (dTimeElapsed >= constants::STUCK_HEADING_ALIGN_TIMEOUT)
179 {
180 // Submit logger message.
181 LOG_NOTICE(logging::g_qSharedLogger,
182 "StuckState: Rotated/Realigned {} degrees in {} seconds before timeout was reached. Rover is still stuck...",
183 constants::STUCK_ALIGN_DEGREES - dRealignmentDegrees,
184 dTimeElapsed);
185 // Update stuck type enum for if we are still stuck after reversing.
186 m_eAttemptType = AttemptType::eReverseRight;
187 // Reset currently aligning toggle.
188 m_bIsCurrentlyAligning = false;
189 // Handle reversing event.
190 globals::g_pStateMachineHandler->HandleEvent(Event::eReverse, true);
191 }
192 }
193 break;
194 }
195 // For the third do it constants::STUCK_ALIGN_DEGREES degrees to the left of the original heading.
196 case AttemptType::eReverseRight:
197 {
198 // Check if we are already realigning.
199 if (!m_bIsCurrentlyAligning)
200 {
201 // Submit logger message.
202 LOG_INFO(logging::g_qSharedLogger, "StuckState: Aligning rover heading {} degrees counter-clockwise...", constants::STUCK_ALIGN_DEGREES);
203 // Set aligning toggle.
204 m_bIsCurrentlyAligning = true;
205 // Update start heading.
206 m_dOriginalHeading = stCurrentRoverPose.GetCompassHeading();
207 // Update start time.
208 m_tmAlignStartTime = std::chrono::system_clock::now();
209 }
210 else
211 {
212 // Calculate time elapsed since realignment was started.
213 double dTimeElapsed = std::chrono::duration_cast<std::chrono::seconds>(tmCurrentTime - m_tmAlignStartTime).count();
214 // Calculate the goal realignment heading.
215 double dGoalHeading = numops::InputAngleModulus<double>(m_dOriginalHeading - constants::STUCK_ALIGN_DEGREES, 0, 360);
216 // Calculate total rotation degrees so far.
217 double dRealignmentDegrees = numops::AngularDifference<double>(stCurrentRoverPose.GetCompassHeading(), dGoalHeading);
218
219 // Align drivetrain to a certain heading with 0 forward/reverse power.
220 diffdrive::DrivePowers stTurnPowers = globals::g_pDriveBoard->CalculateMove(0.0,
221 dGoalHeading,
222 stCurrentRoverPose.GetCompassHeading(),
223 diffdrive::DifferentialControlMethod::eArcadeDrive);
224 // Send drive powers.
225 globals::g_pDriveBoard->SendDrive(stTurnPowers);
226
227 // Check if we have successfully realigned.
228 if (dRealignmentDegrees <= constants::STUCK_ALIGN_TOLERANCE)
229 {
230 // Submit logger message.
231 LOG_INFO(logging::g_qSharedLogger, "StuckState: Realignment complete! Reversing...");
232 // Update stuck type enum for if we are still stuck after reversing.
233 m_eAttemptType = AttemptType::eGiveUp;
234 // Reset currently aligning toggle.
235 m_bIsCurrentlyAligning = false;
236 // Handle reversing event.
237 globals::g_pStateMachineHandler->HandleEvent(Event::eReverse, true);
238 }
239 // If not aligned yet, check if we hit the timeout.
240 else if (dTimeElapsed >= constants::STUCK_HEADING_ALIGN_TIMEOUT)
241 {
242 // Submit logger message.
243 LOG_NOTICE(logging::g_qSharedLogger,
244 "StuckState: Rotated/Realigned {} degrees in {} seconds before timeout was reached. Rover is still stuck...",
245 constants::STUCK_ALIGN_DEGREES - dRealignmentDegrees,
246 dTimeElapsed);
247 // Update stuck type enum for if we are still stuck after reversing.
248 m_eAttemptType = AttemptType::eGiveUp;
249 // Reset currently aligning toggle.
250 m_bIsCurrentlyAligning = false;
251 // Handle reversing event.
252 globals::g_pStateMachineHandler->HandleEvent(Event::eReverse, true);
253 }
254 }
255 break;
256 }
257 case AttemptType::eGiveUp:
258 {
259 // Submit logger message.
260 LOG_WARNING(logging::g_qSharedLogger, "StuckState: After multiple attempts, autonomy was unable to get the rover unstuck. Giving Up...");
261 // Return to idle.
262 globals::g_pStateMachineHandler->HandleEvent(Event::eAbort);
263 break;
264 }
265 default:
266 {
267 // Submit logger message.
268 LOG_ERROR(logging::g_qSharedLogger, "StuckState: Unknown attempt type!");
269 // Return to idle.
270 globals::g_pStateMachineHandler->HandleEvent(Event::eAbort);
271 break;
272 }
273 }
274 }
275 }
diffdrive::DrivePowers CalculateMove(const double dGoalSpeed, const double dGoalHeading, const double dActualHeading, const diffdrive::DifferentialControlMethod eKinematicsMethod)
This method determines drive powers to make the Rover drive towards a given heading at a given speed.
Definition DriveBoard.cpp:92
void SendDrive(diffdrive::DrivePowers &stDrivePowers)
Sets the left and right drive powers of the drive board.
Definition DriveBoard.cpp:120
void HandleEvent(statemachine::Event eEvent, const bool bSaveCurrentState=false)
This method Handles Events that are passed to the State Machine Handler. It will check the current st...
Definition StateMachineHandler.cpp:337
bool SamePosition(const geoops::GPSCoordinate &stOriginalPosition, const geoops::GPSCoordinate &stCurrPosition)
Checks if the rover is approximately in the same position.
Definition StuckState.cpp:364
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:

◆ TriggerEvent()

States statemachine::StuckState::TriggerEvent ( Event  eEvent)
overridevirtual

Trigger an event in the state machine. Returns the next state.

Parameters
eEvent- The event to trigger.
Returns
std::shared_ptr<State> - The next state.
Author
Eli Byrd (edbgk.nosp@m.k@ms.nosp@m.t.edu), clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2024-01-17

Implements statemachine::State.

287 {
288 // Create instance variables.
289 States eNextState = States::eStuck;
290 bool bCompleteStateExit = true;
291
292 switch (eEvent)
293 {
294 case Event::eStart:
295 {
296 // Submit logger message.
297 LOG_INFO(logging::g_qSharedLogger, "StuckState: Handling Start event.");
298 // Send multimedia command to update state display.
299 globals::g_pMultimediaBoard->SendLightingState(MultimediaBoard::MultimediaBoardLightingState::eAutonomy);
300 break;
301 }
302 case Event::eAbort:
303 {
304 // Submit logger message.
305 LOG_INFO(logging::g_qSharedLogger, "StuckState: Handling Abort event.");
306 // Send multimedia command to update state display.
307 globals::g_pMultimediaBoard->SendLightingState(MultimediaBoard::MultimediaBoardLightingState::eAutonomy);
308 // Change state.
309 eNextState = States::eIdle;
310 break;
311 }
312 case Event::eReverse:
313 {
314 // Submit logger message.
315 LOG_INFO(logging::g_qSharedLogger, "StuckState: Handling Reverse event.");
316 // Change state.
317 eNextState = States::eReversing;
318 break;
319 }
320 case Event::eUnstuck:
321 {
322 // Submit logger message.
323 LOG_INFO(logging::g_qSharedLogger, "StuckState: Handling Unstuck event.");
324 // Change state back to the state that originally got stuck.
325 eNextState = m_eTriggeringState;
326 break;
327 }
328 default:
329 {
330 LOG_WARNING(logging::g_qSharedLogger, "StuckState: Handling unknown event.");
331 eNextState = States::eIdle;
332 break;
333 }
334 }
335
336 if (eNextState != States::eStuck)
337 {
338 LOG_INFO(logging::g_qSharedLogger, "StuckState: Transitioning to {} State.", StateToString(eNextState));
339
340 // Exit the current state
341 if (bCompleteStateExit)
342 {
343 Exit();
344 }
345 }
346
347 return eNextState;
348 }
void SendLightingState(MultimediaBoardLightingState eState)
Sends a predetermined color pattern to board.
Definition MultimediaBoard.cpp:55
void Exit() override
This method is called when the state is exited. It is used to clean up the state.
Definition StuckState.cpp:65
std::string StateToString(States eState)
Converts a state object to a string.
Definition State.hpp:89
States
The states that the state machine can be in.
Definition State.hpp:31
Here is the call graph for this function:

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