Beispiel #1
0
def create_fleet(config, nav_graph, mock):
    """Create RMF Adapter and FleetUpdateHandle."""
    profile = traits.Profile(
        geometry.make_final_convex_circle(
            config['rmf_fleet']['profile']['radius']))
    robot_traits = traits.VehicleTraits(
        linear=traits.Limits(*config['rmf_fleet']['limits']['linear']),
        angular=traits.Limits(*config['rmf_fleet']['limits']['angular']),
        profile=profile)

    # RMF_CORE Fleet Adapter: Manages delivery or loop requests
    if mock:
        adapter = adpt.MockAdapter(config['node_names']['rmf_fleet_adapter'])
    else:
        adapter = adpt.Adapter.make(config['node_names']['rmf_fleet_adapter'])

    assert adapter, ("Adapter could not be init! "
                     "Ensure a ROS2 scheduler node is running")

    fleet_name = config['rmf_fleet']['name']
    fleet = adapter.add_fleet(fleet_name, robot_traits, nav_graph)

    if delivery_condition is None:
        # Naively accept all delivery requests
        fleet.accept_delivery_requests(lambda x: True)
    else:
        fleet.accept_delivery_requests(delivery_condition)

    return adapter, fleet, fleet_name, profile
def main():
    rclpy.init()
    adpt.init_rclcpp()
    profile = traits.Profile(geometry.make_final_convex_circle(1.0))
    robot_traits = traits.VehicleTraits(linear=traits.Limits(2.5, 1.0),
                                        angular=traits.Limits(2.5, 1.0),
                                        profile=profile)

    print("Test Run Easy Traffic Light")
    path1, path2 = init_graph()

    adapter = adpt.Adapter.make("TestTrafficLightAdapter")

    # Add robot 1
    mock_tl = MockTrafficLightHandle("dummybot1")
    adapter.add_easy_traffic_light(mock_tl.traffic_light_cb, "dummybot_fleet",
                                   mock_tl.name, robot_traits,
                                   mock_tl.pause_cb, mock_tl.resume_cb)

    # Add robot 2
    mock_tl2 = MockTrafficLightHandle("dummybot2")
    adapter.add_easy_traffic_light(mock_tl2.traffic_light_cb, "dummybot_fleet",
                                   mock_tl2.name, robot_traits,
                                   mock_tl2.pause_cb, mock_tl2.resume_cb)

    adapter.start()

    # this is crucial to wait for traffic light to start
    time.sleep(1)

    # inform rmf that the robot is following these path
    mock_tl.pub_follow_path(path1)
    mock_tl2.pub_follow_path(path2)

    # Move robot along the designated path.
    def control_robot(mod, path):
        for cp in range(len(path) - 1):
            if not mod.move_robot(cp):
                print("Error! Robot Failed to move")
                break
            time.sleep(0.2)

    th1 = Thread(target=control_robot, args=(mock_tl, path1))
    th2 = Thread(target=control_robot, args=(mock_tl2, path2))

    th1.start()
    th2.start()
    th1.join()
    th2.join()

    print(f"Sequence of visited waypoints: \n{visited_waypoints}")
    assert visited_waypoints == [
        ("dummybot2", 3), ("dummybot2", 4), ("dummybot1", 2), ("dummybot2", 6),
        ("dummybot1", 3), ("dummybot1", 4), ("dummybot1", 5)
    ], "Sequence of visited waypoints is incorrect."

    print("Done Traffic Light Tutorial!")
    rclpy.shutdown()
Beispiel #3
0
def main():
    # INIT RCL ================================================================
    rclpy.init()
    adpt.init_rclcpp()

    # INIT GRAPH ==============================================================
    map_name = "test_map"
    test_graph = graph.Graph()

    test_graph.add_waypoint(map_name, [0.0, -10.0])  # 0
    test_graph.add_waypoint(map_name, [0.0, -5.0])  # 1
    test_graph.add_waypoint(map_name, [5.0, -5.0]).set_holding_point(True)  # 2
    test_graph.add_waypoint(map_name, [-10.0, 0])  # 3
    test_graph.add_waypoint(map_name, [-5.0, 0.0])  # 4
    test_graph.add_waypoint(map_name, [0.0, 0.0])  # 5
    test_graph.add_waypoint(map_name, [5.0, 0.0])  # 6
    test_graph.add_waypoint(map_name, [10.0, 0.0])  # 7
    test_graph.add_waypoint(map_name, [0.0, 5.0])  # 8
    test_graph.add_waypoint(map_name, [5.0, 5.0]).set_holding_point(True)  # 9
    test_graph.add_waypoint(map_name, [0.0, 10.0])  # 10

    assert test_graph.get_waypoint(2).holding_point
    assert test_graph.get_waypoint(9).holding_point
    assert not test_graph.get_waypoint(10).holding_point
    """
                     10(D)
                      |
                      |
                      8------9
                      |      |
                      |      |
        3------4------5------6------7(D)
                      |      |
                      |      |
                      1------2
                      |
                      |
                      0
   """

    test_graph.add_bidir_lane(0, 1)  # 0   1
    test_graph.add_bidir_lane(1, 2)  # 2   3
    test_graph.add_bidir_lane(1, 5)  # 4   5
    test_graph.add_bidir_lane(2, 6)  # 6   7
    test_graph.add_bidir_lane(3, 4)  # 8   9
    test_graph.add_bidir_lane(4, 5)  # 10 11
    test_graph.add_bidir_lane(5, 6)  # 12 13
    test_graph.add_dock_lane(6, 7, "A")  # 14 15
    test_graph.add_bidir_lane(5, 8)  # 16 17
    test_graph.add_bidir_lane(6, 9)  # 18 19
    test_graph.add_bidir_lane(8, 9)  # 20 21
    test_graph.add_dock_lane(8, 10, "B")  # 22 23

    assert test_graph.num_lanes == 24

    test_graph.add_key(pickup_name, 7)
    test_graph.add_key(dropoff_name, 10)

    assert len(test_graph.keys) == 2 and pickup_name in test_graph.keys \
        and dropoff_name in test_graph.keys

    # INIT FLEET ==============================================================
    profile = traits.Profile(geometry.make_final_convex_circle(1.0))
    robot_traits = traits.VehicleTraits(linear=traits.Limits(0.7, 0.3),
                                        angular=traits.Limits(1.0, 0.45),
                                        profile=profile)

    # Manages delivery or loop requests
    adapter = adpt.MockAdapter("TestDeliveryAdapter")
    fleet = adapter.add_fleet("test_fleet", robot_traits, test_graph)
    fleet.accept_delivery_requests(lambda x: True)

    cmd_node = Node("RobotCommandHandle")

    # Test compute_plan_starts, which tries to place the robot on the navgraph
    # Your robot MUST be near a waypoint or lane for this to work though!
    starts = plan.compute_plan_starts(test_graph, "test_map",
                                      [[-10.0], [0.0], [0.0]], adapter.now())
    assert [x.waypoint for x in starts] == [3], [x.waypoint for x in starts]

    # Alternatively, if you DO know where your robot is, place it directly!
    starts = [plan.Start(adapter.now(), 0, 0.0)]

    # Lambda to insert an adapter
    def updater_inserter(handle_obj, updater):
        handle_obj.updater = updater

    # Manages and executes robot commands
    robot_cmd = MockRobotCommand(cmd_node, test_graph)

    fleet.add_robot(robot_cmd, "T0", profile, starts,
                    partial(updater_inserter, robot_cmd))

    # INIT TASK OBSERVER ======================================================
    at_least_one_incomplete = False
    completed = False

    def task_cb(msg):
        nonlocal at_least_one_incomplete
        nonlocal completed

        if msg.state == TASK_STATE_COMPLETED:
            completed = True
            at_least_one_incomplete = False
        else:
            completed = False
            at_least_one_incomplete = True

    task_node = rclpy.create_node("task_summary_node")
    task_node.create_subscription(TaskSummary, "task_summaries", task_cb, 10)

    # INIT DISPENSERS =========================================================
    quiet_dispenser = MockQuietDispenser(quiet_dispenser_name)
    flaky_dispenser = MockFlakyDispenser(flaky_dispenser_name)

    # FINAL PREP ==============================================================
    rclpy_executor = SingleThreadedExecutor()
    rclpy_executor.add_node(task_node)
    rclpy_executor.add_node(cmd_node)
    rclpy_executor.add_node(quiet_dispenser)
    rclpy_executor.add_node(flaky_dispenser)

    last_quiet_state = False
    last_flaky_state = False

    # GO! =====================================================================
    adapter.start()

    print("# SENDING NEW REQUEST ############################################")
    request = adpt.type.CPPDeliveryMsg("test_delivery", pickup_name,
                                       quiet_dispenser_name, dropoff_name,
                                       flaky_dispenser_name)
    quiet_dispenser.reset()
    flaky_dispenser.reset()
    adapter.request_delivery(request)
    rclpy_executor.spin_once(1)

    for i in range(1000):
        if quiet_dispenser.success_flag != last_quiet_state:
            last_quiet_state = quiet_dispenser.success_flag
            print("== QUIET DISPENSER FLIPPED SUCCESS STATE ==",
                  last_quiet_state)

        if flaky_dispenser.success_flag != last_flaky_state:
            last_flaky_state = flaky_dispenser.success_flag
            print("== FLAKY DISPENSER FLIPPED SUCCESS STATE ==",
                  last_flaky_state)

        if quiet_dispenser.success_flag and flaky_dispenser.success_flag:
            rclpy_executor.spin_once(1)
            break

        rclpy_executor.spin_once(1)
        time.sleep(0.2)

    print("\n== DEBUG TASK REPORT ==")
    print("Visited waypoints:", robot_cmd.visited_waypoints)
    print("At least one incomplete:", at_least_one_incomplete)
    print("Completed:", completed)
    print()

    assert len(robot_cmd.visited_waypoints) == 6
    assert all([x in robot_cmd.visited_waypoints for x in [0, 5, 6, 7, 8, 10]])
    assert robot_cmd.visited_waypoints[0] == 2
    assert robot_cmd.visited_waypoints[5] == 4
    assert robot_cmd.visited_waypoints[6] == 3
    assert robot_cmd.visited_waypoints[7] == 1
    assert robot_cmd.visited_waypoints[8] == 2
    assert robot_cmd.visited_waypoints[10] == 1
    assert at_least_one_incomplete

    # Uncomment this to send a second request.

    # TODO(CH3):
    # But note! The TaskManager has to be fixed first to allow task pre-emption
    # print("# SENDING NEW REQUEST ##########################################")
    # request = adpt.type.CPPDeliveryMsg("test_delivery_two",
    #                                    dropoff_name,
    #                                    flaky_dispenser_name,
    #                                    pickup_name,
    #                                    quiet_dispenser_name)
    # quiet_dispenser.reset()
    # flaky_dispenser.reset()
    # adapter.request_delivery(request)
    # rclpy_executor.spin_once(1)
    #
    # for i in range(1000):
    #     if quiet_dispenser.success_flag != last_quiet_state:
    #         last_quiet_state = quiet_dispenser.success_flag
    #         print("== QUIET DISPENSER FLIPPED SUCCESS STATE ==",
    #               last_quiet_state)
    #
    #     if flaky_dispenser.success_flag != last_flaky_state:
    #         last_flaky_state = flaky_dispenser.success_flag
    #         print("== FLAKY DISPENSER FLIPPED SUCCESS STATE ==",
    #               last_flaky_state)
    #
    #     if quiet_dispenser.success_flag and flaky_dispenser.success_flag:
    #         rclpy_executor.spin_once(1)
    #         break
    #
    #     rclpy_executor.spin_once(1)
    #     time.sleep(0.2)
    #
    # print("\n== DEBUG TASK REPORT ==")
    # print("Visited waypoints:", robot_cmd.visited_waypoints)
    # print("At least one incomplete:", at_least_one_incomplete)
    # print("Completed:", completed)
    # print()

    task_node.destroy_node()
    cmd_node.destroy_node()
    quiet_dispenser.destroy_node()
    flaky_dispenser.destroy_node()

    rclpy_executor.shutdown()
    rclpy.shutdown()
def main():
    # INIT RCL ================================================================
    rclpy.init()

    try:
        adpt.init_rclcpp()
    except RuntimeError:
        # Continue if it is already initialized
        pass

    # INIT GRAPH ==============================================================
    test_graph = graph.Graph()

    test_graph.add_waypoint(map_name, [0.0, -10.0])  # 0
    test_graph.add_waypoint(map_name, [0.0, -5.0])  # 1
    test_graph.add_waypoint(map_name, [5.0, -5.0]).set_holding_point(True)  # 2
    test_graph.add_waypoint(map_name, [-10.0, 0])  # 3
    test_graph.add_waypoint(map_name, [-5.0, 0.0])  # 4
    test_graph.add_waypoint(map_name, [0.0, 0.0])  # 5
    test_graph.add_waypoint(map_name, [5.0, 0.0])  # 6
    test_graph.add_waypoint(map_name, [10.0, 0.0])  # 7
    test_graph.add_waypoint(map_name, [0.0, 5.0])  # 8
    test_graph.add_waypoint(map_name, [5.0, 5.0]).set_holding_point(True)  # 9
    test_graph.add_waypoint(map_name, [0.0, 10.0])  # 10

    assert test_graph.get_waypoint(2).holding_point
    assert test_graph.get_waypoint(9).holding_point
    assert not test_graph.get_waypoint(10).holding_point

    test_graph_legend = \
        """
        D : Dispenser
        I : Ingestor
        H : Holding Point
        K : Dock
        Numerals : Waypoints
        ---- : Lanes
        """

    test_graph_vis = \
        test_graph_legend + \
        """
                         10(I,K)
                          |
                          |
                          8------9(H)
                          |      |
                          |      |
            3------4------5------6------7(D,K)
                          |      |
                          |      |
                          1------2(H)
                          |
                          |
                          0
       """

    test_graph.add_bidir_lane(0, 1)  # 0   1
    test_graph.add_bidir_lane(1, 2)  # 2   3
    test_graph.add_bidir_lane(1, 5)  # 4   5
    test_graph.add_bidir_lane(2, 6)  # 6   7
    test_graph.add_bidir_lane(3, 4)  # 8   9
    test_graph.add_bidir_lane(4, 5)  # 10 11
    test_graph.add_bidir_lane(5, 6)  # 12 13
    test_graph.add_dock_lane(6, 7, "A")  # 14 15
    test_graph.add_bidir_lane(5, 8)  # 16 17
    test_graph.add_bidir_lane(6, 9)  # 18 19
    test_graph.add_bidir_lane(8, 9)  # 20 21
    test_graph.add_dock_lane(8, 10, "B")  # 22 23

    assert test_graph.num_lanes == 24

    test_graph.add_key(pickup_name, 7)
    test_graph.add_key(dropoff_name, 10)

    assert len(test_graph.keys) == 2 and pickup_name in test_graph.keys \
        and dropoff_name in test_graph.keys

    # INIT FLEET ==============================================================
    profile = traits.Profile(geometry.make_final_convex_circle(1.0))
    robot_traits = traits.VehicleTraits(linear=traits.Limits(0.7, 0.3),
                                        angular=traits.Limits(1.0, 0.45),
                                        profile=profile)

    # Manages delivery or loop requests
    adapter = adpt.MockAdapter("TestDeliveryAdapter")
    fleet = adapter.add_fleet(fleet_name, robot_traits, test_graph)

    # Set up task request callback function
    # we will only accept delivery task here
    def task_request_cb(task_profile):
        from rmf_task_msgs.msg import TaskType
        if (task_profile.description.task_type == TaskType.TYPE_DELIVERY):
            return True
        else:
            return False

    fleet.accept_task_requests(task_request_cb)

    # Set fleet battery profile
    battery_sys = battery.BatterySystem.make(24.0, 40.0, 8.8)
    mech_sys = battery.MechanicalSystem.make(70.0, 40.0, 0.22)
    motion_sink = battery.SimpleMotionPowerSink(battery_sys, mech_sys)
    ambient_power_sys = battery.PowerSystem.make(20.0)
    ambient_sink = battery.SimpleDevicePowerSink(battery_sys,
                                                 ambient_power_sys)
    tool_power_sys = battery.PowerSystem.make(10.0)
    tool_sink = battery.SimpleDevicePowerSink(battery_sys, tool_power_sys)

    fleet.set_recharge_threshold(0.2)
    b_success = fleet.set_task_planner_params(battery_sys, motion_sink,
                                              ambient_sink, tool_sink)

    assert b_success, "set battery param failed"

    cmd_node = Node("RobotCommandHandle")

    # Test compute_plan_starts, which tries to place the robot on the navgraph
    # Your robot MUST be near a waypoint or lane for this to work though!
    starts = plan.compute_plan_starts(test_graph, map_name,
                                      [[-10.0], [0.0], [0.0]], adapter.now())
    assert [x.waypoint for x in starts] == [3], [x.waypoint for x in starts]

    # Alternatively, if you DO know where your robot is, place it directly!
    starts = [plan.Start(adapter.now(), 0, 0.0)]

    # Lambda to insert an adapter
    def updater_inserter(handle_obj, updater):
        updater.update_battery_soc(1.0)
        handle_obj.updater = updater

    # Manages and executes robot commands
    robot_cmd = MockRobotCommand(cmd_node, test_graph)

    fleet.add_robot(robot_cmd, "T0", profile, starts,
                    partial(updater_inserter, robot_cmd))

    # INIT DISPENSERS =========================================================
    dispenser = MockDispenser(dispenser_name)
    ingestor = MockIngestor(ingestor_name)

    # INIT TASK SUMMARY OBSERVER ==============================================
    # Note: this is used for assertation check on TaskSummary.Msg
    observer = TaskSummaryObserver()

    # FINAL PREP ==============================================================
    rclpy_executor = SingleThreadedExecutor()
    rclpy_executor.add_node(cmd_node)
    rclpy_executor.add_node(dispenser)
    rclpy_executor.add_node(ingestor)
    rclpy_executor.add_node(observer)

    # GO! =====================================================================
    adapter.start()

    print("\n")
    print("# SENDING SINGLE DELIVERY REQUEST ################################")
    print(test_graph_vis)

    dispenser.reset()
    ingestor.reset()
    observer.reset()
    observer.add_task(test_name)

    task_desc = Type.CPPTaskDescriptionMsg()
    # this is the time when the robot reaches the pick up point
    task_desc.start_time_sec = int(time.time()) + 50
    task_desc.delivery = Type.CPPDeliveryMsg(pickup_name, dispenser_name,
                                             dropoff_name, ingestor_name)
    task_profile = Type.CPPTaskProfileMsg()
    task_profile.description = task_desc
    task_profile.task_id = test_name
    adapter.dispatch_task(task_profile)

    rclpy_executor.spin_once(1)

    for i in range(1000):
        if observer.all_tasks_complete():
            print("Tasks Complete.")
            break
        rclpy_executor.spin_once(1)
        # time.sleep(0.2)

    results = observer.count_successful_tasks()
    print("\n== DEBUG TASK REPORT ==")
    print("Visited waypoints:", robot_cmd.visited_waypoints)
    print(f"Sucessful Tasks: {results[0]} / {results[1]}")

    assert results[0] == results[1], "Not all tasks were completed."

    error_msg = "Robot did not take the expected route"
    assert robot_cmd.visited_waypoints == [
        0, 0, 5, 5, 6, 6, 7, 6, 5, 5, 8, 8, 10
    ], error_msg

    # check if unstable partcipant works
    # this is helpful for to update the robot when it is
    print("Update a custom itinerary to fleet adapter")
    traj = schedule.make_trajectory(robot_traits, adapter.now(),
                                    [[3, 0, 0], [1, 1, 0], [2, 1, 0]])
    route = schedule.Route("test_map", traj)

    participant = robot_cmd.updater.get_unstable_participant()
    routeid = participant.last_route_id
    participant.set_itinerary([route])
    new_routeid = participant.last_route_id
    print(f"Previous route id: {routeid} , new route id: {new_routeid}")
    assert routeid != new_routeid

    # TODO(YL) There's an issue with during shutdown of the adapter, occurs
    # when set_itinerary() function above is used. Similarly with a non-mock
    # adpater, will need to address this in near future
    print("\n~ Shutting Down everything ~")

    cmd_node.destroy_node()
    observer.destroy_node()
    dispenser.destroy_node()
    ingestor.destroy_node()

    robot_cmd.stop()
    adapter.stop()
    rclpy_executor.shutdown()
    rclpy.shutdown()
def initialize_fleet(config_yaml, nav_graph_path, node, use_sim_time):
    # Profile and traits
    fleet_config = config_yaml['rmf_fleet']
    profile = traits.Profile(
        geometry.make_final_convex_circle(
            fleet_config['profile']['footprint']),
        geometry.make_final_convex_circle(fleet_config['profile']['vicinity']))
    vehicle_traits = traits.VehicleTraits(
        linear=traits.Limits(*fleet_config['limits']['linear']),
        angular=traits.Limits(*fleet_config['limits']['angular']),
        profile=profile)
    vehicle_traits.differential.reversible = fleet_config['reversible']

    # Battery system
    voltage = fleet_config['battery_system']['voltage']
    capacity = fleet_config['battery_system']['capacity']
    charging_current = fleet_config['battery_system']['charging_current']
    battery_sys = battery.BatterySystem.make(voltage, capacity,
                                             charging_current)

    # Mechanical system
    mass = fleet_config['mechanical_system']['mass']
    moment = fleet_config['mechanical_system']['moment_of_inertia']
    friction = fleet_config['mechanical_system']['friction_coefficient']
    mech_sys = battery.MechanicalSystem.make(mass, moment, friction)

    # Power systems
    ambient_power_sys = battery.PowerSystem.make(
        fleet_config['ambient_system']['power'])
    tool_power_sys = battery.PowerSystem.make(
        fleet_config['tool_system']['power'])

    # Power sinks
    motion_sink = battery.SimpleMotionPowerSink(battery_sys, mech_sys)
    ambient_sink = battery.SimpleDevicePowerSink(battery_sys,
                                                 ambient_power_sys)
    tool_sink = battery.SimpleDevicePowerSink(battery_sys, tool_power_sys)

    nav_graph = graph.parse_graph(nav_graph_path, vehicle_traits)

    # Adapter
    fleet_name = fleet_config['name']
    adapter = adpt.Adapter.make(f'{fleet_name}_fleet_adapter')
    if use_sim_time:
        adapter.node.use_sim_time()
    assert adapter, ("Unable to initialize fleet adapter. Please ensure "
                     "RMF Schedule Node is running")
    adapter.start()
    time.sleep(1.0)

    fleet_handle = adapter.add_fleet(fleet_name, vehicle_traits, nav_graph)

    if not fleet_config['publish_fleet_state']:
        fleet_handle.fleet_state_publish_period(None)
    # Account for battery drain
    drain_battery = fleet_config['account_for_battery_drain']
    recharge_threshold = fleet_config['recharge_threshold']
    recharge_soc = fleet_config['recharge_soc']
    finishing_request = fleet_config['task_capabilities']['finishing_request']
    node.get_logger().info(f"Finishing request: [{finishing_request}]")
    # Set task planner params
    ok = fleet_handle.set_task_planner_params(battery_sys, motion_sink,
                                              ambient_sink, tool_sink,
                                              recharge_threshold, recharge_soc,
                                              drain_battery, finishing_request)
    assert ok, ("Unable to set task planner params")

    task_capabilities = []
    if fleet_config['task_capabilities']['loop']:
        node.get_logger().info(
            f"Fleet [{fleet_name}] is configured to perform Loop tasks")
        task_capabilities.append(TaskType.TYPE_LOOP)
    if fleet_config['task_capabilities']['delivery']:
        node.get_logger().info(
            f"Fleet [{fleet_name}] is configured to perform Delivery tasks")
        task_capabilities.append(TaskType.TYPE_DELIVERY)
    if fleet_config['task_capabilities']['clean']:
        node.get_logger().info(
            f"Fleet [{fleet_name}] is configured to perform Clean tasks")
        task_capabilities.append(TaskType.TYPE_CLEAN)

    # Callable for validating requests that this fleet can accommodate
    def _task_request_check(task_capabilities, msg: TaskProfile):
        if msg.description.task_type in task_capabilities:
            return True
        else:
            return False

    fleet_handle.accept_task_requests(
        partial(_task_request_check, task_capabilities))

    # Transforms
    rmf_coordinates = config_yaml['reference_coordinates']['rmf']
    robot_coordinates = config_yaml['reference_coordinates']['robot']
    transforms = {
        'rmf_to_robot': nudged.estimate(rmf_coordinates, robot_coordinates),
        'robot_to_rmf': nudged.estimate(robot_coordinates, rmf_coordinates)
    }
    transforms['orientation_offset'] = \
        transforms['rmf_to_robot'].get_rotation()
    mse = nudged.estimate_error(transforms['rmf_to_robot'], rmf_coordinates,
                                robot_coordinates)
    print(f"Coordinate transformation error: {mse}")
    print("RMF to Robot transform:")
    print(f"    rotation:{transforms['rmf_to_robot'].get_rotation()}")
    print(f"    scale:{transforms['rmf_to_robot'].get_scale()}")
    print(f"    trans:{transforms['rmf_to_robot'].get_translation()}")
    print("Robot to RMF transform:")
    print(f"    rotation:{transforms['robot_to_rmf'].get_rotation()}")
    print(f"    scale:{transforms['robot_to_rmf'].get_scale()}")
    print(f"    trans:{transforms['robot_to_rmf'].get_translation()}")

    def _updater_inserter(cmd_handle, update_handle):
        """Insert a RobotUpdateHandle."""
        cmd_handle.update_handle = update_handle

    # Initialize robots for this fleet
    robots = {}
    for robot_name, robot_config in config_yaml['robots'].items():
        node.get_logger().info(f"Initializing robot:{robot_name}")
        rmf_config = robot_config['rmf_config']
        robot_config = robot_config['robot_config']
        initial_waypoint = rmf_config['start']['waypoint']
        initial_orientation = rmf_config['start']['orientation']
        robot = RobotCommandHandle(
            name=robot_name,
            config=robot_config,
            node=node,
            graph=nav_graph,
            vehicle_traits=vehicle_traits,
            transforms=transforms,
            map_name=rmf_config['start']['map_name'],
            initial_waypoint=initial_waypoint,
            initial_orientation=initial_orientation,
            charger_waypoint=rmf_config['charger']['waypoint'],
            update_frequency=rmf_config.get('robot_state_update_frequency', 1),
            adapter=adapter)

        if robot.initialized:
            robots[robot_name] = robot
            # Add robot to fleet
            fleet_handle.add_robot(robot, robot_name, profile, robot.starts,
                                   partial(_updater_inserter, robot))
            node.get_logger().info(
                f"Successfully added new robot:{robot_name}")

        else:
            node.get_logger().error(f"Failed to initialize robot:{robot_name}")

    return adapter, fleet_handle, robots
# HOLONOMIC ===================================================================
holonomic = traits.Holonomic()


def test_holonomic():
    assert holonomic


# PROFILE =====================================================================
# Setup
circle = geometry.make_final_convex_circle(5)
big_circle = geometry.make_final_convex_circle(10)

# Check instantiation
profile = traits.Profile(circle)
profile_with_vicinity = traits.Profile(big_circle, circle)


def test_profile():
    # Check getters
    assert (profile.footprint.characteristic_length ==
            circle.characteristic_length)
    assert (
        profile.vicinity.characteristic_length == circle.characteristic_length)

    assert (profile_with_vicinity.footprint.characteristic_length ==
            big_circle.characteristic_length)
    assert (profile_with_vicinity.vicinity.characteristic_length ==
            circle.characteristic_length)