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 // Get the obstacle's origin
422 int nObstacleIndex = globals::g_pWaypointHandler->GetObstaclesCount();
423 geoops::UTMCoordinate stObstaclePosition = globals::g_pWaypointHandler->RetrieveObstacleAtIndex(nObstacleIndex - 1).GetUTMCoordinate();
424
425 // Get saved rover path
426 std::vector<geoops::Waypoint> vRefPath = globals::g_pWaypointHandler->RetrievePath("stuckPath");
427 std::vector<geoops::Waypoint> vRevSearchRefPath = (m_eTriggeringState == States::eSearchPattern) ? vRefPath : std::vector<geoops::Waypoint>();
428
429 if (vRefPath.empty())
430 {
431 LOG_WARNING(logging::g_qSharedLogger, "Stuck state received empty path to modify!");
432 globals::g_pWaypointHandler->StorePath("unstuckPath", vRefPath);
433 if (m_eTriggeringState == States::eSearchPattern)
434 {
435 globals::g_pWaypointHandler->StorePath("RevSpiralPath", vRevSearchRefPath);
436 }
437 return;
438 }
439
440 // Get the point on the obstacle's border which the rover came from.
441 double dHeadingRad = (90.0 - m_dOriginalHeading) * M_PI / 180.0;
442 if (dHeadingRad < 0)
443 {
444 dHeadingRad += 2 * M_PI;
445 }
446
447 // Grab starting coordinate and goal (edge of obstacle behind rover) coordinate.
448 geoops::UTMCoordinate stStartCoordinate = stCurrentRoverPose.GetUTMCoordinate();
449 geoops::UTMCoordinate stGoalCoordinate = stObstaclePosition;
450
451 // Get goal coordinate easting and northing.
452 stGoalCoordinate.dEasting -= std::cos(dHeadingRad) * constants::STUCK_OBSTACLE_RADIUS;
453 stGoalCoordinate.dNorthing -= std::sin(dHeadingRad) * constants::STUCK_OBSTACLE_RADIUS;
454
455 std::vector<geoops::Waypoint> vSplicePathCoordinates;
456 std::vector<geoops::Waypoint>::iterator it = vRefPath.begin();
457
458 int nPointsAdded = 0;
459 int nPointsRemoved = 0;
460
461 // TODO: closest point is not necessarily current point in path (thinking of seach state drifting)
462 // Find the node closest to the rover's current position to determine what has already been passed.
463 std::vector<geoops::Waypoint>::iterator itClosest = vRefPath.begin();
464 double dMinDistSq = std::numeric_limits<double>::max();
465 for (std::vector<geoops::Waypoint>::iterator itSearch = vRefPath.begin(); itSearch != vRefPath.end(); ++itSearch)
466 {
467 // Get easting and northing coordinates and determine the distance squared.
468 double dx = itSearch->GetUTMCoordinate().dEasting - stCurrentRoverPose.GetUTMCoordinate().dEasting;
469 double dy = itSearch->GetUTMCoordinate().dNorthing - stCurrentRoverPose.GetUTMCoordinate().dNorthing;
470 double dDistSq = dx * dx + dy * dy;
471
472 // If our distance is too small, update the minimum value and closest iterator point.
473 if (dDistSq < dMinDistSq)
474 {
475 dMinDistSq = dDistSq;
476 itClosest = itSearch;
477 }
478 }
479
480 // Delete all points in the path prior to the closest point, as they are behind the rover.
481 if (itClosest != vRefPath.begin())
482 {
483 nPointsRemoved += std::distance(vRefPath.begin(), itClosest);
484 it = vRefPath.erase(vRefPath.begin(), itClosest);
485 }
486
487 LOG_INFO(logging::g_qSharedLogger, "Stuck state path filter removed {} elements: ", nPointsRemoved);
488 nPointsRemoved = 0;
489
490 // If rover is in the obstacle, then path it out first and connect it to previous path
491 double dx = stCurrentRoverPose.GetUTMCoordinate().dEasting - stObstaclePosition.dEasting;
492 double dy = stCurrentRoverPose.GetUTMCoordinate().dNorthing - stObstaclePosition.dNorthing;
493 if (dx * dx + dy * dy <= constants::STUCK_OBSTACLE_RADIUS * constants::STUCK_OBSTACLE_RADIUS)
494 {
495 geoops::UTMCoordinate stFirstNodeOfOriginalPath = vRefPath.front().GetUTMCoordinate();
496
497 // Splice in a new path from rover's current location to outside of the obstacle
498 vSplicePathCoordinates = globals::g_pGeoPlanner->PlanPath(globals::g_pLiDARHandler, stStartCoordinate, stGoalCoordinate);
499 it = vRefPath.insert(vRefPath.begin(), vSplicePathCoordinates.begin(), vSplicePathCoordinates.end());
500 it += vSplicePathCoordinates.size();
501 nPointsAdded += vSplicePathCoordinates.size();
502
503 // Splice in a new path from outside of the obstacle to the end of the previous path
504 stStartCoordinate = (vSplicePathCoordinates.size() >= 2) ? std::prev(vSplicePathCoordinates.end())->GetUTMCoordinate() : stStartCoordinate;
505 vSplicePathCoordinates = globals::g_pGeoPlanner->PlanPath(globals::g_pLiDARHandler, stStartCoordinate, stFirstNodeOfOriginalPath);
506 if (vSplicePathCoordinates.size() >= 3)
507 {
508 it = vRefPath.insert(it, std::next(vSplicePathCoordinates.begin()), std::prev(vSplicePathCoordinates.end()));
509 nPointsAdded += vSplicePathCoordinates.size() - 2;
510 }
511 LOG_INFO(logging::g_qSharedLogger, "Stuck State was within obstacle: {} nodes added, {} nodes removed", nPointsAdded, nPointsRemoved);
512 }
513
514 // Else if rover is not inside obstacle, then just connect it to previous path
515 else
516 {
517 // Splice in a new path from rover's current location to the end of the previous path
518 stGoalCoordinate = vRefPath.front().GetUTMCoordinate();
519 vSplicePathCoordinates = globals::g_pGeoPlanner->PlanPath(globals::g_pLiDARHandler, stStartCoordinate, stGoalCoordinate);
520 if (vSplicePathCoordinates.size() >= 2)
521 {
522 it = vRefPath.insert(vRefPath.begin(), vSplicePathCoordinates.begin(), std::prev(vSplicePathCoordinates.end()));
523 nPointsAdded += vSplicePathCoordinates.size() - 1;
524 }
525 LOG_INFO(logging::g_qSharedLogger, "Stuck State was not within obstacle: {} nodes added, {} nodes removed", nPointsAdded, nPointsRemoved);
526 }
527
528 // Remove all points that are in stuck zone and re path-plan deleted path segments.
529 SplicePath(vRefPath, stObstaclePosition);
530 if (m_eTriggeringState == States::eSearchPattern)
531 {
532 SplicePath(vRevSearchRefPath, stObstaclePosition);
533 }
534
535 // Save path for use in returning state
536 globals::g_pWaypointHandler->StorePath("unstuckPath", vRefPath);
537 if (m_eTriggeringState == States::eSearchPattern)
538 {
539 globals::g_pWaypointHandler->StorePath("RevSpiralPath", vRevSearchRefPath);
540 }
541 }
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:550
Namespace containing functions related to operations on global position number systems and other data...
Definition GeospatialOperations.hpp:33
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.

Author
Sam Nolte (samno.nosp@m.lte0.nosp@m.302@g.nosp@m.mail.nosp@m..com)
Date
2026-05-19
551 {
552 if (vPath.size() < 2)
553 {
554 return;
555 }
556
557 geoops::RoverPose stCurrentRoverPose = globals::g_pStateMachineHandler->SmartRetrieveRoverPose();
558 geoops::UTMCoordinate stStartCoordinate;
559 geoops::UTMCoordinate stGoalCoordinate;
560 std::vector<geoops::Waypoint> vSplicePathCoordinates;
561 std::vector<geoops::Waypoint>::iterator it = vPath.begin();
562
563 int nPointsAdded = 0;
564 int nPointsRemoved = 0;
565
566 bool bLastDeleted = false;
567 while (it != std::prev(vPath.end()))
568 {
569 double dDifferenceX = it->GetUTMCoordinate().dEasting - stObstaclePosition.dEasting;
570 double dDifferenceY = it->GetUTMCoordinate().dNorthing - stObstaclePosition.dNorthing;
571
572 // If path coord is inside stuck zone, then remove it.
573 if (dDifferenceX * dDifferenceX + dDifferenceY * dDifferenceY <= constants::STUCK_OBSTACLE_RADIUS * constants::STUCK_OBSTACLE_RADIUS)
574 {
575 bLastDeleted = true;
576 it = vPath.erase(it);
577 ++nPointsRemoved;
578 }
579 // If the previous node was deleted, then connect the dots correctly by splicing a new path in between.
580 else if (bLastDeleted)
581 {
582 // Plan a new path to the next remaining path node.
583 stStartCoordinate = (it != vPath.begin()) ? std::prev(it)->GetUTMCoordinate() : stCurrentRoverPose.GetUTMCoordinate();
584 stGoalCoordinate = it->GetUTMCoordinate();
585 vSplicePathCoordinates = globals::g_pGeoPlanner->PlanPath(globals::g_pLiDARHandler, stStartCoordinate, stGoalCoordinate);
586 if (vSplicePathCoordinates.size() >= 3)
587 {
588 bLastDeleted = false;
589 it = vPath.insert(it, std::next(vSplicePathCoordinates.begin()), std::prev(vSplicePathCoordinates.end()));
590 it += vSplicePathCoordinates.size() - 1;
591 nPointsAdded += vSplicePathCoordinates.size() - 2;
592 }
593 }
594 else
595 {
596 ++it;
597 }
598 }
599 // If last node is deleted and while loop ends then still connect the path to goal
600 if (bLastDeleted)
601 {
602 // Plan a new path to the next remaining path node
603 stStartCoordinate = std::prev(it)->GetUTMCoordinate();
604 stGoalCoordinate = it->GetUTMCoordinate();
605 vSplicePathCoordinates = globals::g_pGeoPlanner->PlanPath(globals::g_pLiDARHandler, stStartCoordinate, stGoalCoordinate);
606 vPath.insert(it, std::next(vSplicePathCoordinates.begin()), std::prev(vSplicePathCoordinates.end()));
607 nPointsAdded += vSplicePathCoordinates.size() - 2;
608 }
609
610 LOG_INFO(logging::g_qSharedLogger, "Stuck State Splice modified path: {} nodes added, {} nodes removed", nPointsAdded, nPointsRemoved);
611 }
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: