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

The NavigatingState class implements the Navigating state for the Autonomy State Machine. More...

#include <NavigatingState.h>

Inheritance diagram for statemachine::NavigatingState:
Collaboration diagram for statemachine::NavigatingState:

Public Member Functions

 NavigatingState ()
 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 Attributes

bool m_bFetchNewWaypoint
 
geoops::Waypoint m_stGoalWaypoint
 
int m_nMaxDataPoints
 
std::vector< double > m_vRoverXPosition
 
std::vector< double > m_vRoverYPosition
 
std::array< double, 2 > m_dStuckCheckLastPosition
 
bool m_bInitialized
 
std::vector< TagDetector * > m_vTagDetectors
 
statemachine::TimeIntervalBasedStuckDetector m_StuckDetector
 

Detailed Description

The NavigatingState class implements the Navigating 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

◆ NavigatingState()

statemachine::NavigatingState::NavigatingState ( )

Construct a new State object.

Author
Eli Byrd (edbgk.nosp@m.k@ms.nosp@m.t.edu)
Date
2024-01-17
72 : State(States::eNavigating)
73 {
74 // Submit logger message.
75 LOG_INFO(logging::g_qConsoleLogger, "Entering State: {}", ToString());
76
77 // Initialize member variables.
78 m_bInitialized = false;
79 m_StuckDetector = statemachine::TimeIntervalBasedStuckDetector(constants::STUCK_CHECK_ATTEMPTS,
80 constants::STUCK_CHECK_INTERVAL,
81 constants::STUCK_CHECK_VEL_THRESH,
82 constants::STUCK_CHECK_ROT_THRESH);
83 // Start state.
84 if (!m_bInitialized)
85 {
86 Start();
87 m_bInitialized = true;
88 }
89 }
void Start() override
This method is called when the state is first started. It is used to initialize the state.
Definition NavigatingState.cpp:31
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::NavigatingState::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.

32 {
33 // Schedule the next run of the state's logic
34 LOG_INFO(logging::g_qSharedLogger, "NavigatingState: Scheduling next run of state logic.");
35
36 // Initialize member variables.
37 m_bFetchNewWaypoint = true;
38 m_nMaxDataPoints = 100;
39
40 m_dStuckCheckLastPosition[0] = 0;
41 m_dStuckCheckLastPosition[1] = 0;
42
43 m_vRoverXPosition.reserve(m_nMaxDataPoints);
44 m_vRoverYPosition.reserve(m_nMaxDataPoints);
45
46 m_vTagDetectors = {globals::g_pTagDetectionHandler->GetTagDetector(TagDetectionHandler::TagDetectors::eHeadMainCam),
47 globals::g_pTagDetectionHandler->GetTagDetector(TagDetectionHandler::TagDetectors::eFrameLeftCam),
48 globals::g_pTagDetectionHandler->GetTagDetector(TagDetectionHandler::TagDetectors::eFrameRightCam)};
49 }
TagDetector * GetTagDetector(TagDetectors eDetectorName)
Accessor for TagDetector detectors.
Definition TagDetectionHandler.cpp:197
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Exit()

void statemachine::NavigatingState::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.

60 {
61 // Clean up the state before exiting
62 LOG_INFO(logging::g_qSharedLogger, "NavigatingState: Exiting state.");
63 }

◆ Run()

void statemachine::NavigatingState::Run ( )
overridevirtual

Run the state machine. Returns the next state.

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

Implements statemachine::State.

98 {
99 // Submit logger message.
100 LOG_DEBUG(logging::g_qSharedLogger, "NavigatingState: Running state-specific behavior.");
101
102 /*
103 The overall flow of this state is as follows.
104 1. Navigate to goal waypoint.
105 1. Is there a tag -> MarkerSeen
106 2. Is there an object -> ObjectSeen
107 3. Is there an obstacle -> TBD
108 4. Is the rover stuck -> Stuck
109 */
110
112 /* --- Navigate to goal waypoint --- */
114
115 // Check if we should get a new goal waypoint and that the waypoint handler has one for us.
116 if (m_bFetchNewWaypoint && globals::g_pWaypointHandler->GetWaypointCount() > 0)
117 {
118 // Trigger new waypoint event.
119 globals::g_pStateMachineHandler->HandleEvent(Event::eNewWaypoint, true);
120 return;
121 }
122
123 // Get Current rover pose.
124 geoops::RoverPose stCurrentRoverPose = globals::g_pWaypointHandler->SmartRetrieveRoverPose();
125 // Calculate distance and bearing from goal waypoint.
126 geoops::GeoMeasurement stGoalWaypointMeasurement = geoops::CalculateGeoMeasurement(stCurrentRoverPose.GetUTMCoordinate(), m_stGoalWaypoint.GetUTMCoordinate());
127
128 // Only print out every so often.
129 static bool bAlreadyPrinted = false;
130 if ((std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count() % 5) == 0 && !bAlreadyPrinted)
131 {
132 // Get raw Navboard GPS position.
133 geoops::GPSCoordinate stCurrentGPSPosition = globals::g_pNavigationBoard->GetGPSData();
134 // Calculate error between pose and GPS.
135 geoops::GeoMeasurement stErrorMeasurement = geoops::CalculateGeoMeasurement(stCurrentRoverPose.GetGPSCoordinate(), stCurrentGPSPosition);
136
137 // Assemble the error metrics into a single string. We are going to include the distance and bearing to the goal waypoint and
138 // the error between the rover pose and the GPS position. The rover pose could be from VIO or GNSS fusion, or just GPS.
139 std::string szErrorMetrics =
140 "--------[ Navigating Error Report ]--------\nDistance to Goal Waypoint: " + std::to_string(stGoalWaypointMeasurement.dDistanceMeters) + " meters\n" +
141 "Bearing to Goal Waypoint: " + std::to_string(stGoalWaypointMeasurement.dStartRelativeBearing) + " degrees\n" +
142 "GPS/VIO Position Error (UTM for easy reading):\n" + std::to_string(stErrorMeasurement.dDistanceMeters) + " (distance) " +
143 std::to_string(stErrorMeasurement.dStartRelativeBearing) + " (bearing)";
144 // Submit the error metrics to the logger.
145 LOG_INFO(logging::g_qSharedLogger, "{}", szErrorMetrics);
146
147 // Set toggle.
148 bAlreadyPrinted = true;
149 }
150 else if ((std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count() % 5) != 0 && bAlreadyPrinted)
151 {
152 // Reset toggle.
153 bAlreadyPrinted = false;
154 }
155
156 // Check if we are at the goal waypoint.
157 if (stGoalWaypointMeasurement.dDistanceMeters > constants::NAVIGATING_REACHED_GOAL_RADIUS)
158 {
159 // Calculate drive move/powers.
160 diffdrive::DrivePowers stDriveSpeeds = globals::g_pDriveBoard->CalculateMove(constants::DRIVE_MAX_POWER,
161 stGoalWaypointMeasurement.dStartRelativeBearing,
162 stCurrentRoverPose.GetCompassHeading(),
163 diffdrive::DifferentialControlMethod::eArcadeDrive);
164 // Send drive powers over RoveComm.
165 globals::g_pDriveBoard->SendDrive(stDriveSpeeds);
166 }
167 else
168 {
169 // Stop drive.
170 globals::g_pDriveBoard->SendStop();
171
172 // Check waypoint type.
173 switch (m_stGoalWaypoint.eType)
174 {
175 // Goal waypoint is navigation.
176 case geoops::WaypointType::eNavigationWaypoint:
177 {
178 // We are at the goal, signal event.
179 globals::g_pStateMachineHandler->HandleEvent(Event::eReachedGpsCoordinate, false);
180 break;
181 }
182 // Goal waypoint is marker.
183 case geoops::WaypointType::eTagWaypoint:
184 {
185 // We are at the goal, signal event.
186 globals::g_pStateMachineHandler->HandleEvent(Event::eReachedMarker, false);
187 break;
188 }
189 // Goal waypoint is object.
190 case geoops::WaypointType::eObjectWaypoint:
191 {
192 // We are at the goal, signal event.
193 globals::g_pStateMachineHandler->HandleEvent(Event::eReachedObject, false);
194 break;
195 }
196 // Goal waypoint is object.
197 case geoops::WaypointType::eMalletWaypoint:
198 {
199 // We are at the goal, signal event.
200 globals::g_pStateMachineHandler->HandleEvent(Event::eReachedObject, false);
201 break;
202 }
203 // Goal waypoint is object.
204 case geoops::WaypointType::eWaterBottleWaypoint:
205 {
206 // We are at the goal, signal event.
207 globals::g_pStateMachineHandler->HandleEvent(Event::eReachedObject, false);
208 break;
209 }
210 default: break;
211 }
212 }
213
215 /* --- Detect Tags --- */
217
218 // In order to even care about any tags we see, the goal waypoint needs to be of type MARKER and we need to be within the search radius of the MARKER waypoint.
219 if (m_stGoalWaypoint.eType == geoops::WaypointType::eTagWaypoint && stGoalWaypointMeasurement.dDistanceMeters <= m_stGoalWaypoint.dRadius)
220 {
221 // Get a list of the currently detected tags, and their stats.
222 std::vector<arucotag::ArucoTag> vDetectedArucoTags;
223 std::vector<tensorflowtag::TensorflowTag> vDetectedTensorflowTags;
224 tagdetectutils::LoadDetectedTags(vDetectedArucoTags, vDetectedTensorflowTags, m_vTagDetectors, false);
225
226 // Check if we have detected any tags.
227 if (vDetectedArucoTags.size() || vDetectedTensorflowTags.size())
228 {
229 // Check if any of the tags have a detection counter or confidence greater than the threshold.
230 if (std::any_of(vDetectedArucoTags.begin(),
231 vDetectedArucoTags.end(),
232 [this](arucotag::ArucoTag& stTag)
233 {
234 // If the Tag ID given by the user in the waypoint is less than 0, then we don't care about the ID.
235 if (m_stGoalWaypoint.nID < 0)
236 {
237 return stTag.nHits >= constants::APPROACH_MARKER_DETECT_ATTEMPTS_LIMIT;
238 }
239 else
240 {
241 return (stTag.nID == m_stGoalWaypoint.nID && stTag.nHits >= constants::APPROACH_MARKER_DETECT_ATTEMPTS_LIMIT);
242 }
243 }) ||
244 std::any_of(vDetectedTensorflowTags.begin(),
245 vDetectedTensorflowTags.end(),
246 [](tensorflowtag::TensorflowTag& stTag) { return stTag.dConfidence >= constants::APPROACH_MARKER_TF_CONFIDENCE_THRESHOLD; }))
247 {
248 // Submit logger message.
249 LOG_NOTICE(logging::g_qSharedLogger, "NavigatingState: Marker seen!");
250 // Handle state transition.
251 globals::g_pStateMachineHandler->HandleEvent(Event::eMarkerSeen);
252 return;
253 }
254 }
255 }
256
258 /* --- Detect Objects --- */
260
261 // TODO: Add object detection to SearchPattern state
262
264 /* --- Detect Obstacles --- */
266
267 // TODO: Add obstacle detection to SearchPattern state
268
270 /* --- Check if the rover is stuck --- */
272
273 // Check if stuck.
274 if (m_StuckDetector.CheckIfStuck(globals::g_pWaypointHandler->SmartRetrieveVelocity(), globals::g_pWaypointHandler->SmartRetrieveAngularVelocity()))
275 {
276 // Submit logger message.
277 LOG_NOTICE(logging::g_qSharedLogger, "NavigatingState: Rover has become stuck!");
278 // Handle state transition and save the current search pattern state.
279 globals::g_pStateMachineHandler->HandleEvent(Event::eStuck, true);
280 // Don't execute the rest of the state.
281 return;
282 }
283 }
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 SendStop()
Stop the drivetrain of the Rover.
Definition DriveBoard.cpp:162
void SendDrive(diffdrive::DrivePowers &stDrivePowers)
Sets the left and right drive powers of the drive board.
Definition DriveBoard.cpp:120
geoops::GPSCoordinate GetGPSData()
Accessor for most recent GPS data received from NavBoard.
Definition NavigationBoard.cpp:78
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
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
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:445
void LoadDetectedTags(std::vector< arucotag::ArucoTag > &vDetectedArucoTags, std::vector< tensorflowtag::TensorflowTag > &vDetectedTensorflowTags, const std::vector< TagDetector * > &vTagDetectors, bool bUnique=false)
Aggregates all detected tags from each provided tag detector for both OpenCV and Tensorflow detection...
Definition TagDetectionUtilty.hpp:50
Represents a single ArUco tag. Stores all information about a specific tag detection.
Definition ArucoDetection.hpp:44
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 stores/contains information about a GPS data.
Definition GeospatialOperations.hpp:148
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: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
const geoops::UTMCoordinate & GetUTMCoordinate() const
Accessor for the geoops::UTMCoordinate member variable.
Definition GeospatialOperations.hpp:733
const geoops::UTMCoordinate & GetUTMCoordinate() const
Accessor for the geoops::UTMCoordinate member variable.
Definition GeospatialOperations.hpp:634
Represents a single ArUco tag. Stores all information about a specific tag detection.
Definition TensorflowTagDetection.hpp:43
Here is the call graph for this function:

◆ TriggerEvent()

States statemachine::NavigatingState::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.

295 {
296 // Create instance variables.
297 States eNextState = States::eNavigating;
298 bool bCompleteStateExit = true;
299
300 switch (eEvent)
301 {
302 case Event::eNoWaypoint:
303 {
304 // Submit logger message.
305 LOG_INFO(logging::g_qSharedLogger, "NavigatingState: Handling No Waypoint event.");
306 // Change state.
307 eNextState = States::eIdle;
308 break;
309 }
310 case Event::eReachedGpsCoordinate:
311 {
312 // Submit logger message.
313 LOG_INFO(logging::g_qSharedLogger, "NavigatingState: Handling Reached GPS Coordinate event.");
314 globals::g_pMultimediaBoard->SendLightingState(MultimediaBoard::MultimediaBoardLightingState::eAutonomy);
315 // Change state.
316 eNextState = States::eVerifyingPosition;
317 break;
318 }
319 case Event::eReachedMarker:
320 {
321 // Submit logger message.
322 LOG_INFO(logging::g_qSharedLogger, "NavigatingState: Handling Reached Marker Waypoint event.");
323 // Send multimedia command to update state display.
324 globals::g_pMultimediaBoard->SendLightingState(MultimediaBoard::MultimediaBoardLightingState::eAutonomy);
325 // Change state.
326 eNextState = States::eSearchPattern;
327 break;
328 }
329 case Event::eReachedObject:
330 {
331 // Submit logger message.
332 LOG_INFO(logging::g_qSharedLogger, "NavigatingState: Handling Reached Object Waypoint event.");
333 // Send multimedia command to update state display.
334 globals::g_pMultimediaBoard->SendLightingState(MultimediaBoard::MultimediaBoardLightingState::eAutonomy);
335 // Change state.
336 eNextState = States::eSearchPattern;
337 break;
338 }
339 case Event::eNewWaypoint:
340 {
341 // Check if the next goal waypoint equals the current one.
342 if (m_stGoalWaypoint == globals::g_pWaypointHandler->PeekNextWaypoint())
343 {
344 // Submit logger message.
345 LOG_INFO(logging::g_qSharedLogger, "NavigatingState: Reusing current Waypoint.");
346 }
347 else
348 {
349 // Submit logger message.
350 LOG_INFO(logging::g_qSharedLogger, "NavigatingState: Handling New Waypoint event.");
351 // Get and store new goal waypoint.
352 m_stGoalWaypoint = globals::g_pWaypointHandler->PeekNextWaypoint();
353 }
354
355 // Send multimedia command to update state display.
356 globals::g_pMultimediaBoard->SendLightingState(MultimediaBoard::MultimediaBoardLightingState::eAutonomy);
357 // Set toggle.
358 m_bFetchNewWaypoint = false;
359 break;
360 }
361 case Event::eStart:
362 {
363 // Submit logger message.
364 LOG_INFO(logging::g_qSharedLogger, "NavigatingState: Handling Start event.");
365 // Send multimedia command to update state display.
366 globals::g_pMultimediaBoard->SendLightingState(MultimediaBoard::MultimediaBoardLightingState::eAutonomy);
367 break;
368 }
369 case Event::eAbort:
370 {
371 // Submit logger message.
372 LOG_INFO(logging::g_qSharedLogger, "NavigatingState: Handling Abort event.");
373 // Stop drive.
374 globals::g_pDriveBoard->SendStop();
375 // Send multimedia command to update state display.
376 globals::g_pMultimediaBoard->SendLightingState(MultimediaBoard::MultimediaBoardLightingState::eAutonomy);
377 // Set toggle.
378 m_bFetchNewWaypoint = true;
379 // Change states.
380 eNextState = States::eIdle;
381 break;
382 }
383 case Event::eMarkerSeen:
384 {
385 // Submit logger message.
386 LOG_INFO(logging::g_qSharedLogger, "NavigatingState: Handling MarkerSeen event.");
387 // Change states.
388 eNextState = States::eApproachingMarker;
389 break;
390 }
391 case Event::eObstacleAvoidance:
392 {
393 LOG_INFO(logging::g_qSharedLogger, "NavigatingState: Handling Obstacle Avoidance event.");
394 eNextState = States::eAvoidance;
395 break;
396 }
397 case Event::eReverse:
398 {
399 LOG_INFO(logging::g_qSharedLogger, "NavigatingState: Handling Reverse event.");
400 eNextState = States::eReversing;
401 break;
402 }
403 case Event::eStuck:
404 {
405 LOG_INFO(logging::g_qSharedLogger, "NavigatingState: Handling Stuck event.");
406 eNextState = States::eStuck;
407 break;
408 }
409 default:
410 {
411 LOG_WARNING(logging::g_qSharedLogger, "NavigatingState: Handling unknown event.");
412 eNextState = States::eIdle;
413 break;
414 }
415 }
416
417 if (eNextState != States::eNavigating)
418 {
419 LOG_INFO(logging::g_qSharedLogger, "NavigatingState: Transitioning to {} State.", StateToString(eNextState));
420
421 // Exit the current state
422 if (bCompleteStateExit)
423 {
424 Exit();
425 }
426 }
427
428 return eNextState;
429 }
void SendLightingState(MultimediaBoardLightingState eState)
Sends a predetermined color pattern to board.
Definition MultimediaBoard.cpp:55
const geoops::Waypoint PeekNextWaypoint()
Returns an immutable reference to the geoops::Waypoint struct at the front of the list without removi...
Definition WaypointHandler.cpp:539
void Exit() override
This method is called when the state is exited. It is used to clean up the state.
Definition NavigatingState.cpp:59
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: