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.
 
void DeclareObstacle ()
 Adds the area in front of the rover as an obstacle by modifying the area's trav-score in LiDAR data.
 
void ModifyPath ()
 Modify stored path to reflect new obstacle and store it for use in returning state.
 
void SplicePath (std::vector< geoops::Waypoint > &vPath, const geoops::UTMCoordinate &stObstaclePosition)
 Removes all points within stuck area in path and re-path plans all deleted paths segments.
 

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
81 : State(States::eStuck)
82 {
83 LOG_INFO(logging::g_qConsoleLogger, "Entering State: {}", ToString());
84
85 m_bInitialized = false;
86
87 if (!m_bInitialized)
88 {
89 Start();
90 m_bInitialized = true;
91 }
92 }
virtual std::string ToString() const
Accessor for the State private member. Returns the state as a string.
Definition State.hpp:202
State(States eState)
Construct a new State object.
Definition State.hpp:145
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
371 {
372 double dDistance = geoops::CalculateGeoMeasurement(stOriginalPosition, stCurrPosition).dDistanceMeters;
373 return dDistance <= constants::STUCK_SAME_POINT_PROXIMITY;
374 }
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:553
Here is the call graph for this function:
Here is the caller graph for this function:

◆ DeclareObstacle()

void statemachine::StuckState::DeclareObstacle ( )
private

Adds the area in front of the rover as an obstacle by modifying the area's trav-score in LiDAR data.

Note
Uses constants::STUCK_OBSTACLE_RADIUS for the declared obstacle's radius and constants::STUCK_OBSTACLE_DISTANCE for distance in front of the rover that is declared an obstacle
Author
Sam Nolte (samno.nosp@m.lte0.nosp@m.302@g.nosp@m.mail.nosp@m..com)
Date
2026-01-27
386 {
387 // Convert from compass degrees to unit circle radians.
388 double dRadians = (90.0 - m_dOriginalHeading) * M_PI / 180.0;
389 if (dRadians < 0)
390 {
391 dRadians += 2 * M_PI;
392 }
393
394 // Get the obstacle's origin.
395 geoops::UTMCoordinate stObstaclePosition = globals::g_pStateMachineHandler->SmartRetrieveRoverPose().GetUTMCoordinate();
396 stObstaclePosition.dEasting += std::cos(dRadians) * constants::STUCK_OBSTACLE_DISTANCE;
397 stObstaclePosition.dNorthing += std::sin(dRadians) * constants::STUCK_OBSTACLE_DISTANCE;
398
399 // Add to waypoint handler obstacle list
400 globals::g_pWaypointHandler->AddObstacle(stObstaclePosition, constants::STUCK_OBSTACLE_RADIUS);
401 }
geoops::RoverPose SmartRetrieveRoverPose(bool bIMUHeading=true)
This method is used to retrieve the rover's current position and heading. It uses the GPS data from t...
Definition StateMachineHandler.cpp:375
void AddObstacle(const geoops::Waypoint &stWaypoint)
Append a new obstacle to the WaypointHandler obstacle list.
Definition WaypointHandler.cpp:203
const geoops::UTMCoordinate & GetUTMCoordinate() const
Accessor for the geoops::UTMCoordinate member variable.
Definition GeospatialOperations.hpp:767
This struct stores/contains information about a UTM coordinate.
Definition GeospatialOperations.hpp:211
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ModifyPath()

void statemachine::StuckState::ModifyPath ( )
private

Modify stored path to reflect new obstacle and store it for use in returning state.

1) Filter out any points that are a specific distance away from the obstacle 2) Connect the rover position to the path to the first node of the vector by path-planning. If the rover is inside the obstacle, then first path plan it to the close edge of the obstacle. 3) Iteratively go through the points of the path vector. If the point is inside the obstacle remove it. If the next point isn't being removed then connect the "hole" in the path by path-planning

Author
Sam Nolte (samno.nosp@m.lte0.nosp@m.302@g.nosp@m.mail.nosp@m..com), Sam Hajdukiewicz (saman.nosp@m.thah.nosp@m.ajduk.nosp@m.iewi.nosp@m.cz@gm.nosp@m.ail..nosp@m.com)
Date
2026-04-13
417 {
418 // Get the rover's pose AFTER stuck state has ran
419 geoops::RoverPose stCurrentRoverPose = globals::g_pStateMachineHandler->SmartRetrieveRoverPose();
420
421 // Check if there are any obstacles.
422 if (globals::g_pWaypointHandler->GetObstaclesCount() == 0)
423 {
424 LOG_WARNING(logging::g_qSharedLogger, "StuckState: No obstacles recorded to splice around!");
425 return;
426 }
427
428 // Get the obstacle's origin
429 int nObstacleIndex = globals::g_pWaypointHandler->GetObstaclesCount() - 1;
430 geoops::UTMCoordinate stObstaclePosition = globals::g_pWaypointHandler->RetrieveObstacleAtIndex(nObstacleIndex).GetUTMCoordinate();
431
432 // Get saved rover path
433 std::vector<geoops::Waypoint> vRefPath = globals::g_pWaypointHandler->RetrievePath("GeoPlannerPath");
434 std::vector<geoops::Waypoint> vSearchRevSpiralPath = globals::g_pWaypointHandler->RetrievePath("GeoPlannerPathReverse");
435
436 if (vRefPath.empty())
437 {
438 LOG_WARNING(logging::g_qSharedLogger, "Stuck state received empty path to modify!");
439 return;
440 }
441
442 // Get the point on the obstacle's border which the rover came from.
443 double dHeadingRad = (90.0 - m_dOriginalHeading) * M_PI / 180.0;
444 if (dHeadingRad < 0)
445 {
446 dHeadingRad += 2 * M_PI;
447 }
448
449 // Grab starting coordinate and goal (edge of obstacle behind rover) coordinate.
450 geoops::UTMCoordinate stStartCoordinate = stCurrentRoverPose.GetUTMCoordinate();
451 geoops::UTMCoordinate stGoalCoordinate = stObstaclePosition;
452
453 // Get goal coordinate easting and northing.
454 stGoalCoordinate.dEasting -= std::cos(dHeadingRad) * constants::STUCK_OBSTACLE_RADIUS;
455 stGoalCoordinate.dNorthing -= std::sin(dHeadingRad) * constants::STUCK_OBSTACLE_RADIUS;
456
457 std::vector<geoops::Waypoint> vSplicePathCoordinates;
458 std::vector<geoops::Waypoint>::iterator it = vRefPath.begin();
459
460 int nPointsAdded = 0;
461 int nPointsRemoved = 0;
462
463 // TODO: closest point is not necessarily current point in path (thinking of seach state drifting)
464 // Find the node closest to the rover's current position to determine what has already been passed.
465 std::vector<geoops::Waypoint>::iterator itClosest = vRefPath.begin();
466 double dMinDistSq = std::numeric_limits<double>::max();
467 for (std::vector<geoops::Waypoint>::iterator itSearch = vRefPath.begin(); itSearch != vRefPath.end(); ++itSearch)
468 {
469 // Get easting and northing coordinates and determine the distance squared.
470 double dx = itSearch->GetUTMCoordinate().dEasting - stCurrentRoverPose.GetUTMCoordinate().dEasting;
471 double dy = itSearch->GetUTMCoordinate().dNorthing - stCurrentRoverPose.GetUTMCoordinate().dNorthing;
472 double dDistSq = dx * dx + dy * dy;
473
474 // If our distance is too small, update the minimum value and closest iterator point.
475 if (dDistSq < dMinDistSq)
476 {
477 dMinDistSq = dDistSq;
478 itClosest = itSearch;
479 }
480 }
481
482 // Delete all points in the path prior to the closest point, as they are behind the rover.
483 if (itClosest != vRefPath.begin())
484 {
485 nPointsRemoved += std::distance(vRefPath.begin(), itClosest);
486 it = vRefPath.erase(vRefPath.begin(), itClosest);
487 }
488
489 LOG_INFO(logging::g_qSharedLogger, "Stuck state path filter removed {} elements: ", nPointsRemoved);
490 nPointsRemoved = 0;
491
492 // If rover is in the obstacle, then path it out first and connect it to previous path
493 double dx = stCurrentRoverPose.GetUTMCoordinate().dEasting - stObstaclePosition.dEasting;
494 double dy = stCurrentRoverPose.GetUTMCoordinate().dNorthing - stObstaclePosition.dNorthing;
495 if (dx * dx + dy * dy <= constants::STUCK_OBSTACLE_RADIUS * constants::STUCK_OBSTACLE_RADIUS)
496 {
497 geoops::UTMCoordinate stFirstNodeOfOriginalPath = vRefPath.front().GetUTMCoordinate();
498
499 // Splice in a new path from rover's current location to outside of the obstacle
500 vSplicePathCoordinates = globals::g_pGeoPlanner->PlanPath(globals::g_pLiDARHandler, stStartCoordinate, stGoalCoordinate);
501 it = vRefPath.insert(vRefPath.begin(), vSplicePathCoordinates.begin(), vSplicePathCoordinates.end());
502 it += vSplicePathCoordinates.size();
503 nPointsAdded += vSplicePathCoordinates.size();
504
505 // Splice in a new path from outside of the obstacle to the end of the previous path
506 stStartCoordinate = (vSplicePathCoordinates.size() >= 2) ? std::prev(vSplicePathCoordinates.end())->GetUTMCoordinate() : stStartCoordinate;
507 vSplicePathCoordinates = globals::g_pGeoPlanner->PlanPath(globals::g_pLiDARHandler, stStartCoordinate, stFirstNodeOfOriginalPath);
508 if (vSplicePathCoordinates.size() >= 3)
509 {
510 it = vRefPath.insert(it, std::next(vSplicePathCoordinates.begin()), std::prev(vSplicePathCoordinates.end()));
511 nPointsAdded += vSplicePathCoordinates.size() - 2;
512 }
513 LOG_INFO(logging::g_qSharedLogger, "Stuck State was within obstacle: {} nodes added, {} nodes removed", nPointsAdded, nPointsRemoved);
514 }
515
516 // Else if rover is not inside obstacle, then just connect it to previous path
517 else
518 {
519 // Splice in a new path from rover's current location to the end of the previous path
520 stGoalCoordinate = vRefPath.front().GetUTMCoordinate();
521 vSplicePathCoordinates = globals::g_pGeoPlanner->PlanPath(globals::g_pLiDARHandler, stStartCoordinate, stGoalCoordinate);
522 if (vSplicePathCoordinates.size() >= 2)
523 {
524 it = vRefPath.insert(vRefPath.begin(), vSplicePathCoordinates.begin(), std::prev(vSplicePathCoordinates.end()));
525 nPointsAdded += vSplicePathCoordinates.size() - 1;
526 }
527 LOG_INFO(logging::g_qSharedLogger, "Stuck State was not within obstacle: {} nodes added, {} nodes removed", nPointsAdded, nPointsRemoved);
528 }
529
530 // Remove all points that are in stuck zone and re path-plan deleted path segments.
531 SplicePath(vRefPath, stObstaclePosition);
532 // Save path for use in returning state
533 globals::g_pWaypointHandler->StorePath("GeoPlannerPath", vRefPath);
534
535 // Second half of the SearchPatternState spiral is named differently. Don't forget to reroute it too.
536 if (m_eTriggeringState == States::eSearchPattern && !vSearchRevSpiralPath.empty())
537 {
538 // Remove all points that are in stuck zone and re path-plan deleted path segments.
539 SplicePath(vSearchRevSpiralPath, stObstaclePosition);
540 // Save path for use in returning state
541 globals::g_pWaypointHandler->StorePath("GeoPlannerPathReverse", vSearchRevSpiralPath);
542 }
543 }
int GetObstaclesCount()
Accessor for the number of elements on the WaypointHandler's obstacle vector.
Definition WaypointHandler.cpp:721
void StorePath(const std::string &szPathName, const std::vector< geoops::Waypoint > &vWaypointPath)
Store a path in the WaypointHandler.
Definition WaypointHandler.cpp:120
const std::vector< geoops::Waypoint > RetrievePath(const std::string &szPathName)
Retrieve an immutable reference to the path at the given path name/key.
Definition WaypointHandler.cpp:600
const geoops::Waypoint RetrieveObstacleAtIndex(const long unsigned int nIndex)
Retrieve an immutable reference to the obstacle at the given index.
Definition WaypointHandler.cpp:626
std::vector< geoops::Waypoint > PlanPath(LiDARHandler *pLiDARHandler, const geoops::UTMCoordinate &stStart, const geoops::UTMCoordinate &stEnd, double dSearchRadius=3.0, double dMaxSearchTimeSeconds=120.0, double dCorridorPadding=100.0)
Plan an optimal trajectory path from the start UTM to the end UTM coordinate utilizing a 2....
Definition GeoPlanner.cpp:116
void SplicePath(std::vector< geoops::Waypoint > &vPath, const geoops::UTMCoordinate &stObstaclePosition)
Removes all points within stuck area in path and re-path plans all deleted paths segments.
Definition StuckState.cpp:554
This struct is used by the WaypointHandler to provide an easy way to store all pose data about the ro...
Definition GeospatialOperations.hpp:708
const geoops::UTMCoordinate & GetUTMCoordinate() const
Accessor for the geoops::UTMCoordinate member variable.
Definition GeospatialOperations.hpp:508
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SplicePath()

void statemachine::StuckState::SplicePath ( std::vector< geoops::Waypoint > &  vPath,
const geoops::UTMCoordinate &  stObstaclePosition 
)
private

Removes all points within stuck area in path and re-path plans all deleted paths segments.

Parameters
vPath- The path to modify.
stObstaclePosition- The position of the obstacle to splice around.
Author
Sam Nolte (samno.nosp@m.lte0.nosp@m.302@g.nosp@m.mail.nosp@m..com)
Date
2026-05-19
555 {
556 if (vPath.size() < 2)
557 {
558 return;
559 }
560
561 geoops::RoverPose stCurrentRoverPose = globals::g_pStateMachineHandler->SmartRetrieveRoverPose();
562 geoops::UTMCoordinate stStartCoordinate;
563 geoops::UTMCoordinate stGoalCoordinate;
564 std::vector<geoops::Waypoint> vSplicePathCoordinates;
565 std::vector<geoops::Waypoint>::iterator it = vPath.begin();
566
567 int nPointsAdded = 0;
568 int nPointsRemoved = 0;
569
570 bool bLastDeleted = false;
571 while (it != vPath.end())
572 {
573 double dDifferenceX = it->GetUTMCoordinate().dEasting - stObstaclePosition.dEasting;
574 double dDifferenceY = it->GetUTMCoordinate().dNorthing - stObstaclePosition.dNorthing;
575
576 // If path coord is inside stuck zone, then remove it.
577 // Make sure not to delete the last point in the path, as it is the final goal.
578 if (it != std::prev(vPath.end()) &&
579 dDifferenceX * dDifferenceX + dDifferenceY * dDifferenceY <= constants::STUCK_OBSTACLE_RADIUS * constants::STUCK_OBSTACLE_RADIUS)
580 {
581 bLastDeleted = true;
582 it = vPath.erase(it);
583 ++nPointsRemoved;
584 }
585 // If we are back outside the stuck zone, and the previous node was deleted, then connect the dots correctly by splicing a new path in between.
586 else if (bLastDeleted)
587 {
588 // Plan a new path to the next remaining path node.
589 // If we are at the beginning of the path, then use the rover's current position as the start coordinate.
590 stStartCoordinate = (it != vPath.begin()) ? std::prev(it)->GetUTMCoordinate() : stCurrentRoverPose.GetUTMCoordinate();
591 stGoalCoordinate = it->GetUTMCoordinate();
592 vSplicePathCoordinates = globals::g_pGeoPlanner->PlanPath(globals::g_pLiDARHandler, stStartCoordinate, stGoalCoordinate);
593 // Splice in the new path, ignoring the start and goal coordinates since they are already in the path.
594 if (vSplicePathCoordinates.size() >= 3)
595 {
596 it = vPath.insert(it, std::next(vSplicePathCoordinates.begin()), std::prev(vSplicePathCoordinates.end()));
597 // Skip over the newly inserted nodes.
598 it += vSplicePathCoordinates.size() - 2;
599 nPointsAdded += vSplicePathCoordinates.size() - 2;
600 }
601 bLastDeleted = false;
602 }
603 else
604 {
605 ++it;
606 }
607 }
608
609 LOG_INFO(logging::g_qSharedLogger, "Stuck State Splice modified path: {} nodes added, {} nodes removed", nPointsAdded, nPointsRemoved);
610 }
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_pStateMachineHandler->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
56 // Declare area in front of rover as an obstacle
58 }
void SendStop()
Stop the drivetrain of the Rover.
Definition DriveBoard.cpp:246
statemachine::States GetPreviousState() const
Accessor for the Previous State private member.
Definition StateMachineHandler.cpp:358
void DeclareObstacle()
Adds the area in front of the rover as an obstacle by modifying the area's trav-score in LiDAR data.
Definition StuckState.cpp:385
const geoops::GPSCoordinate & GetGPSCoordinate() const
Accessor for the geoops::GPSCoordinate member variable.
Definition GeospatialOperations.hpp:756
double GetCompassHeading() const
Accessor for the Compass Heading private member.
Definition GeospatialOperations.hpp:787
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.

69 {
70 // Clean up the state before exiting
71 LOG_INFO(logging::g_qSharedLogger, "StuckState: Exiting state.");
72 }
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), Sam Nolte (samno.nosp@m.lte0.nosp@m.302@g.nosp@m.mail.nosp@m..com)
Date
2024-01-17

Implements statemachine::State.

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

291 {
292 // Create instance variables.
293 States eNextState = States::eStuck;
294 bool bCompleteStateExit = true;
295
296 switch (eEvent)
297 {
298 case Event::eStart:
299 {
300 // Submit logger message.
301 LOG_INFO(logging::g_qSharedLogger, "StuckState: Handling Start event.");
302 // Send multimedia command to update state display.
303 globals::g_pMultimediaBoard->SendLightingState(MultimediaBoard::MultimediaBoardLightingState::eAutonomy);
304 break;
305 }
306 case Event::eAbort:
307 {
308 // Submit logger message.
309 LOG_INFO(logging::g_qSharedLogger, "StuckState: Handling Abort event.");
310 // Send multimedia command to update state display.
311 globals::g_pMultimediaBoard->SendLightingState(MultimediaBoard::MultimediaBoardLightingState::eOff);
312 // Change state.
313 eNextState = States::eIdle;
314 break;
315 }
316 case Event::eReverse:
317 {
318 // Submit logger message.
319 LOG_INFO(logging::g_qSharedLogger, "StuckState: Handling Reverse event.");
320 // Change state.
321 eNextState = States::eReversing;
322 break;
323 }
324 case Event::eUnstuck:
325 {
326 // Modify referenced rover path to reflect new obstacle
327 ModifyPath();
328 // Submit logger message.
329 LOG_INFO(logging::g_qSharedLogger, "StuckState: Handling Unstuck event.");
330 // Change state back to the state that originally got stuck.
331 eNextState = m_eTriggeringState;
332 break;
333 }
334 default:
335 {
336 LOG_WARNING(logging::g_qSharedLogger, "StuckState: Handling unknown event.");
337 eNextState = States::eIdle;
338 break;
339 }
340 }
341
342 if (eNextState != States::eStuck)
343 {
344 LOG_INFO(logging::g_qSharedLogger, "StuckState: Transitioning to {} State.", StateToString(eNextState));
345
346 // Exit the current state
347 if (bCompleteStateExit)
348 {
349 Exit();
350 }
351 }
352
353 return eNextState;
354 }
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:68
void ModifyPath()
Modify stored path to reflect new obstacle and store it for use in returning state.
Definition StuckState.cpp:416
std::string StateToString(States eState)
Converts a state object to a string.
Definition State.hpp:85
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: