Beispiel #1
0
def main(args: argparse.Namespace) -> None:
    if args.verbose:
        ff.print_airsim_path(airsim.__path__)

    preflight(args)  # setup
    client = connect(ff.SimMode.ComputerVision)
    try:
        fly(client, args)  # do stuff
    except KeyboardInterrupt:
        client.reset()  # avoid UE4 'fatal error' when exiting with Ctrl+C
    finally:
        ff.log("Done")
Beispiel #2
0
def preflight(args: argparse.Namespace) -> None:
    assert os.path.isfile(
        args.ply_path), f"Invalid file path: '{args.ply_path}'"

    # Parse the point cloud into a pandas dataframe and extract its points
    ply_df = read_ply(args.ply_path)
    if args.verbose:
        ff.log(ply_df)

    args.points = ply_df["points"][["x", "y", "z"]].to_numpy()
    n_of_points, _ = args.points.shape
    print(f"The point cloud has {n_of_points} points.")

    # NOTE avoid plotting all points for large clouds, since Unreal can't handle it
    k = 0 if args.every_k is None else args.every_k
    while not k:
        try:
            k = int(
                input_or_exit(
                    "Do you want to plot one every how many points? "))
        except KeyboardInterrupt:
            exit()
        except:
            k = 0
            print("\nPlease input a valid integer. ", end="")
            continue

        answer = input_or_exit(
            f"This will plot a total of {n_of_points // k} points"
            f" (i.e. one every {k}).\nDo you want to continue? [Y/n] ")
        k = 0 if answer.lower().strip() in ["n", "no"] else k
    args.every_k = k

    # Check if a uavmvs trajectory was passed in and parse it into points
    if args.trajectory_path is not None:
        _, ext = os.path.splitext(args.trajectory_path)
        assert os.path.isfile(args.trajectory_path
                              ), f"Invalid file path: '{args.trajectory_path}'"
        assert ext in parse_uavmvs.keys(
        ), f"Invalid trajectory extension: '{args.trajectory_path}'"

        args.trajectory = parse_uavmvs[ext](args.trajectory_path)
        if args.verbose:
            ff.log(f"The trajectory has {len(args.trajectory)} camera poses")
    else:
        args.trajectory = None

    if args.env_name is not None:
        # the --launch option was passed
        ff.launch_env(*ff.LaunchEnvArgs(args))
        ff.input_or_exit("\nPress [enter] to connect to AirSim ")
Beispiel #3
0
def main(args: argparse.Namespace) -> None:
    if args.verbose:
        ff.print_airsim_path(airsim.__path__)

    assert args.env_name is not None, "missing --launch option"
    ff.launch_env(*ff.LaunchEnvArgs(args))

    if not args.skip_connect:
        ff.input_or_exit("\nPress [enter] to connect to AirSim ")

        client = connect(ff.SimMode.ComputerVision)
        time.sleep(1)
        client.reset()

    ff.log("Done")
Beispiel #4
0
 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)
Beispiel #5
0
def main(args: argparse.Namespace) -> None:
    if args.verbose:
        ff.print_airsim_path(airsim.__path__)

    preflight(args)  # setup
    client = connect(SIM_MODE)
    try:
        fly(client, args)  # do stuff
    except KeyboardInterrupt:
        client.reset()  # avoid UE4 'fatal error' when exiting with Ctrl+C
    finally:
        ff.log("Done\n")
        ff.log_info(f"Used scale = {args.scale} and offset = {args.offset}")
        ff.log_info(f"Used VELOCITY = {VELOCITY}")
        ff.log_info(f"Used SIM_MODE = {SIM_MODE}")
        ff.log_info(f"Used LOOK_AT_TARGET = {to_xyz_str(LOOK_AT_TARGET)}")
        ff.log_info(f"Used CAPTURE_CAMERA = {CAPTURE_CAMERA}")
Beispiel #6
0
def preflight(args: argparse.Namespace) -> None:
    path = args.trajectory_path
    _, ext = os.path.splitext(path)
    assert os.path.isfile(path), path
    assert ext in parse_uavmvs.keys(), path

    args.trajectory = parse_uavmvs[ext](path)
    if args.verbose:
        ff.log(f"The trajectory has {len(args.trajectory)} camera poses")

    if args.capture_dir:
        args.capture_dir = os.path.abspath(args.capture_dir)
        assert os.path.isdir(args.capture_dir), args.capture_dir

    if args.env_name is not None:
        # the --launch option was passed
        ff.launch_env(*ff.LaunchEnvArgs(args))
        ff.input_or_exit("\nPress [enter] to connect to AirSim ")
Beispiel #7
0
def enter_edit_mode(client: airsim.MultirotorClient,
                    points: List[Vector3r]) -> None:
    mode = EditMode.TRANSLATING
    step = 1.0
    total = {
        EditMode.TRANSLATING:
        Vector3r(0, 0, 0),
        # EditMode.ROTATING: Vector3r(0, 0, 0),
        EditMode.SCALING:
        Vector3r(1, 1, 1),
    }
    try:
        while True:
            key = ord(airsim.wait_key())
            if key == 224:  # arrow keys
                arrow_key = ArrowKey(ord(airsim.wait_key()))
                client.simFlushPersistentMarkers()
                if mode == EditMode.TRANSLATING:
                    delta = {
                        ArrowKey.Up: Vector3r(step, 0, 0),
                        ArrowKey.Down: Vector3r(-step, 0, 0),
                        ArrowKey.Left: Vector3r(0, -step, 0),
                        ArrowKey.Right: Vector3r(0, step, 0),
                    }[arrow_key]
                    points = [point + delta for point in points]
                    total[EditMode.TRANSLATING] += delta
                elif mode == EditMode.SCALING:
                    factor = {
                        ArrowKey.Up: 1 + step * 0.1,
                        ArrowKey.Down: 1 - step * 0.1,
                        ArrowKey.Left: 1 - step * 0.1,
                        ArrowKey.Right: 1 + step * 0.1,
                    }[arrow_key]
                    points = [point * factor for point in points]
                    total[EditMode.SCALING] *= factor
                else:
                    assert False  # TODO handle other edit modes for rotating and scaling
                client.simPlotPoints(points,
                                     Rgba.Blue,
                                     POINT_CLOUD_POINT_SIZE,
                                     is_persistent=True)
            elif key == 27:  # esc
                ff.log("TRANSLATING:", total[EditMode.TRANSLATING])
                ff.log("SCALING:", total[EditMode.SCALING])
                return
            else:
                if key == ord(b"["):
                    step /= 2.0
                elif key == ord(b"]"):
                    step *= 2.0
                elif key == ord(b"\t"):
                    mode = EditMode.next(mode)
                ff.log(f"{mode=} {step=}")
    except KeyboardInterrupt:
        return
Beispiel #8
0
def fly(client: MultirotorClient, args: argparse.Namespace) -> None:
    reset(client)

    rect = cast(Rect, args.rect)
    initial_pose = cast(Pose, client.simGetVehiclePose())
    closest_corner = rect.closest_corner(initial_pose.position)

    if args.verbose:
        ff.print_pose(initial_pose, airsim.to_eularian_angles)
        ff.log_info(f"Closest corner {ff.to_xyz_str(closest_corner)}")

    start_pos = Vector3r(
        *ff.to_xyz_tuple(closest_corner))  # NOTE make sure we copy it by value
    start_pos.z_val += args.z_offset
    start_pos.y_val += args.y_offset
    start_pos.x_val += args.x_offset

    plot = Plotter(client)
    plot.flush_persistent()
    plot.points([start_pos], Rgba.Red)

    if args.teleport:
        ff.log(f"Teleporting to {ff.to_xyz_str(start_pos)}...")
        new_pose = Pose(start_pos, initial_pose.orientation)
        Controller.teleport(client, to=new_pose, ignore_collision=True)
    else:
        ff.log(f"Flying to {ff.to_xyz_str(start_pos)}...")
        client.moveToPositionAsync(*ff.to_xyz_tuple(start_pos),
                                   velocity=5).join()

    ff.log("Capturing grid...")
    time.sleep(2)

    z = Vector3r(0, 0, args.altitude_shift)
    path = [
        z + Vector3r(*ff.to_xyz_tuple(corner))
        for corner in rect.zigzag(lanes=args.zigzags)
    ]
    if AUGMENT_PATHS:
        path = Controller.augment_path(path, AUGMENT_PATHS_MAX_DIST)

    plot.points(path, Rgba.White)
    plot.lines(path, Rgba.Green)

    try:
        if RECORD:
            client.startRecording()
        Controller.fly_path(client, path)
    except Exception as e:
        raise e
    finally:
        if RECORD:
            client.stopRecording()
Beispiel #9
0
        *ff.to_xyz_tuple(closest_corner if args.corner else args.roi.center))

    # NOTE AirSim uses NED coordinates, so negative Z values are "up" actually
    if (z := args.z_offset):
        start_pos.z_val -= z  # start higher up, to avoid crashing with objects
    if (y := args.y_offset): start_pos.y_val += y
    if (x := args.x_offset): start_pos.x_val += x

    # Plot a point at the start position and go to it
    if SHOW_PLOTS:
        client.simPlotPoints([start_pos],
                             color_rgba=Rgba.White,
                             is_persistent=True)

    if args.teleport:
        ff.log(f"Teleporting to {ff.to_xyz_str(start_pos)}...")
        # NOTE using `nanQuaternionr` for the orientation should work for `simSetVehiclePose`
        #      not to change it (which is called by `Controller.teleport`)... but it doesn't
        new_pose = Pose(start_pos, initial_pose.orientation)
        Controller.teleport(client, to=new_pose, ignore_collision=True)
    else:
        ff.log(f"Flying to {ff.to_xyz_str(start_pos)}...")
        client.moveToPositionAsync(*ff.to_xyz_tuple(start_pos),
                                   velocity=5,
                                   timeout_sec=12).join()

    # Fly over the region of interest now that we reached the starting position
    ff.log("Flying over zone...")
    time.sleep(2)
    fly_zone(client, args.roi, altitude_shift=args.z_shift)
Beispiel #10
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 #11
0
def fly(client: airsim.MultirotorClient, args: argparse.Namespace) -> None:
    # TODO verify we are in "ComputerVision" mode
    # if (sim_mode := ff.curr_sim_mode()) != ff.SimMode.ComputerVision:
    #     assert False, f"Please change the SimMode from '{sim_mode}' to 'ComputerVision'"

    if args.roi is not None:
        if args.verbose:
            ff.log_info(f"Loading ROI from '{args.roi}'\n")
        with open(args.roi, "r") as f:
            zone = Rect.from_dump(f.read())
    else:
        zone = Rect(Vector3r(), Vector3r(0, 10, 0), Vector3r(10, 0, 0))

    # repeat the first coordinate to close the line strip
    client.simPlotLineStrip(points=zone.corners(repeat_first=True), is_persistent=True)

    # available keys (i.e. not used by AirSim)
    # ,----------------------------------------------------------------------------------------.
    # |  ` |     |     |     |  4  |  5  |  6  |  7  |  8  |  9  |     |  -* |  =  |           |
    # |----------------------------------------------------------------------------------------+
    # |  Tab   |     |     |     |     |     |  Y  |  U  |  I* |  O  |  P  |  [  |  ]  |       |
    # |----------------------------------------------------------------------------------------+
    # |  CpsLck |     |     |     |     |  G  |  H  |  J  |  K*  |  L  |     |  '  |    Enter  |
    # |----------------------------------------------------------------------------------------+
    # |   Shift   |  Z  |  X  |  C  |  V  |     |  N  |     |  ,  |  .  |     |      Shift     |
    # `----------------------------------------------------------------------------------------'
    ff.log("Use [z], [x], [c], [v] to move the region of interest (ROI)")
    ff.log("Press [lshift] to swap editing modes (translating, scaling)")
    ff.log("Press [rshift] to save the current ROI to json")

    edit_mode = EditMode.TRANSLATING

    # define keyboard callbacks
    swap_mode_key = keyboard.Key.shift_l
    save_rect_key = keyboard.Key.shift_r

    def on_press(key):
        nonlocal edit_mode, swap_mode_key, zone

        client.simPrintLogMessage("ROI coordinates: ", message_param=str(zone))

        if key == swap_mode_key:
            edit_mode = EditMode.next(edit_mode, skip_rotation=True)
            client.simPrintLogMessage("Current edit mode: ", message_param=edit_mode.name)

        elif key == save_rect_key:
            filename = save_zone(args.outputdir, zone)
            client.simPrintLogMessage(f"Saved ROI coordinates to '{filename}'")
            if args.verbose:
                ff.log_info(f"Saved ROI coordinates to '{filename}'")

        elif edit_zone(key, edit_mode, zone):
            client.simFlushPersistentMarkers()
            client.simPlotLineStrip(points=zone.corners(repeat_first=True), is_persistent=True)

    def on_release(key):
        if key == keyboard.Key.esc:
            return False  # stop the listener

    # collect events until released
    with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
        ff.log("Press [esc] to quit")
        listener.join()

    if args.clear:
        client.simFlushPersistentMarkers()