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::ApproachingMarkerState Class Reference

The ApproachingMarkerState class implements the Approaching Marker state for the Autonomy State Machine. More...

#include <ApproachingMarkerState.h>

Inheritance diagram for statemachine::ApproachingMarkerState:
Collaboration diagram for statemachine::ApproachingMarkerState:

Public Member Functions

 ApproachingMarkerState ()
 Accessor for the State private member. Returns the state as a string.
 
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.
 

Private 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 Attributes

std::vector< std::shared_ptr< TagDetector > > m_vTagDetectors
 
statemachine::TimeIntervalBasedStuckDetector m_StuckDetector
 
States m_eTriggeringState
 
bool m_bInitialized
 
geoops::Waypoint m_stGoalWaypoint
 
std::unique_ptr< logging::graphing::PathTracerm_pRoverPathPlot
 

Additional Inherited Members

Detailed Description

The ApproachingMarkerState class implements the Approaching Marker state for the Autonomy State Machine.

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

Constructor & Destructor Documentation

◆ ApproachingMarkerState()

statemachine::ApproachingMarkerState::ApproachingMarkerState ( )

Accessor for the State private member. Returns the state as a string.

Returns
std::string - The current state as a string.
Author
Eli Byrd (edbgk.nosp@m.k@ms.nosp@m.t.edu)
Date
2024-01-17
75 : State(States::eApproachingMarker)
76 {
77 LOG_INFO(logging::g_qConsoleLogger, "Entering State: {}", ToString());
78
79 m_bInitialized = false;
80
81 m_StuckDetector = statemachine::TimeIntervalBasedStuckDetector(constants::STUCK_CHECK_ATTEMPTS,
82 constants::STUCK_CHECK_INTERVAL,
83 constants::STUCK_CHECK_VEL_THRESH,
84 constants::STUCK_CHECK_ROT_THRESH);
85 m_pRoverPathPlot = std::make_unique<logging::graphing::PathTracer>("ApproachingMarkerRoverPath");
86
87 if (!m_bInitialized)
88 {
89 Start();
90 m_bInitialized = true;
91 }
92 }
void Start() override
This method is called when the state is first started. It is used to initialize the state.
Definition ApproachingMarkerState.cpp:33
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
This class should be instantiated within another state to be used for detection of if the rover is st...
Definition StuckDetection.hpp:43
Here is the call graph for this function:

Member Function Documentation

◆ Start()

void statemachine::ApproachingMarkerState::Start ( )
overrideprivatevirtual

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, "ApproachingMarkerState: Scheduling next run of state logic.");
37
38 // Initialize member variables.
39 m_stGoalWaypoint = globals::g_pWaypointHandler->PeekNextWaypoint();
40
41 // Store the state that got stuck and triggered a MarkerSeen event.
42 m_eTriggeringState = globals::g_pStateMachineHandler->GetPreviousState();
43
44 // Add the search and rover path layers to the plot.
45 m_pRoverPathPlot->CreateDotLayer("DetectedTags", "blue");
46 m_pRoverPathPlot->CreateDotLayer("FinalTag", "green");
47 m_pRoverPathPlot->CreatePathLayer("RoverPath", "-.r*");
48
49 // Get tag detectors.
50 m_vTagDetectors = {globals::g_pTagDetectionHandler->GetTagDetector(TagDetectionHandler::TagDetectors::eHeadMainCam)};
51 }
statemachine::States GetPreviousState() const
Accessor for the Previous State private member.
Definition StateMachineHandler.cpp:423
std::shared_ptr< TagDetector > GetTagDetector(TagDetectors eDetectorName)
Accessor for TagDetector detectors.
Definition TagDetectionHandler.cpp:132
const geoops::Waypoint PeekNextWaypoint()
Returns an immutable reference to the geoops::Waypoint struct at the front of the list without removi...
Definition WaypointHandler.cpp:540
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Exit()

void statemachine::ApproachingMarkerState::Exit ( )
overrideprivatevirtual

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.

62 {
63 // Clean up the state before exiting
64 LOG_INFO(logging::g_qSharedLogger, "ApproachingMarkerState: Exiting state.");
65 }
Here is the caller graph for this function:

◆ Run()

void statemachine::ApproachingMarkerState::Run ( )
overridevirtual

Run the state machine. Returns the next state.

Author
sam_hajdukiewicz (saman.nosp@m.thah.nosp@m.ajduk.nosp@m.iewi.nosp@m.cz@gm.nosp@m.ail..nosp@m.com)
Date
2024-01-17

Implements statemachine::State.

101 {
102 // Submit logger message.
103 LOG_DEBUG(logging::g_qSharedLogger, "ApproachingMarkerState: Running state-specific behavior.");
104
105 // Get the current rover pose.
106 geoops::RoverPose stCurrentRoverPose = globals::g_pWaypointHandler->SmartRetrieveRoverPose();
107
108 // Add the current rover pose to the path plot.
109 m_pRoverPathPlot->AddPathPoint(stCurrentRoverPose.GetUTMCoordinate(), "RoverPath");
110
111 // Check Rover radius from marker waypoint.
112 geoops::GeoMeasurement stCurrentMeasurement = geoops::CalculateGeoMeasurement(m_stGoalWaypoint.GetGPSCoordinate(), stCurrentRoverPose.GetGPSCoordinate());
113 if (stCurrentMeasurement.dDistanceMeters > m_stGoalWaypoint.dRadius)
114 {
115 // Submit logger message.
116 LOG_WARNING(logging::g_qSharedLogger,
117 "ApproachingMarkerState: Rover is too far from the original waypoint! Waypoint radius is {} meters, current distance is {} meters.",
118 m_stGoalWaypoint.dRadius,
119 stCurrentMeasurement.dDistanceMeters);
120 globals::g_pStateMachineHandler->HandleEvent(Event::eMarkerUnseen);
121 return;
122 }
123
124 // Identify target marker.
125 tagdetectutils::ArucoTag stBestArucoTag, stBestTorchTag;
126 statemachine::IdentifyTargetMarker(m_vTagDetectors, stBestArucoTag, stBestTorchTag, m_stGoalWaypoint.nID);
127
128 // Check if both tag types are unseen.
129 static bool bAlreadyPrintedLost = false;
130 static std::chrono::system_clock::time_point tLastSeenTime = std::chrono::system_clock::now();
131 if (stBestArucoTag.nID == -1 && stBestTorchTag.dConfidence == 0.0)
132 {
133 std::chrono::system_clock::time_point tmCurrentTime = std::chrono::system_clock::now();
134 if ((std::chrono::duration_cast<std::chrono::milliseconds>(tmCurrentTime - tLastSeenTime).count() / 1000.0) > constants::APPROACH_MARKER_LOST_GIVE_UP_TIME)
135 {
136 // Submit logger message.
137 globals::g_pStateMachineHandler->HandleEvent(Event::eMarkerUnseen);
138 return;
139 }
140 else
141 {
142 if (!bAlreadyPrintedLost)
143 {
144 bAlreadyPrintedLost = true;
145 // Submit logger message.
146 LOG_WARNING(logging::g_qSharedLogger, "ApproachingMarkerState: No tags detected.");
147
148 // If either of the tags are good and have a valid geoposition, don't stop the drive, we can keep driving to it.
149 if (stBestArucoTag.nID != -1 && stBestArucoTag.stGeolocatedPosition.eType != geoops::WaypointType::eUNKNOWN)
150 {
151 // Submit logger message.
152 LOG_NOTICE(logging::g_qSharedLogger, "ApproachingMarkerState: OpenCV tag is geolocated.");
153 return;
154 }
155 if (stBestTorchTag.dConfidence != 0.0 && stBestTorchTag.stGeolocatedPosition.eType != geoops::WaypointType::eUNKNOWN)
156 {
157 // Submit logger message.
158 LOG_NOTICE(logging::g_qSharedLogger, "ApproachingMarkerState: Torch tag is geolocated.");
159 return;
160 }
161
162 // Stop the drive.
163 globals::g_pDriveBoard->SendStop();
164 return;
165 }
166 }
167 }
168 else
169 {
170 // Submit logger message.
171 if (bAlreadyPrintedLost)
172 {
173 LOG_NOTICE(logging::g_qSharedLogger, "ApproachingMarkerState: Tags were detected again.");
174 }
175
176 // Reset the last seen time if a tag is detected.
177 tLastSeenTime = std::chrono::system_clock::now();
178 // Reset printed flag when tags are detected again
179 bAlreadyPrintedLost = false;
180 }
181
182 // Create instance variables.
183 static double dHeadingSetPoint = 0.0;
184 static double dDistanceFromTag = 0.0;
185 // Check if we got a good OpenCV tag.
186 if (stBestArucoTag.nID != -1)
187 {
188 dDistanceFromTag = stBestArucoTag.dStraightLineDistance;
189 // Check if the tag has an absolute coordinate populated.
190 if (stBestArucoTag.stGeolocatedPosition.eType != geoops::WaypointType::eUNKNOWN)
191 {
192 // Calculate the geomeasurement to the tag.
193 geoops::GeoMeasurement stTagMeasurement =
194 geoops::CalculateGeoMeasurement(stCurrentRoverPose.GetUTMCoordinate(), stBestArucoTag.stGeolocatedPosition.GetUTMCoordinate());
195 // Update static variables.
196 dHeadingSetPoint = stTagMeasurement.dStartRelativeBearing;
197 // Add the most recent geolocated tag to the plot.
198 m_pRoverPathPlot->AddDot(stBestArucoTag.stGeolocatedPosition.GetUTMCoordinate(), "DetectedTags");
199 }
200 else
201 {
202 dHeadingSetPoint = numops::InputAngleModulus(stBestArucoTag.dYawAngle + stCurrentRoverPose.GetCompassHeading(), 0.0, 360.0);
203 }
204 }
205 // Check if we got a good Torch tag.
206 else if (stBestTorchTag.dConfidence != 0.0)
207 {
208 dDistanceFromTag = stBestTorchTag.dStraightLineDistance;
209 // Check if the tag has an absolute coordinate populated.
210 if (stBestTorchTag.stGeolocatedPosition.eType != geoops::WaypointType::eUNKNOWN)
211 {
212 // Calculate the geomeasurement to the tag.
213 geoops::GeoMeasurement stTagMeasurement =
214 geoops::CalculateGeoMeasurement(stCurrentRoverPose.GetUTMCoordinate(), stBestTorchTag.stGeolocatedPosition.GetUTMCoordinate());
215 // Update static variables.
216 dHeadingSetPoint = stTagMeasurement.dStartRelativeBearing;
217 // Add the most recent geolocated tag to the plot.
218 m_pRoverPathPlot->AddDot(stBestTorchTag.stGeolocatedPosition.GetUTMCoordinate(), "DetectedTags");
219 }
220 else
221 {
222 dHeadingSetPoint = numops::InputAngleModulus(stBestTorchTag.dYawAngle + stCurrentRoverPose.GetCompassHeading(), 0.0, 360.0);
223 }
224 }
225
226 // Move the rover to the target's estimated position.
227 diffdrive::DrivePowers stDrivePowers = globals::g_pDriveBoard->CalculateMove(constants::APPROACH_MARKER_MOTOR_POWER,
228 dHeadingSetPoint,
229 stCurrentRoverPose.GetCompassHeading(),
230 diffdrive::DifferentialControlMethod::eArcadeDrive);
231 globals::g_pDriveBoard->SendDrive(stDrivePowers);
232
233 // Static variable to track last log time.
234 static std::chrono::system_clock::time_point tmLastLogTime = std::chrono::system_clock::now();
235 std::chrono::system_clock::time_point tmCurrentTime = std::chrono::system_clock::now();
236 // Only log once per second.
237 if (std::chrono::duration_cast<std::chrono::seconds>(tmCurrentTime - tmLastLogTime).count() >= 1)
238 {
239 // Update the last log time.
240 tmLastLogTime = tmCurrentTime;
241
242 if (stBestArucoTag.nID != -1)
243 {
244 LOG_NOTICE(logging::g_qSharedLogger,
245 "ApproachingMarkerState: OpenCV Tag ID: {}, Distance: {:.2f} m, Heading: {:.2f} deg",
246 stBestArucoTag.nID,
247 dDistanceFromTag,
248 dHeadingSetPoint);
249 }
250 else if (stBestTorchTag.dConfidence != 0.0)
251 {
252 LOG_NOTICE(logging::g_qSharedLogger,
253 "ApproachingMarkerState: Torch Tag Confidence: {:.2f}, Distance: {:.2f} m, Heading: {:.2f} deg",
254 stBestTorchTag.dConfidence,
255 dDistanceFromTag,
256 dHeadingSetPoint);
257 }
258 }
259
260 // Check if tag is reached.
261 if (dDistanceFromTag != 0.0 && dDistanceFromTag < constants::APPROACH_MARKER_PROXIMITY_THRESHOLD)
262 {
263 // Submit logger message.
264 LOG_NOTICE(logging::g_qSharedLogger, "ApproachingMarkerState: Rover has reached the target marker!");
265 // Check if the OpenCV tag has a good absolute position.
266 if (stBestArucoTag.nID != -1 && stBestArucoTag.stGeolocatedPosition.eType == geoops::WaypointType::eTagWaypoint)
267 {
268 // Add the tag to the path plot.
269 m_pRoverPathPlot->AddDot(stBestArucoTag.stGeolocatedPosition.GetUTMCoordinate(), "FinalTag", 7);
270 }
271 // Check if the torch tag has a good absolute position.
272 if (stBestTorchTag.dConfidence != 0.0 && stBestTorchTag.stGeolocatedPosition.eType == geoops::WaypointType::eTagWaypoint)
273 {
274 // Add the tag to the path plot.
275 m_pRoverPathPlot->AddDot(stBestTorchTag.stGeolocatedPosition.GetUTMCoordinate(), "FinalTag", 7);
276 }
277
278 // Reset the tag heading and distance.
279 dHeadingSetPoint = 0.0;
280 dDistanceFromTag = 0.0;
281
282 // Handle state transition and save the current search pattern state.
283 globals::g_pStateMachineHandler->HandleEvent(Event::eReachedMarker, true);
284 // Don't execute the rest of the state.
285 return;
286 }
287
289 // --- Check if the rover is stuck --- //
291
292 // Check if stuck.
293 if (constants::APPROACH_MARKER_ENABLE_STUCK_DETECT &&
294 m_StuckDetector.CheckIfStuck(globals::g_pWaypointHandler->SmartRetrieveVelocity(), globals::g_pWaypointHandler->SmartRetrieveAngularVelocity()))
295 {
296 // Submit logger message.
297 LOG_NOTICE(logging::g_qSharedLogger, "ApproachingMarkerState: Rover has become stuck!");
298 // Handle state transition and save the current search pattern state.
299 globals::g_pStateMachineHandler->HandleEvent(Event::eStuck, true);
300 // Don't execute the rest of the state.
301 return;
302 }
303
304 return;
305 }
void SendDrive(const diffdrive::DrivePowers &stDrivePowers)
Sets the left and right drive powers of the drive board.
Definition DriveBoard.cpp:117
void SendStop()
Stop the drivetrain of the Rover.
Definition DriveBoard.cpp:163
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.
Definition DriveBoard.cpp:87
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:350
geoops::RoverPose SmartRetrieveRoverPose(bool bVIOHeading=true, bool bVIOTracking=false)
Retrieve the rover's current position and heading. Automatically picks between getting the position/h...
Definition WaypointHandler.cpp:742
bool CheckIfStuck(double dCurrentVelocity, double dCurrentAngularVelocity)
Checks if the rover meets stuck criteria based in the given parameters.
Definition StuckDetection.hpp:105
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:522
constexpr T InputAngleModulus(T tValue, T tMinValue, T tMaxValue)
Calculates the modulus of an input angle.
Definition NumberOperations.hpp:165
int IdentifyTargetMarker(const std::vector< std::shared_ptr< TagDetector > > &vTagDetectors, tagdetectutils::ArucoTag &stArucoTarget, tagdetectutils::ArucoTag &stTorchTarget, const int nTargetTagID=static_cast< int >(manifest::Autonomy::AUTONOMYWAYPOINTTYPES::ANY))
Identify a target marker in the rover's vision, using OpenCV detection.
Definition TagDetectionChecker.hpp:91
This struct is used to store the left and right drive powers for the robot. Storing these values in a...
Definition DifferentialDrive.hpp:73
This struct is used to store the distance, arc length, and relative bearing for a calculated geodesic...
Definition GeospatialOperations.hpp:82
This struct is used by the WaypointHandler to provide an easy way to store all pose data about the ro...
Definition GeospatialOperations.hpp:677
const geoops::GPSCoordinate & GetGPSCoordinate() const
Accessor for the geoops::GPSCoordinate member variable.
Definition GeospatialOperations.hpp:725
double GetCompassHeading() const
Accessor for the Compass Heading private member.
Definition GeospatialOperations.hpp:756
const geoops::UTMCoordinate & GetUTMCoordinate() const
Accessor for the geoops::UTMCoordinate member variable.
Definition GeospatialOperations.hpp:736
const geoops::GPSCoordinate & GetGPSCoordinate() const
Accessor for the geoops::GPSCoordinate member variable.
Definition GeospatialOperations.hpp:466
const geoops::UTMCoordinate & GetUTMCoordinate() const
Accessor for the geoops::UTMCoordinate member variable.
Definition GeospatialOperations.hpp:477
Represents a single ArUco tag. Combines attributes from TorchTag, TensorflowTag, and the original Aru...
Definition TagDetectionUtilty.hpp:59
Here is the call graph for this function:

◆ TriggerEvent()

States statemachine::ApproachingMarkerState::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)
Date
2024-01-17

Implements statemachine::State.

317 {
318 // Create instance variables.
319 States eNextState = States::eApproachingMarker;
320 bool bCompleteStateExit = true;
321
322 switch (eEvent)
323 {
324 case Event::eReachedMarker:
325 {
326 // Submit logger message.
327 LOG_INFO(logging::g_qSharedLogger, "ApproachingMarkerState: Handling ReachedMarker event.");
328
329 // Check if verifying marker state is enabled.
330 if (constants::APPROACH_MARKER_VERIFY_POSITION)
331 {
332 // Change states.
333 eNextState = States::eVerifyingMarker;
334 }
335 else
336 {
337 // Send multimedia command to update state display.
338 globals::g_pMultimediaBoard->SendLightingState(MultimediaBoard::MultimediaBoardLightingState::eReachedGoal);
339 // Pop old waypoint out of queue.
340 globals::g_pWaypointHandler->PopNextWaypoint();
341 // Clear saved search pattern state.
342 globals::g_pStateMachineHandler->ClearSavedStates();
343 // Submit logger message.
344 LOG_NOTICE(logging::g_qSharedLogger, "ApproachingMarkerState: Cleared old search pattern state and approaching marker state from saved states.");
345 // Change state.
346 eNextState = States::eIdle;
347 }
348 break;
349 }
350 case Event::eStart:
351 {
352 // Submit logger message.
353 LOG_INFO(logging::g_qSharedLogger, "ApproachingMarkerState: Handling Start event.");
354 // Send multimedia command to update state display.
355 globals::g_pMultimediaBoard->SendLightingState(MultimediaBoard::MultimediaBoardLightingState::eAutonomy);
356 break;
357 }
358 case Event::eMarkerUnseen:
359 {
360 // Submit logger message.
361 LOG_INFO(logging::g_qSharedLogger, "ApproachingMarkerState: Handling MarkerUnseen event.");
362 // Change states.
363 eNextState = m_eTriggeringState;
364 break;
365 }
366 case Event::eAbort:
367 {
368 // Submit logger message.
369 LOG_INFO(logging::g_qSharedLogger, "ApproachingMarkerState: Handling Abort event.");
370 // Send multimedia command to update state display.
371 globals::g_pMultimediaBoard->SendLightingState(MultimediaBoard::MultimediaBoardLightingState::eOff);
372 // Change state.
373 eNextState = States::eIdle;
374 break;
375 }
376 default:
377 {
378 LOG_WARNING(logging::g_qSharedLogger, "ApproachingMarkerState: Handling unknown event.");
379 eNextState = States::eIdle;
380 break;
381 }
382 }
383
384 if (eNextState != States::eApproachingMarker)
385 {
386 LOG_INFO(logging::g_qSharedLogger, "ApproachingMarkerState: Transitioning to {} State.", StateToString(eNextState));
387
388 // Exit the current state
389 if (bCompleteStateExit)
390 {
391 Exit();
392 }
393 }
394
395 return eNextState;
396 }
void SendLightingState(MultimediaBoardLightingState eState)
Sends a predetermined color pattern to board.
Definition MultimediaBoard.cpp:55
void ClearSavedStates()
Clear all saved states.
Definition StateMachineHandler.cpp:376
geoops::Waypoint PopNextWaypoint()
Removes and returns the next waypoint at the front of the list.
Definition WaypointHandler.cpp:500
void Exit() override
This method is called when the state is exited. It is used to clean up the state.
Definition ApproachingMarkerState.cpp:61
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: