Issue in following recorded track

Hi, I was trying to have amiga follow a straight path of specific length using code from given example “Drive a Square”. I am able to create a new path and start the track_follower service without any errors but there are issues.

Even though the track length is 4m, amiga only moved 3.83 m before stopping for no apparent reason.
The message from the subscriber on track follower status is given below.

image

In the message it reads that remaining distance is 3.75 m when it should be 0.17 m.

This is from one of the runs but the other runs were similar. Every time amiga only moved less than expected, stopped for no reason and remaining distance was way more than it should be.

Help me understand what’s going wrong here and what can I do to fix it.

Hello @priyajakhar ,

Thanks for reaching out with this question!

Collecting some baseline information

There can be a few different things going on here, so we will need a bit more information.

  1. Can you email us at support@farm-ng.com with the name of your brain so we can confirm you are on the latest stable release?
  2. Can you share the code from the modified example you are running when this behavior occurs?
  3. Can you share what the speed settings you are using are? The max speed of controls you are sending (should be part of the example code) and the max speed you have the dashboard constrained to.
  4. How accurate are your RTK-GPS measurements? For example, if you were running this indoors, you would have low accuracy and 0.17m error would not be unexpected. You can check accuracy and carr_soln of your RTK measurements in the GPS app / page.
  5. Is the 0.17m early stop consistent or does the distance change each run? If so, on what range does it change?

Thinking about what can be going on

Reason it stops

There should be more information in the streamed TrackFollowerState than in the screenshot you shared, especially the TrackStatusEnum nested in the TrackFollowerStatus.

This should tell you why the robot stopped following the track.
While the robot is following the track, you should have a stream with TRACK_FOLLOWING. If the track was successfully completed you would see a TRACK_COMPLETE. If something went wrong you should see TRACK_FAILED.

Stopping distance

NOTE: Since you are stopping 0.17 m before the target end, I think this option is unlikely

The track follower should send the signal to stop 5 cm before the end of a track (as long as it does not end in a turn in place). Within typical operating speed ranges (~1 m/s) on hard-packed dirt, this will stop near the target endpoint. If more precise stopping at the end point is required, you can adjust the endpoint based on trial and error for your speed and ground conditions or create logic to send some short goals to bump the robot forward based on where it stops and the current position.

Reversed track?

The image you shared of what is streamed shows you are close to waypoint 3, with a goal index of 12. That sounds like it is towards the beginning of the track, but you said this is near the end. Do the closest_waypoint_index and goal_waypoint_index start at ~42 (the track_size) and decrement down to the end of the track? Do the distance_remaining and duration_remaining start low and increase as the track is followed? The track follower has the ability to follow tracks in either direction, but there could be a small bug in the distance_remaining and duration_remaining calculations. Both should decrease as the track is followed, regardless of direction.

I am looking forward to working through this with you.

– Kyle

Hello @priyajakhar ,

I will document a few of your private responses here that are OK to share, so it may help future users encountering similar issues.

  1. I am not constraining the max speed on the controller
  2. The amiga is being run outdoors, the accuracies are around h=0.014 and v=0.012. carr_soln is 2.
  3. The early stop was somewhat consistent when I ran some recent tests. I am also not running reverse tracks.

OK so that is all good. I looked at the example code you sent me and ran it on one of our robots. It ran successfully, with some tweaks.

sleeping in an async for loop

In your track follower’s stream_status method (based on the stream_track_state method of the Follow a Track | Farm-ng Developers example), you are sleeping inside an async for loop.

    # Stream the track_follower state
    async def stream_status(self) -> None:
        await asyncio.sleep(1.0)
        message: TrackFollowerState
        with open(logfile, "a") as l_file:
            async for _, message in self.clients["track_follower"].subscribe(SubscribeRequest(uri=Uri(path="/state"))):
                l_file.write(str(message))
                print("###################\n", message)
                await asyncio.sleep(1)

This is a very common mistake, but is something you should almost never do (unless you have a very good reason and the sleep is much shorter than the expected loop rate). What is happening here, is the async for is already asynchronously waiting for the next TrackFollowerState message. This releases the event loop to schedule other tasks while it waits for the next message.
By adding await asyncio.sleep(1) in the async for loop, you are causing the loop (and next message to get printed) to get delayed 1 additional second each message, causing a massive backlog for a message streamed at ~20 hz. Because the max queue size on the gRPC stream is large, you are getting a very late TrackFollowerState messages.

Slowing down the state stream

IFF you do want to slow the rate of messages printing, you can use the every_n parameter of the SubscribeRequest proto. In this case, you can set every_n=20 to limit the 20hz message stream to 1hz (though I would recommend a much lower number so you get more fine grained status updates).

See: farm-ng-core/protos/farm_ng/core/event_service.proto at main · farm-ng/farm-ng-core · GitHub

Not looking at message.status

I’d also recommend you look at the status field of the TrackFollowerState messages to monitor what is happening if your robot is stopping early.

If your robot is in fact stopping early, this will tell you why.

Recommended stream_status method

Putting it all together, I’d advocate you change to something more like:

    async def stream_status(self) -> None:
        await asyncio.sleep(1.0)
        message: TrackFollowerState
        with open(logfile, "a") as l_file:
            async for _, message in self.clients["track_follower"].subscribe(SubscribeRequest(uri=Uri(path="/state"), every_n=2)):
                l_file.write(str(message))
                print("###################\n", message.progress)
                print(message.status)

Expected output

The last message before finishing the track and the first at completion should look like:

###################
 track_size: 42
goal_waypoint_index: 41
closest_waypoint_index: 41
distance_total: 4.0000000000000009
distance_remaining: 0.060659848555762945
duration_total: 5
duration_remaining: 0.075824810694703676

track_status: TRACK_FOLLOWING
robot_status {
  controllable: true
}
driving_direction: DIRECTION_FORWARD
waypoint_order: ORDER_STANDARD

###################
 track_size: 42
goal_waypoint_index: 41
closest_waypoint_index: 41
distance_total: 4.0000000000000009
duration_total: 5

track_status: TRACK_COMPLETE
robot_status {
  controllable: true
}
driving_direction: DIRECTION_FORWARD
waypoint_order: ORDER_STANDARD

If it does fail you will see the reason. E.g.,

###################
 track_size: 42
distance_total: 4.0000000000000009
distance_remaining: 7.1767206273288089
duration_total: 5
duration_remaining: 8.97090078416101

track_status: TRACK_FAILED
robot_status {
  failure_modes: FILTER_TIMEOUT
}
driving_direction: DIRECTION_FORWARD
waypoint_order: ORDER_STANDARD

Next steps

I hand measured the final position of the robot and it was consistently stopping between 3.95 & 4.0 meters, unless there was a failure reason.

Please let me know what you see now.

Best,
Kyle

Hi @kylecoble ,

Thank you for your help. That did help solve the problem with not getting accurate information on ‘distance_remaining’.
I ran 2 tests and robot stopped 3.9m and 4m for a track of 4m length.

Hi @priyajakhar ,

That’s great to hear! Please let us know if you encounter any more issues or if the stopping distance is becoming a pain point and we can work on a solution to mitigate that.

Best,
Kyle