Beispiel #1
0
def fly(client: airsim.MultirotorClient, args: argparse.Namespace) -> None:
    initial_pose = client.simGetVehiclePose()
    if args.verbose:
        ff.print_pose(initial_pose, airsim.to_eularian_angles)
        ff.log(client.simGetCameraInfo(camera_name=CAPTURE_CAMERA))

    if args.flush or (args.capture_dir and not args.debug):
        client.simFlushPersistentMarkers()

    camera_poses = []
    for camera in args.trajectory:
        position = convert_uavmvs_to_airsim_position(
            camera.position, translation=args.offset, scaling=args.scale
        )
        orientation = quaternion_orientation_from_eye_to_look_at(position, LOOK_AT_TARGET)
        camera_poses.append(Pose(position, orientation))

    if args.debug:
        camera_positions = [pose.position for pose in camera_poses]
        client.simPlotPoints(camera_positions, Rgba.Blue, is_persistent=True)
        client.simPlotLineStrip(camera_positions, Rgba.Cyan, thickness=2.5, is_persistent=True)

    airsim_record = []

    def do_stuff_at_uavmvs_viewpoint(i, pose):
        nonlocal client, camera_poses, airsim_record
        log_string = f"({i}/{len(camera_poses)})"
        p, q = pose.position, pose.orientation
        if args.debug:
            log_string += f" position = {to_xyz_str(p)}"
            client.simPlotTransforms([pose], scale=100, is_persistent=True)
            # client.simPlotArrows([p], [LOOK_AT_TARGET], Rgba.White, thickness=3.0, duration=10)
        elif args.capture_dir:
            path = f"{args.prefix}pose{args.suffix}_{i:0{len(str(len(camera_poses)))}}.png"
            path = os.path.join(args.capture_dir, path)
            airsim.write_png(path, AirSimImage.get_mono(client, CAPTURE_CAMERA))
            log_string += f' saved image to "{path}"'
            record_line = AirSimRecord.make_line_string(p, q, time_stamp=str(i), image_file=path)
            airsim_record.append(record_line)
        ff.log(log_string)

    if IS_CV_MODE:
        for i, camera_pose in enumerate(camera_poses):
            client.simSetVehiclePose(camera_pose, ignore_collision=True)
            do_stuff_at_uavmvs_viewpoint(i, camera_pose)
            time.sleep(CV_SLEEP_SEC)
    else:
        client.moveToZAsync(z=-10, velocity=VELOCITY).join()  # XXX avoid colliding on take off
        client.hoverAsync().join()
        mean_position_error = 0.0

        for i, camera_pose in enumerate(camera_poses):
            client.moveToPositionAsync(
                *to_xyz_tuple(camera_pose.position),
                velocity=VELOCITY,
                drivetrain=DrivetrainType.MaxDegreeOfFreedom,
                yaw_mode=YawMode(is_rate=False, yaw_or_rate=YAW_N),
            ).join()

            with pose_at_simulation_pause(client) as real_pose:
                # NOTE when we pre-compute the viewpoint's camera orientation, we use the
                # expected drone position, which (should be close, but) is not the actual
                # drone position. Hence, we could experiment with using fake orientation:
                # quaternion_orientation_from_eye_to_look_at(real_pose.position, LOOK_AT_TARGET)
                fake_pose = Pose(real_pose.position, camera_pose.orientation)

                client.simSetVehiclePose(fake_pose, ignore_collision=True)
                client.simContinueForFrames(1)  # NOTE ensures pose change
                do_stuff_at_uavmvs_viewpoint(i, fake_pose)
                client.simSetVehiclePose(real_pose, ignore_collision=True)

                position_error = real_pose.position.distance_to(camera_pose.position)
                mean_position_error += position_error
                ff.log_debug(f"{position_error = }")

        mean_position_error /= len(camera_poses)
        ff.log_debug(f"{mean_position_error = }")

    if airsim_record:
        print_to_file = args.record_path is not None
        file = open(args.record_path, "w") if print_to_file else None
        print(AirSimRecord.make_header_string(), file=(file if print_to_file else sys.stdout))
        for line in airsim_record:
            print(line, file=(file if print_to_file else sys.stdout))
        if print_to_file:
            file.close()
            ff.log_info(f'Saved AirSim record to "{args.record_path}"')
Beispiel #2
0
class Drone(Thread):
    def __init__(self, telemetry: Telemetry):
        super(Drone, self).__init__()
        self.daemon = True
        self._exit = False

        self.telemetry = telemetry
        self.client: Optional[MultirotorClient] = None
        self.connect()

        self.controller = Controller(self.client, self.telemetry)
        self.collision_type = CollisionType.NONE

    def run(self):
        while not self._exit:
            try:
                self._process()
            except BufferError:
                pass
            except KeyboardInterrupt:
                self.shutdown()

    def _process(self):
        self.update_telemetry()

        if self.is_collision():
            self.process_collision()
        elif self.telemetry.collision_mode:
            self.stop_collision()
        else:
            self.controller.check_progress()

        time.sleep(0.1)

    def shutdown(self):
        self._exit = True
        self.client.enableApiControl(False)
        self.client.reset()

    def connect(self):
        self.client = MultirotorClient()
        self.client.confirmConnection()
        self.client.enableApiControl(True)
        self.client.getBarometerData()

    # region TELEMETRY

    def update_telemetry(self):
        multirotor_state = self.client.getMultirotorState()

        self.telemetry.landed_state = multirotor_state.landed_state
        self.telemetry.ned_position = multirotor_state.kinematics_estimated.position
        self.telemetry.linear_velocity = multirotor_state.kinematics_estimated.linear_velocity

        self.telemetry.gps_position = self.client.getGpsData().gnss.geo_point
        self.telemetry.gps_home = self.client.getHomeGeoPoint()

        self.telemetry.quaternion = self.client.simGetVehiclePose().orientation

        self.get_front_camera_image()
        self.get_bottom_camera_image()

    def get_bottom_camera_image(self):
        self.client.simSetCameraOrientation('0',
                                            Quaternionr(0.0, -0.7, 0.0, 0.5))
        bottom_camera_data = self.client.simGetImages([
            airsim.ImageRequest("0",
                                airsim.ImageType.DepthPlanner,
                                pixels_as_float=True)
        ])
        self.telemetry.terrain_collision.process_image(bottom_camera_data[0])

    def get_front_camera_image(self):
        self.client.simSetCameraOrientation('0',
                                            Quaternionr(0.0, 0.0, 0.0, 1.0))
        front_camera_data = self.client.simGetImages([
            airsim.ImageRequest("0",
                                airsim.ImageType.DepthPlanner,
                                pixels_as_float=True)
        ])
        self.telemetry.wall_collision.process_image(front_camera_data[0])

    # endregion

    # region COLLISION

    def is_collision(self):
        collision = (self.telemetry.wall_collision.collision
                     or self.telemetry.terrain_collision.collision)
        return collision

    def process_collision(self):
        wall_collision = self.telemetry.wall_collision.collision
        terrain_collision = self.telemetry.terrain_collision.collision

        if wall_collision:
            if terrain_collision:
                self.wall_collision()
                self.collision_type = CollisionType.BOTH
            else:
                self.wall_collision()
                self.collision_type = CollisionType.WALL
        else:
            if terrain_collision:
                self.terrain_collision()
                self.collision_type = CollisionType.TERRAIN
            else:
                self.collision_type = CollisionType.NONE

    def wall_collision(self):
        if (self.collision_type != CollisionType.WALL
                and self.collision_type != CollisionType.BOTH):
            self.telemetry.collision_mode = True
            self.client.moveToZAsync(-500, settings.COLLISION_SPEED)

    def terrain_collision(self):
        if self.collision_type != CollisionType.TERRAIN:
            if self.telemetry.ned_position.z_val < -8:
                self.telemetry.collision_mode = True
                target = self.telemetry.target_position
                actual = self.telemetry.ned_position
                self.client.moveToPositionAsync(target.x_val, target.y_val,
                                                actual.z_val - 1,
                                                settings.COLLISION_SPEED)

    def stop_collision(self):
        self.controller.send_position()
        self.telemetry.collision_mode = False