Skip to content
Omega Core edited this page May 19, 2024 · 4 revisions

code found in 'trail.py'

We define the trail as a collection of points the center of the robot has been to. Storing them in a list and displaying them with pygame already starts to look like a trail, but there is an issue. Depending on the speed, points will be further apart and it'll lose it's trail aspect. We can fix this by drawing lines between each 2 consecutive points.

This allows us to set a color and with for each line, but we'll keep the same constants all lines in one trail.

This implementations leads to multiple options to control the trail. You can enter the 'trail mode', in which you can add points to the trail, so you can draw it in real time. This is done with X / A button on the controller. Erasing all points from the trail list can be done with left bumper. Keep in mind, stopping the trail drawing won't automatically erase the trail.

But what if I stop trail drawing, move far away, then start it again?
Clearly we have a problem here. Because our script draws lines between all two consecutive points, It'll draw one across the distance you traveled, which is not what we want in this case. Now we introduce the notion of Trail Segments. Defining a distance threshold between two consecudive points, any bigger distance will result in a different trail segment. Each segment has it's own color and line with, the user could theoretically change them, but no actual implementation has been done yet.

Separate methods for erasing the entire trail or just a specific segment exist, but aren't used that much.


Let's add limitations on these features!

First, add a boolean to check if you need to update the trail or not. If trail drawing is off, the trail stays like that until you either erase it or turn drawing back on:

# snipper from 'trail.py'
def buildTrail(self, pose: Pose):
    if self.constants.FREEZE_TRAIL.compare():
        return 0
    ...

Otherwise, we define a criteria for trail erasing:

  • a maximum point list dimension is introduced, so when getting to the limit, adding a new point means erasing the first point from the list (FIFO concept - First IN First OUT). This gives the user the illusion of a trail following the robot ;
  • the more complicated way of erasing a trail is the static erase. Because consecutive duplicate positions don't add to the list, staying in place wouldn't make the trail longer. We count the number of loops the trail length doesn't change, and after hitting a threshold, the points in the trail will start being deleated ;
# snippet from 'trail.py'
def shouldErasePoint(self, length: int) -> bool:
    if self.constants.ERASE_TRAIL.compare(False):
        return False
        
    if length == self.past_trail_length:
        self.pop_trail_loop += 1
    else: self.pop_trail_loop = 0

    if length == self.constants.MAX_TRAIL_LEN: # length criteria
        return True
    if self.pop_trail_loop >= self.constants.TRAIL_LOOPS: # static criteria
        return True
    
    return False

If we need to erase the last point, we pop the first point from the first segment in the trail. If the segment is empty, get rid of the segment altogether.

# snippet from 'trail.py'
for segment in self.segments: # counts all the points in the trail
    trail_length += len(segment.points)

if self.shouldErasePoint(trail_length):
    if len(self.segments[0].points) == 0:
        self.segments.pop(0)
        self.current_segment -= 1
    self.segments[0].points.pop(0)
    trail_length -= 1

From here, build the trail by the rules briefly mentioned above:

  • don't add duplicate consecutive points ;
  • if the distance between the new point and the last point is bigger than e threhsold, make a new segment ;
# snippet from 'trail.py'
if segment_length == 0:
    self.segments[self.current_segment].points.append((int(pose.x), int(pose.y)))

elif self.segments[self.current_segment].points[-1] != (int(pose.x), int(pose.y)):
    last_point = self.segments[self.current_segment].points[-1]

    if distance(last_point, (int(pose.x), int(pose.y))) > self.constants.DRAW_TRAIL_THRESHOLD:
        self.segments.append(TrailSegment(self.constants))
        self.current_segment += 1

    self.segments[self.current_segment].points.append((int(pose.x), int(pose.y)))

next page →

← previous page