scripts/positioning.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 """
3 Use this node to perform indoor zone location using the metraTec IPS tracking system. Prerequisites for using this node
4 is a running receiver-node that handles communication with the receiver and thus with the beacons in the vicinity.
5 Also, make sure that you have defined your zones correctly in the YAML config file.
6 
7 Subscribed topics:
8  - ips/receiver/raw (indoor_positioning/StringStamped):
9  Raw messages received by the UWB receiver
10 
11 Published topics:
12  - ips/receiver/current_zone/name (indoor_positioning/StringStamped):
13  Name of the zone the receiver is currently in
14  - ips/receiver/current_zone/polygon (geometry_msgs/PolygonStamped):
15  Polygon comprising the current zone
16  - ips/receiver/zone_leave (indoor_positioning/StringStamped):
17  Name of the zone that the receiver has left. Is published at the moment a zone-leave occurs
18  - ips/receiver/zone_enter (indoor_positioning/StringStamped):
19  Name of the zone that the receiver has entered. Is published at the moment a zone-enter occurs
20 
21 Parameters:
22  - ~config_file (string, default='PKG_DIR/config/zones.yml'):
23  Path to the configuration file of zones and beacons relative to the package directory
24  - ~rate (double, default=1):
25  The publishing rate in messages per second
26  - ~bcn_len (int, default=2*number_of_beacons):
27  Buffer length for BCN messages
28 """
29 
30 import rospy
31 import os
32 import rospkg
33 from geometry_msgs.msg import PolygonStamped, Point32
34 from indoor_positioning.msg import StringStamped
35 from indoor_positioning.positioning import Positioning
36 
37 
38 class IPS:
39  """Configure ROS node for metraTec IPS indoor positioning system for zone location."""
40  def __init__(self):
41  # subscribe to raw messages from USB stick
42  self.receiver_sub = rospy.Subscriber('ips/receiver/raw', StringStamped, self.callback)
43 
44  # get directory of config file
45  config_dir = rospy.get_param('~config_file') if rospy.has_param('~config_file') else 'config/zones.yml'
46  abs_dir = os.path.join(rospkg.RosPack().get_path('indoor_positioning'), config_dir)
47  # initialize positioning class
48  self.positioning = Positioning(abs_dir)
49  # get number of beacons specified in zones.yml file for default buffer values
50  n_beacons = self.positioning.n_beacons
51 
52  # number of messages to keep
53  self.buffer_length = rospy.get_param('~bcn_len') if rospy.has_param('~bcn_len') else 2*n_beacons
54  self.buffer_length = 2*n_beacons if self.buffer_length == -1 else self.buffer_length
55  # list of incoming messages
56  self.msg_buffer = []
57  # timestamp from last received message
58  self.last_time = None
59 
60  # publishers
61  # current zone name
62  self.zone_name_pub = rospy.Publisher('ips/receiver/current_zone/name', StringStamped, queue_size=1)
63  # polygon of current zone
64  self.zone_polygon_pub = rospy.Publisher('ips/receiver/current_zone/polygon', PolygonStamped, queue_size=1)
65  # zone leave event
66  self.zone_leave_pub = rospy.Publisher('ips/receiver/zone_leave', StringStamped, queue_size=10)
67  # zone enter event
68  self.zone_enter_pub = rospy.Publisher('ips/receiver/zone_enter', StringStamped, queue_size=10)
69  # set publishing rate
70  self.rate = rospy.Rate(rospy.get_param('~rate')) if rospy.has_param('~rate') else rospy.Rate(1)
71 
72  def callback(self, msg):
73  """
74  Append incoming messages to list of previous messages.
75  :param msg: String, message of subscribed topic
76  """
77  # append message to buffer
78  self.msg_buffer.append(msg.data)
79  # save time of last raw signal
80  self.last_time = msg.header.stamp
81  # delete oldest message if buffer is full
82  if len(self.msg_buffer) > self.buffer_length:
83  del(self.msg_buffer[0])
84 
85  def publish(self):
86  """Publish zone information"""
87  # last zone that the receiver was in
88  last_zone = None
89  while not rospy.is_shutdown():
90  # get the current zone
91  zone = self.positioning.get_zone(self.msg_buffer) if self.msg_buffer else None
92  # check if zone change occurred
93  if zone != last_zone:
94  # publish zone change event
95  event = StringStamped()
96  event.header.stamp = self.last_time
97  # only zone leave
98  if zone is None:
99  event.data = last_zone.name
100  self.zone_leave_pub.publish(event)
101  # only zone enter
102  elif last_zone is None:
103  event.data = zone.name
104  self.zone_enter_pub.publish(event)
105  # leave on zone and enter another
106  else:
107  event.data = last_zone.name
108  self.zone_leave_pub.publish(event)
109  event.data = zone.name
110  self.zone_enter_pub.publish(event)
111  if zone is not None:
112  # publish zone name
113  name = StringStamped()
114  name.header.stamp = self.last_time
115  name.header.frame_id = zone.frame_id
116  name.data = zone.name
117  self.zone_name_pub.publish(name)
118  # publish zone polygon
119  polygon = PolygonStamped()
120  polygon.header.stamp = self.last_time
121  polygon.header.frame_id = zone.frame_id
122  points = []
123  for p in zone.polygon:
124  points.append(Point32(p[0], p[1], p[2]))
125  polygon.polygon.points = points
126  self.zone_polygon_pub.publish(polygon)
127  # set current zone to last zone
128  last_zone = zone
129  # wait to start next iteration
130  self.rate.sleep()
131 
132 
133 if __name__ == '__main__':
134  # start node
135  rospy.init_node('positioning', anonymous=False)
136  # initialize IPSReceiver class
137  ips = IPS()
138  try:
139  # publish receiver messages
140  ips.publish()
141  except rospy.ROSInterruptException:
142  pass
def callback(self, msg)


indoor_positioning
Author(s): Christian Arndt
autogenerated on Mon Jun 10 2019 13:33:13