Autonomous Racing  1
f1tenth Project Group of Technical University Dortmund, Germany
lap_timer.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 import rospy
4 import sys
5 from gazebo_msgs.msg import ModelState, ModelStates
6 from std_msgs.msg import Duration
7 from math import floor
8 
9 from collections import namedtuple
10 
11 Point = namedtuple("Point", ["x", "y"])
12 
13 
14 def format_duration(duration):
15  minutes = int(duration.to_sec() / 60)
16  seconds = int(duration.to_sec()) % 60
17  fraction = duration.to_sec() - floor(duration.to_sec())
18  return str(minutes) + ":" + str(seconds).ljust(2, '0') + \
19  "." + str(int(fraction * 100)).ljust(2, '0')
20 
21 
22 class Area():
23  def __init__(self, center, extents):
24  self.center = center
25  self.extents = extents
26 
27  def contains(self, point):
28  return abs(self.center.x - point.x) < self.extents.x \
29  and abs(self.center.y - point.y) < self.extents.y
30 
31 
32 class Timer():
33  def __init__(self, name, checkpoints):
34  self.name = name
35  self.checkpoints = checkpoints
36  self.next_checkpoint = 0
37  self.history = []
38  self.start = None
39  self.lap_time_publisher = rospy.Publisher(
40  "/lap_time", Duration, queue_size=1)
41 
42  def update(self, position):
43  if self.checkpoints[self.next_checkpoint].contains(position):
44  self.next_checkpoint += 1
45  if self.next_checkpoint == 2:
46  rospy.loginfo("Lap started (" + self.name + ")")
47  self.start = rospy.Time.now()
48  if self.next_checkpoint >= len(self.checkpoints):
49  self.complete_lap()
50  self.next_checkpoint = 2
51  elif self.next_checkpoint > 1 and self.next_checkpoint < len(self.checkpoints) - 1 and self.checkpoints[0].contains(position):
52  self.next_checkpoint = 1
53  elif self.next_checkpoint == 1 and any([area.contains(position) for area in self.checkpoints[2:-2]]):
54  self.next_checkpoint = 0
55 
56  def complete_lap(self):
57  time = rospy.Time.now()
58  duration = time - self.start
59  self.history.append(duration)
60  if len(self.history) == 1:
61  rospy.loginfo("Lap " + str(len(self.history)) + " (" + self.name + "): " + # nopep8
62  format_duration(duration))
63  else:
64  average = rospy.Duration(sum([item.to_sec() for item in self.history]) / len(self.history)) # nopep8
65  rospy.loginfo("Lap " + str(len(self.history)) + " (" + self.name + "): " + # nopep8
66  format_duration(duration) + ", average: " + format_duration(average)) # nopep8
67  self.start = time
68  self.lap_time_publisher.publish(duration)
69 
70 
71 world_name = rospy.get_param('world_name')
72 if world_name not in [
73  'racetrack_decorated',
74  'racetrack_decorated_2',
75  'racetrack_decorated_2_big']:
76  rospy.logfatal('Racetrack not supported by lap_timer.')
77  sys.exit(1)
78 
79 FINISH_LINE_1 = Area(Point(0, -0.5), Point(2.8, 1))
80 FINISH_LINE_2 = Area(Point(4, -0.5), Point(1.2, 1))
81 CHECKPOINT_1 = Area(Point(11, 7), Point(2, 2))
82 CHECKPOINT_2 = Area(Point(0, 4), Point(2, 2))
83 CHECKPOINT_3 = Area(Point(-14, 1), Point(2, 2))
84 
85 if world_name == 'racetrack_decorated_2_big':
86  for area in [
87  FINISH_LINE_1,
88  FINISH_LINE_2,
89  CHECKPOINT_1,
90  CHECKPOINT_2,
91  CHECKPOINT_3]:
92  area.center = Point(area.center.x * 2.5, area.center.y * 2.5)
93  area.extents = Point(area.extents.x * 2.5, area.extents.y * 2.5)
94 
95 forward_track = Timer("forward", (
96  FINISH_LINE_1,
97  FINISH_LINE_2,
98  CHECKPOINT_1,
99  CHECKPOINT_2,
100  CHECKPOINT_3,
101  FINISH_LINE_1,
102  FINISH_LINE_2))
103 
104 reverse_track = Timer("reverse", (
105  FINISH_LINE_2,
106  FINISH_LINE_1,
107  CHECKPOINT_3,
108  CHECKPOINT_2,
109  CHECKPOINT_1,
110  FINISH_LINE_2,
111  FINISH_LINE_1))
112 
113 
114 def model_state_callback(message):
115  if len(message.pose) < 2:
116  return
117 
118  position = Point(message.pose[1].position.x, message.pose[1].position.y)
119  forward_track.update(position)
120  reverse_track.update(position)
121 
122 
123 rospy.init_node('lap_timer', anonymous=True)
124 rospy.Subscriber("/gazebo/model_states", ModelStates, model_state_callback)
125 
126 rospy.spin()
def format_duration(duration)
Definition: lap_timer.py:14
def update(self, position)
Definition: lap_timer.py:42
def model_state_callback(message)
Definition: lap_timer.py:114
def __init__(self, center, extents)
Definition: lap_timer.py:23
def __init__(self, name, checkpoints)
Definition: lap_timer.py:33
def contains(self, point)
Definition: lap_timer.py:27