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.
 

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 Member Functions

bool IdentifyTargetArucoMarker (arucotag::ArucoTag &stTarget)
 Identify a target marker in the rover's vision, using OpenCV detection.
 
bool IdentifyTargetTensorflowMarker (tensorflowtag::TensorflowTag &stTarget)
 Identify a target marker in the rover's vision, using Tensorflow detection.
 

Private Attributes

bool m_bInitialized
 
States m_eTriggeringState
 
int m_nNumDetectionAttempts
 
int m_nTargetTagID
 
bool m_bDetected
 
arucotag::ArucoTag m_stTargetTagAR
 
tensorflowtag::TensorflowTag m_stTargetTagTF
 
double m_dLastTargetHeading
 
double m_dLastTargetDistance
 
std::vector< TagDetector * > m_vTagDetectors
 

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 if (!m_bInitialized)
82 {
83 Start();
84 m_bInitialized = true;
85 }
86 }
void Start() override
This method is called when the state is first started. It is used to initialize the state.
Definition ApproachingMarkerState.cpp:32
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
Here is the call graph for this function:

Member Function Documentation

◆ IdentifyTargetArucoMarker()

bool statemachine::ApproachingMarkerState::IdentifyTargetArucoMarker ( arucotag::ArucoTag stTarget)
private

Identify a target marker in the rover's vision, using OpenCV detection.

Note
If multiple markers are detected the closest one will be chosen as the target.
Parameters
tTarget- Reference to store the tag identified as the target.
Returns
true - A target marker was identified.
false - A target marker was not identified.
Author
JSpencerPittman (jspen.nosp@m.cerp.nosp@m.ittma.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2024-02-29
333 {
334 // Load all detected tags in the rover's vision.
335 std::vector<arucotag::ArucoTag> vDetectedArucoTags;
336 std::vector<tensorflowtag::TensorflowTag> vDetectedTensorflowTags;
337 tagdetectutils::LoadDetectedTags(vDetectedArucoTags, vDetectedTensorflowTags, m_vTagDetectors);
338
339 arucotag::ArucoTag stBestTag;
340 stBestTag.dStraightLineDistance = std::numeric_limits<double>::max();
341 stBestTag.nID = -1;
342
343 // Create string to store detected tags in.
344 std::string szIdentifiedTags = "";
345
346 // Select the tag that is the closest to the rover's current position.
347 for (const arucotag::ArucoTag& stCandidate : vDetectedArucoTags)
348 {
349 szIdentifiedTags += "\tID: " + std::to_string(stCandidate.nID) + " Hits: " + std::to_string(stCandidate.nHits) + "\n";
350
351 if (stCandidate.dStraightLineDistance < stBestTag.dStraightLineDistance)
352 {
353 stBestTag = stCandidate;
354 }
355 }
356
357 // A tag was found.
358 if (stBestTag.nID >= 0)
359 {
360 // TODO: Change to a Debug Statement after we confirm it works.
361 LOG_INFO(logging::g_qSharedLogger, "ApproachingMarkerState: Detected Tags: \n{}", szIdentifiedTags);
362 LOG_INFO(logging::g_qSharedLogger, "ApproachingMarkerState: Best Tag: \n\tID: {} Hits: {}", stBestTag.nID, stBestTag.nHits);
363
364 // Save it to the passed in reference.
365 stTarget = stBestTag;
366 return true;
367 }
368 // No target tag was found.
369 else
370 {
371 // TODO: Change to a Debug Statement after we confirm it works.
372 LOG_INFO(logging::g_qSharedLogger, "ApproachingMarkerState: No Tag Detected!");
373 return false;
374 }
375 }
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
Here is the call graph for this function:
Here is the caller graph for this function:

◆ IdentifyTargetTensorflowMarker()

bool statemachine::ApproachingMarkerState::IdentifyTargetTensorflowMarker ( tensorflowtag::TensorflowTag stTarget)
private

Identify a target marker in the rover's vision, using Tensorflow detection.

Note
If multiple markers are detected the closest one will be chosen as the target. Also all tags must have a confidence of at least APPROACH_MARKER_TF_CONFIDENCE_THRESHOLD.
Parameters
tTarget- Reference to store the tag identified as the target.
Returns
true - A target marker was identified.
false - A target marker was not identified.
Author
JSpencerPittman (jspen.nosp@m.cerp.nosp@m.ittma.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2024-02-29
391 {
392 // Load all detected tags in the rover's vision.
393 std::vector<arucotag::ArucoTag> vDetectedArucoTags;
394 std::vector<tensorflowtag::TensorflowTag> vDetectedTensorflowTags;
395 tagdetectutils::LoadDetectedTags(vDetectedArucoTags, vDetectedTensorflowTags, m_vTagDetectors);
396
398 stBestTag.dStraightLineDistance = std::numeric_limits<double>::max();
399 bool bTagIdentified = false;
400 // stBestTag.nID = -1;
401
402 // Select the tag that is the closest to the rover's current position and above the confidence threshold.
403 for (const tensorflowtag::TensorflowTag& stCandidate : vDetectedTensorflowTags)
404 {
405 if (stCandidate.dStraightLineDistance < stBestTag.dStraightLineDistance && stCandidate.dConfidence >= constants::APPROACH_MARKER_TF_CONFIDENCE_THRESHOLD)
406 {
407 stBestTag = stCandidate;
408
409 // Update tag found toggle.
410 bTagIdentified = true;
411 }
412 }
413
414 // Check if a tag has been identified.
415 if (bTagIdentified)
416 {
417 // Save it to the passed in reference.
418 stTarget = stBestTag;
419 }
420
421 return bTagIdentified;
422 }
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:
Here is the caller graph for this function:

◆ Start()

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

33 {
34 // Schedule the next run of the state's logic
35 LOG_INFO(logging::g_qSharedLogger, "ApproachingMarkerState: Scheduling next run of state logic.");
36
37 // Initialize member variables.
38 m_nNumDetectionAttempts = 0;
39 m_nTargetTagID = -1;
40 m_bDetected = false;
41 m_dLastTargetHeading = 0;
42 m_dLastTargetDistance = 0;
43
44 // Store the state that got stuck and triggered a MarkerSeen event.
45 m_eTriggeringState = globals::g_pStateMachineHandler->GetPreviousState();
46
47 // Get tag detectors.
48 m_vTagDetectors = {globals::g_pTagDetectionHandler->GetTagDetector(TagDetectionHandler::TagDetectors::eHeadMainCam),
49 globals::g_pTagDetectionHandler->GetTagDetector(TagDetectionHandler::TagDetectors::eFrameLeftCam),
50 globals::g_pTagDetectionHandler->GetTagDetector(TagDetectionHandler::TagDetectors::eFrameRightCam)};
51 }
statemachine::States GetPreviousState() const
Accessor for the Previous State private member.
Definition StateMachineHandler.cpp:407
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::ApproachingMarkerState::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.

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
Eli Byrd (edbgk.nosp@m.k@ms.nosp@m.t.edu)
Date
2024-01-17

Implements statemachine::State.

95 {
96 // Submit logger message.
97 LOG_DEBUG(logging::g_qSharedLogger, "ApproachingMarkerState: Running state-specific behavior.");
98
99 // Create instance variables.
100 bool bDetectedTagAR = false; // Was the tag detected through OpenCV.
101 bool bDetectedTagTF = false; // Was the tag detected through Tensorflow.
102
103 // Get the current rover pose.
104 geoops::RoverPose stCurrentRoverPose = globals::g_pWaypointHandler->SmartRetrieveRoverPose();
105
106 // If a target hasn't been identified yet attempt to find a target tag in the rover's vision.
107 if (!m_bDetected && m_nNumDetectionAttempts < constants::APPROACH_MARKER_DETECT_ATTEMPTS_LIMIT)
108 {
109 // Attempt to identify the target with OpenCV.
110 // While OpenCV struggles to find tags, the tags it does find are much more reliable compared to TensorFlow.
111 bDetectedTagAR = IdentifyTargetArucoMarker(m_stTargetTagAR);
112 if (bDetectedTagAR)
113 {
114 // Save the identified tag's ID.
115 m_nTargetTagID = m_stTargetTagAR.nID;
116 m_bDetected = true;
117 m_nNumDetectionAttempts = 0;
118 }
119 else
120 {
121 // If OpenCV fails to find the tag rely on the TensorFlow vision algorithms to identify it.
122 bDetectedTagTF = IdentifyTargetTensorflowMarker(m_stTargetTagTF);
123 if (bDetectedTagTF)
124 {
125 // Save the identified tag's ID.
126 // NOTE: Commented this out since TensorflowTag no longer has ID.
127 // m_nTargetTagID = m_stTargetTagTF.nID;
128 m_bDetected = true;
129 m_nNumDetectionAttempts = 0;
130 }
131 }
132
133 // Both OpenCV & TensorFlow failed to identify a target tag.
134 if (!m_bDetected)
135 {
136 ++m_nNumDetectionAttempts;
137 }
138
139 return;
140 }
141 // A target hasn't been identified and the amount of attempts has exceeded the limit.
142 else if (!m_bDetected)
143 {
144 // Abort approaching marker.
145 globals::g_pStateMachineHandler->HandleEvent(Event::eMarkerUnseen);
146 return;
147 }
148
149 // Attempt to find the target marker in OpenCV.
150 bDetectedTagAR = tagdetectutils::FindArucoTagByID(m_nTargetTagID, m_stTargetTagAR, m_vTagDetectors);
151 // LEAD: Commented this out since TensorflowTag no longer has ID.
152 // if (!bDetectedTagAR)
153 // {
154 // // Attempt to find the target marker in TensorFlow.
155 // bDetectedTagTF = tagdetectutils::FindTensorflowTagByID(m_nTargetTagID, m_stTargetTagTF, m_vTagDetectors);
156 // }
157
158 // The target marker wasn't found.
159 if (!bDetectedTagAR && !bDetectedTagTF)
160 {
161 ++m_nNumDetectionAttempts;
162 }
163 // The target marker was found.
164 else
165 {
166 m_nNumDetectionAttempts = 0;
167 }
168
169 // If we have made too many consecutive failed detection attempts
170 // inform the statemachine the marker has been lost.
171 if (m_nNumDetectionAttempts >= constants::APPROACH_MARKER_DETECT_ATTEMPTS_LIMIT)
172 {
173 globals::g_pStateMachineHandler->HandleEvent(Event::eMarkerUnseen);
174 return;
175 }
176
177 // Get the current absolute heading of the rover.
178 double dCurrHeading = stCurrentRoverPose.GetCompassHeading();
179
180 // Find the target's heading and distance with respect to the rover's current position.
181 double dTargetHeading;
182 double dTargetDistance;
183
184 if (bDetectedTagAR)
185 {
186 dTargetHeading = numops::InputAngleModulus<double>(dCurrHeading + m_stTargetTagAR.dYawAngle, 0, 360);
187 dTargetDistance = m_stTargetTagAR.dStraightLineDistance;
188 }
189 else if (bDetectedTagTF)
190 {
191 dTargetHeading = numops::InputAngleModulus<double>(dCurrHeading + m_stTargetTagTF.dYawAngle, 0, 360);
192 dTargetDistance = m_stTargetTagTF.dStraightLineDistance;
193 }
194 // Use the last recorded heading and distance.
195 else
196 {
197 dTargetHeading = m_dLastTargetHeading;
198 dTargetDistance = m_dLastTargetDistance;
199 }
200 // Save the found heading and distance.
201 m_dLastTargetHeading = dTargetHeading;
202 m_dLastTargetDistance = dTargetDistance;
203
204 // Only print out every so often.
205 static bool bAlreadyPrinted = false;
206 if ((std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count() % 5) == 0 && !bAlreadyPrinted)
207 {
208 // Submit logger message.
209 LOG_INFO(logging::g_qSharedLogger,
210 "ApproachingMarkerState: Rover is {} meters from the marker. Minimum Distance is {}.",
211 dTargetDistance,
212 constants::APPROACH_MARKER_PROXIMITY_THRESHOLD);
213 // Set toggle.
214 bAlreadyPrinted = true;
215 }
216 else if ((std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count() % 5) != 0 && bAlreadyPrinted)
217 {
218 // Reset toggle.
219 bAlreadyPrinted = false;
220 }
221
222 // If we are close enough to the target inform the state machine we have reached the marker.
223 if (dTargetDistance < constants::APPROACH_MARKER_PROXIMITY_THRESHOLD)
224 {
225 globals::g_pStateMachineHandler->HandleEvent(Event::eReachedMarker);
226 return;
227 }
228
229 // Move the rover to the target's estimated position.
230 diffdrive::DrivePowers stDrivePowers = globals::g_pDriveBoard->CalculateMove(constants::APPROACH_MARKER_MOTOR_POWER,
231 dTargetHeading,
232 dCurrHeading,
233 diffdrive::DifferentialControlMethod::eArcadeDrive);
234 globals::g_pDriveBoard->SendDrive(stDrivePowers);
235
236 return;
237 }
diffdrive::DrivePowers CalculateMove(const double dGoalSpeed, const double dGoalHeading, const double dActualHeading, const diffdrive::DifferentialControlMethod eKinematicsMethod)
This method determines drive powers to make the Rover drive towards a given heading at a given speed.
Definition DriveBoard.cpp:92
void SendDrive(diffdrive::DrivePowers &stDrivePowers)
Sets the left and right drive powers of the drive board.
Definition DriveBoard.cpp:120
void HandleEvent(statemachine::Event eEvent, const bool bSaveCurrentState=false)
This method Handles Events that are passed to the State Machine Handler. It will check the current st...
Definition StateMachineHandler.cpp:337
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 IdentifyTargetArucoMarker(arucotag::ArucoTag &stTarget)
Identify a target marker in the rover's vision, using OpenCV detection.
Definition ApproachingMarkerState.cpp:332
bool IdentifyTargetTensorflowMarker(tensorflowtag::TensorflowTag &stTarget)
Identify a target marker in the rover's vision, using Tensorflow detection.
Definition ApproachingMarkerState.cpp:390
bool FindArucoTagByID(int nID, arucotag::ArucoTag &stIdentifiedArucoTag, const std::vector< TagDetector * > &vTagDetectors)
Find a tag in the rover's vision with the specified ID, using OpenCV detection.
Definition TagDetectionUtilty.hpp:133
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 by the WaypointHandler to provide an easy way to store all pose data about the ro...
Definition GeospatialOperations.hpp:674
double GetCompassHeading() const
Accessor for the Compass Heading private member.
Definition GeospatialOperations.hpp:743
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.

249 {
250 // Create instance variables.
251 States eNextState = States::eApproachingMarker;
252 bool bCompleteStateExit = true;
253
254 switch (eEvent)
255 {
256 case Event::eReachedMarker:
257 {
258 // Submit logger message.
259 LOG_INFO(logging::g_qSharedLogger, "ApproachingMarkerState: Handling ReachedMarker event.");
260 // Send multimedia command to update state display.
261 globals::g_pMultimediaBoard->SendLightingState(MultimediaBoard::MultimediaBoardLightingState::eReachedGoal);
262 // Pop old waypoint out of queue.
263 globals::g_pWaypointHandler->PopNextWaypoint();
264 // Clear saved search pattern state.
265 globals::g_pStateMachineHandler->ClearSavedState(States::eSearchPattern);
266 // Submit logger message.
267 LOG_NOTICE(logging::g_qSharedLogger, "ApproachingMarkerState: Cleared old search pattern state from saved states.");
268 // Change states.
269 eNextState = States::eIdle;
270 break;
271 }
272 case Event::eStart:
273 {
274 // Submit logger message.
275 LOG_INFO(logging::g_qSharedLogger, "ApproachingMarkerState: Handling Start event.");
276 // Send multimedia command to update state display.
277 globals::g_pMultimediaBoard->SendLightingState(MultimediaBoard::MultimediaBoardLightingState::eAutonomy);
278 break;
279 }
280 case Event::eMarkerUnseen:
281 {
282 // Submit logger message.
283 LOG_INFO(logging::g_qSharedLogger, "ApproachingMarkerState: Handling MarkerUnseen event.");
284 // Change states.
285 eNextState = m_eTriggeringState;
286 break;
287 }
288 case Event::eAbort:
289 {
290 // Submit logger message.
291 LOG_INFO(logging::g_qSharedLogger, "ApproachingMarkerState: Handling Abort event.");
292 // Send multimedia command to update state display.
293 globals::g_pMultimediaBoard->SendLightingState(MultimediaBoard::MultimediaBoardLightingState::eAutonomy);
294 // Change state.
295 eNextState = States::eIdle;
296 break;
297 }
298 default:
299 {
300 LOG_WARNING(logging::g_qSharedLogger, "ApproachingMarkerState: Handling unknown event.");
301 eNextState = States::eIdle;
302 break;
303 }
304 }
305
306 if (eNextState != States::eApproachingMarker)
307 {
308 LOG_INFO(logging::g_qSharedLogger, "ApproachingMarkerState: Transitioning to {} State.", StateToString(eNextState));
309
310 // Exit the current state
311 if (bCompleteStateExit)
312 {
313 Exit();
314 }
315 }
316
317 return eNextState;
318 }
void SendLightingState(MultimediaBoardLightingState eState)
Sends a predetermined color pattern to board.
Definition MultimediaBoard.cpp:55
void ClearSavedState(statemachine::States eState)
Clear a saved state based on the given state.
Definition StateMachineHandler.cpp:378
geoops::Waypoint PopNextWaypoint()
Removes and returns the next waypoint at the front of the list.
Definition WaypointHandler.cpp:499
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: