Beispiel #1
0
 def on_pose2d(self, timestamp, data):
     x, y, heading = data
     pose = (x / 1000.0, y / 1000.0, math.radians(heading / 100.0))
     if self.last_position is not None:
         self.is_moving = (self.last_position != pose)
         dist = math.hypot(pose[0] - self.last_position[0], pose[1] - self.last_position[1])
         direction = ((pose[0] - self.last_position[0]) * math.cos(self.last_position[2]) +
                      (pose[1] - self.last_position[1]) * math.sin(self.last_position[2]))
         if direction < 0:
             dist = -dist
     else:
         dist = 0.0
     self.last_position = pose
     if self.start_pose is None:
         self.start_pose = pose
     self.traveled_dist += dist
     x, y, z = self.xyz
     x += math.cos(self.pitch) * math.cos(self.yaw) * dist
     y += math.cos(self.pitch) * math.sin(self.yaw) * dist
     z += math.sin(self.pitch) * dist
     x0, y0, z0 = self.offset
     self.last_send_time = self.bus.publish('pose2d', [round((x + x0) * 1000), round((y + y0) * 1000),
                                 round(math.degrees(self.yaw) * 100)])
     if self.virtual_bumper is not None:
         if self.is_virtual:
             self.virtual_bumper.update_pose(timedelta(seconds=self.sim_time_sec), pose)
         else:
             self.virtual_bumper.update_pose(self.time, pose)
     self.xyz = x, y, z
     self.trace.update_trace(self.xyz)
     # pose3d
     dist3d = quaternion.rotate_vector([dist, 0, 0], self.orientation)
     self.xyz_quat = [a + b for a, b in zip(self.xyz_quat, dist3d)]
     xyz_quat = [p + o for p, o in zip(self.xyz_quat, self.offset)]
     self.bus.publish('pose3d', [xyz_quat, self.orientation])
Beispiel #2
0
    def on_pose2d(self):
        x, y, heading = self.pose2d
        pose = (x / 1000.0, y / 1000.0, math.radians(heading / 100.0))
        if self.last_position is not None:
            dist = math.hypot(pose[0] - self.last_position[0],
                              pose[1] - self.last_position[1])
            direction = ((pose[0] - self.last_position[0]) *
                         math.cos(self.last_position[2]) +
                         (pose[1] - self.last_position[1]) *
                         math.sin(self.last_position[2]))
            if direction < 0:
                dist = -dist
        else:
            dist = 0.0
        self.last_position = pose
        x, y, z = self.xyz
        x += math.cos(self.pitch) * math.cos(self.yaw) * dist
        y += math.cos(self.pitch) * math.sin(self.yaw) * dist
        z += math.sin(self.pitch) * dist
        x0, y0, z0 = self.offset
        self.last_send_time = self.publish('pose2d', [
            round((x + x0) * 1000),
            round((y + y0) * 1000),
            round(math.degrees(self.yaw) * 100)
        ])
        self.xyz = x, y, z

        # pose3d
        if self.orientation is not None:
            dist3d = quaternion.rotate_vector([dist, 0, 0], self.orientation)
            self.xyz_quat = [a + b for a, b in zip(self.xyz_quat, dist3d)]
            self.publish('pose3d', [self.xyz_quat, self.orientation])
Beispiel #3
0
 def on_desired_speed(self, dt, channel, data):
     forward = data[0]/1000.               # from millimeters per second to meters per second
     angular = math.radians(data[1]/100.)  # from centidegrees per second to radians per second
     dtime = 0.1                           # simulation step time in seconds
     max_acc_forward = 1                   # meters per sec**2
     max_acc_angular = 1                   # radians per sec**2
     acc_forward = np.clip(-max_acc_forward, (forward - self.speed_forward)/dtime, max_acc_forward)
     acc_angular = np.clip(-max_acc_angular, (angular - self.speed_angular)/dtime, max_acc_angular)
     self.speed_forward += acc_forward * dtime
     self.speed_angular += acc_angular * dtime
     log("desired", f"forward {forward:.2f} m/s", f"angular {math.degrees(angular):.2f} deg/s")
     log("current", f"forward {self.speed_forward:.2f} m/s", f"angular {math.degrees(self.speed_angular):.2f} deg/s")
     dist = dtime * self.speed_forward
     dist3d = quaternion.rotate_vector([dist, 0, 0], self.orientation)
     self.xyz = [a + b for a, b in zip(self.xyz, dist3d)]
     turn = quaternion.from_axis_angle((0,0,1), dtime * self.speed_angular)
     self.orientation = quaternion.multiply(self.orientation, turn)
     self.time += datetime.timedelta(seconds=dtime)
     heading_centidegrees = round(math.degrees(quaternion.heading(self.orientation))*100)
     x_mm, y_mm, z_mm = [round(c*1000) for c in self.xyz]
     self.bus.publish('orientation', self.orientation)
     self.bus.publish('rot', [heading_centidegrees, 0, 0])
     self.bus.publish('pose2d', [x_mm, y_mm, heading_centidegrees])
     self.bus.publish('pose3d', [[a - b for a, b, in zip(self.xyz, self.origin)], self.orientation])
     self.bus.publish('sim_time_sec', self.time.total_seconds())
     self.bus.publish('scan', self.scan())
Beispiel #4
0
 def pose_callback(self, frame):
     try:
         pose_frame = frame.as_pose_frame()
         profile = pose_frame.get_profile()
         with self.origins_lock:
             try:
                 name = self.origins[profile.unique_id()]
             except KeyError:
                 print(
                     'Pose callback call before registering the stream origin.'
                 )
                 return
         pose = pose_frame.get_pose_data()
         n = frame.get_frame_number()
         if n % self.pose_subsample != 0:
             return
         timestamp = frame.get_timestamp()
     except Exception as e:
         print(e)
         self.finished.set()
         return
     orientation = quaternion_multiply(
         self.tracking_sensor_pitch_quat_inv[name],
         t265_to_osgar_orientation(pose.rotation))
     self.publish(f'{name}_orientation', orientation)
     x, y, z = rotate_vector(t265_to_osgar_position(pose.translation),
                             self.tracking_sensor_yaw_quat[name])
     yaw = quaternion.heading(orientation)
     self.publish(
         f'{name}_pose2d',
         [int(x * 1000),
          int(y * 1000),
          int(math.degrees(yaw) * 100)])
     self.publish(f'{name}_pose3d', [[x, y, z], orientation])
     self.publish(f'{name}_pose_raw', [
         n,
         timestamp,
         [pose.translation.x, pose.translation.y, pose.translation.z],
         [
             pose.rotation.x, pose.rotation.y, pose.rotation.z,
             pose.rotation.w
         ],
         [pose.velocity.x, pose.velocity.y, pose.velocity.z],
         [
             pose.angular_velocity.x, pose.angular_velocity.y,
             pose.angular_velocity.z
         ],
         [pose.acceleration.x, pose.acceleration.y, pose.acceleration.z],
         [
             pose.angular_acceleration.x, pose.angular_acceleration.y,
             pose.angular_acceleration.z
         ],
         [pose.mapper_confidence, pose.tracker_confidence],
     ])  # raw RealSense2 Pose data
Beispiel #5
0
 def pose_callback(self, frame):
     try:
         pose = frame.as_pose_frame().get_pose_data()
         n = frame.get_frame_number()
         if n % self.pose_subsample != 0:
             return
         timestamp = frame.get_timestamp()
     except Exception as e:
         print(e)
         self.finished.set()
         return
     orientation = quaternion_multiply(
         self.tracking_sensor_pitch_quat_inv,
         t265_to_osgar_orientation(pose.rotation))
     self.publish('orientation', orientation)
     x, y, z = rotate_vector(t265_to_osgar_position(pose.translation),
                             self.tracking_sensor_yaw_quat)
     yaw = quaternion.heading(orientation)
     self.publish(
         'pose2d',
         [int(x * 1000),
          int(y * 1000),
          int(math.degrees(yaw) * 100)])
     self.publish('pose3d', [[x, y, z], orientation])
     self.publish('pose_raw', [
         n,
         timestamp,
         [pose.translation.x, pose.translation.y, pose.translation.z],
         [
             pose.rotation.x, pose.rotation.y, pose.rotation.z,
             pose.rotation.w
         ],
         [pose.velocity.x, pose.velocity.y, pose.velocity.z],
         [
             pose.angular_velocity.x, pose.angular_velocity.y,
             pose.angular_velocity.z
         ],
         [pose.acceleration.x, pose.acceleration.y, pose.acceleration.z],
         [
             pose.angular_acceleration.x, pose.angular_acceleration.y,
             pose.angular_acceleration.z
         ],
         [pose.mapper_confidence, pose.tracker_confidence],
     ])  # raw RealSense2 Pose data
Beispiel #6
0
    def on_odom(self, pose2d):
        x, y, heading = pose2d
        if self.orientation is None:
            return

        odom = Pose2d(x / 1000.0, y / 1000.0, math.radians(heading / 100.0))
        if self.last_odom is not None:
            dist = math.hypot(odom.x - self.last_odom.x, odom.y - self.last_odom.y)
            direction = ((odom.x - self.last_odom.x) * math.cos(self.last_odom.heading) +
                         (odom.y - self.last_odom.y) * math.sin(self.last_odom.heading))
            if direction < 0:
                dist = -dist
        else:
            dist = 0.0

        self.last_odom = odom
        dist3d = quaternion.rotate_vector([dist, 0, 0], self.orientation)
        self.xyz = [a + b for a, b in zip(self.xyz, dist3d)]
        self.bus.publish('pose3d', [self.xyz, self.orientation])
Beispiel #7
0
    def update(self):
        packet = self.bus.listen()
        if packet is not None:
            #            print('SubT', packet)
            timestamp, channel, data = packet
            if self.time is None or int(self.time.seconds) // 60 != int(
                    timestamp.seconds) // 60:
                print(timestamp, '(%.1f %.1f %.1f)' % self.xyz,
                      sorted(self.stat.items()))
                print(timestamp,
                      list(('%.1f' % (v / 100)) for v in self.voltage))
                self.stat.clear()

            self.time = timestamp

            if not VIRTUAL_WORLD:
                self.sim_time_sec = self.time.total_seconds()

            self.stat[channel] += 1
            if channel == 'pose2d':
                x, y, heading = data
                pose = (x / 1000.0, y / 1000.0, math.radians(heading / 100.0))
                if self.last_position is not None:
                    self.is_moving = (self.last_position != pose)
                    dist = math.hypot(pose[0] - self.last_position[0],
                                      pose[1] - self.last_position[1])
                    direction = ((pose[0] - self.last_position[0]) *
                                 math.cos(self.last_position[2]) +
                                 (pose[1] - self.last_position[1]) *
                                 math.sin(self.last_position[2]))
                    if direction < 0:
                        dist = -dist
                else:
                    dist = 0.0
                self.last_position = pose
                if self.start_pose is None:
                    self.start_pose = pose
                self.traveled_dist += dist
                x, y, z = self.xyz
                x += math.cos(self.pitch) * math.cos(self.yaw) * dist
                y += math.cos(self.pitch) * math.sin(self.yaw) * dist
                z += math.sin(self.pitch) * dist
                self.bus.publish('pose2d', [
                    round(x * 1000),
                    round(y * 1000),
                    round(math.degrees(self.yaw) * 100)
                ])
                self.xyz = x, y, z
                self.trace.update_trace(self.xyz)
                # pose3d
                dist3d = quaternion.rotate_vector([dist, 0, 0],
                                                  self.orientation)
                self.xyz_quat = [a + b for a, b in zip(self.xyz_quat, dist3d)]
                self.bus.publish('pose3d', [self.xyz_quat, self.orientation])
            elif channel == 'scan':
                self.scan = data
                if self.local_planner is not None:
                    self.local_planner.update(data)
            elif channel == 'rot':
                self.yaw, self.pitch, self.roll = [
                    math.radians(x / 100) for x in data
                ]
            elif channel == 'orientation':
                self.orientation = data
            elif channel == 'sim_time_sec':
                self.sim_time_sec = data
            elif channel == 'acc':
                acc = [x / 1000.0 for x in data]
                gacc = np.matrix([[0., 0.,
                                   9.80]])  # Gravitational acceleration.
                cos_pitch = math.cos(self.pitch)
                sin_pitch = math.sin(self.pitch)
                # TODO: Once roll is correct, incorporate it here too.
                egacc = np.matrix(
                    [  # Expected gravitational acceleration given known pitch.
                        [cos_pitch, 0., sin_pitch], [0., 1., 0.],
                        [-sin_pitch, 0., cos_pitch]
                    ]) * gacc.T
                cacc = np.asarray(
                    acc
                ) - egacc.T  # Corrected acceleration (without gravitational acceleration).
                magnitude = math.hypot(cacc[0, 0], cacc[0, 1])
                if magnitude > 12.0:
                    print(self.time, 'Collision!', acc, 'reported:',
                          self.collision_detector_enabled)
                    if self.collision_detector_enabled:
                        self.collision_detector_enabled = False
                        raise Collision()
            elif channel == 'artf':
                artifact_data, deg_100th, dist_mm = data
                x, y, z = self.xyz
                angle, dist = self.yaw + math.radians(
                    deg_100th / 100.0), dist_mm / 1000.0
                ax = x + math.cos(angle) * dist
                ay = y + math.sin(angle) * dist
                az = z
                self.maybe_remember_artifact(artifact_data, (ax, ay, az))
            elif channel == 'voltage':
                self.voltage = data
            return channel
Beispiel #8
0
    def update(self):
        packet = self.bus.listen()
        if packet is not None:
#            print('SubT', packet)
            timestamp, channel, data = packet
            if self.time is None or int(self.time.seconds)//60 != int(timestamp.seconds)//60:
                print(timestamp, '(%.1f %.1f %.1f)' % self.xyz, sorted(self.stat.items()))
                print(timestamp, list(('%.1f' % (v/100)) for v in self.voltage))
                self.stat.clear()

            self.time = timestamp

            if not VIRTUAL_WORLD:
                self.sim_time_sec = self.time.total_seconds()

            self.stat[channel] += 1
            if channel == 'pose2d':
                x, y, heading = data
                pose = (x/1000.0, y/1000.0, math.radians(heading/100.0))
                if self.last_position is not None:
                    self.is_moving = (self.last_position != pose)
                    dist = math.hypot(pose[0] - self.last_position[0], pose[1] - self.last_position[1])
                    direction = ((pose[0] - self.last_position[0]) * math.cos(self.last_position[2]) +
                                 (pose[1] - self.last_position[1]) * math.sin(self.last_position[2]))
                    if direction < 0:
                        dist = -dist
                else:
                    dist = 0.0
                self.last_position = pose
                if self.start_pose is None:
                    self.start_pose = pose
                self.traveled_dist += dist
                x, y, z = self.xyz
                x += math.cos(self.pitch) * math.cos(self.yaw) * dist
                y += math.cos(self.pitch) * math.sin(self.yaw) * dist
                z += math.sin(self.pitch) * dist
                self.bus.publish('pose2d', [round(x*1000), round(y*1000),
                                            round(math.degrees(self.yaw)*100)])
                self.xyz = x, y, z
                self.trace.update_trace(self.xyz)
                # pose3d
                dist3d = quaternion.rotate_vector([dist, 0, 0], self.orientation)
                self.xyz_quat = [a+b for a, b in zip(self.xyz_quat, dist3d)]
                self.bus.publish('pose3d', [self.xyz_quat, self.orientation])
            elif channel == 'scan':
                self.scan = data
                if self.local_planner is not None:
                    self.local_planner.update(data)
            elif channel == 'rot':
                self.yaw, self.pitch, self.roll = [math.radians(x/100) for x in data]
            elif channel == 'orientation':
                self.orientation = data
            elif channel == 'sim_time_sec':
                self.sim_time_sec = data
            elif channel == 'acc':
                acc = [x/1000.0 for x in data]
                gacc = np.matrix([[0., 0., 9.80]])  # Gravitational acceleration.
                cos_pitch = math.cos(self.pitch)
                sin_pitch = math.sin(self.pitch)
                # TODO: Once roll is correct, incorporate it here too.
                egacc = np.matrix([  # Expected gravitational acceleration given known pitch.
                    [ cos_pitch, 0., sin_pitch],
                    [        0., 1., 0.],
                    [-sin_pitch, 0., cos_pitch]
                ]) * gacc.T
                cacc = np.asarray(acc) - egacc.T  # Corrected acceleration (without gravitational acceleration).
                magnitude = math.hypot(cacc[0, 0], cacc[0, 1])
                if magnitude > 12.0:
                    print(self.time, 'Collision!', acc, 'reported:', self.collision_detector_enabled)
                    if self.collision_detector_enabled:
                        self.collision_detector_enabled = False
                        raise Collision()
            elif channel == 'artf':
                artifact_data, deg_100th, dist_mm = data
                x, y, z = self.xyz
                angle, dist = self.yaw + math.radians(deg_100th/100.0), dist_mm/1000.0
                ax = x + math.cos(angle) * dist
                ay = y + math.sin(angle) * dist
                az = z
                self.maybe_remember_artifact(artifact_data, (ax, ay, az))
            elif channel == 'voltage':
                self.voltage = data
            return channel