From 2aded5d5995538f1c921a3055a398e49867894e5 Mon Sep 17 00:00:00 2001 From: Arjo Chakravarty Date: Tue, 6 Feb 2024 14:46:33 +0800 Subject: [PATCH 01/21] Add proto-reservation node as core part of RMF Signed-off-by: Arjo Chakravarty --- rmf_demos/launch/common.launch.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rmf_demos/launch/common.launch.xml b/rmf_demos/launch/common.launch.xml index f13431f5..f9323379 100644 --- a/rmf_demos/launch/common.launch.xml +++ b/rmf_demos/launch/common.launch.xml @@ -60,6 +60,11 @@ + + + + + From 052bc0171616f31358a33231d82d5d98a2ddc2ff Mon Sep 17 00:00:00 2001 From: Arjo Chakravarty Date: Thu, 1 Aug 2024 22:48:09 -0400 Subject: [PATCH 02/21] Enabled the chope system Signed-off-by: Arjo Chakravarty --- rmf_demos/config/office/tinyRobot_config.yaml | 6 +++--- .../rmf_demos_fleet_adapter/fleet_adapter.py | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/rmf_demos/config/office/tinyRobot_config.yaml b/rmf_demos/config/office/tinyRobot_config.yaml index 75d53a75..43fd85d2 100644 --- a/rmf_demos/config/office/tinyRobot_config.yaml +++ b/rmf_demos/config/office/tinyRobot_config.yaml @@ -30,13 +30,13 @@ rmf_fleet: loop: True delivery: True actions: ["teleop"] - finishing_request: "park" # [park, charge, nothing] - responsive_wait: True # Should responsive wait be on/off for the whole fleet by default? False if not specified. + finishing_request: "nothing" # [park, charge, nothing] + responsive_wait: False # Should responsive wait be on/off for the whole fleet by default? False if not specified. + use_parking_reservations: True reassign_task_interval: 120 # seconds, specify how often a task reassignment should be triggered in the fleet robots: tinyRobot1: charger: "tinyRobot1_charger" - responsive_wait: False # Should responsive wait be on/off for this specific robot? Overrides the fleet-wide setting. tinyRobot2: charger: "tinyRobot2_charger" # No mention of responsive_wait means the fleet-wide setting will be used diff --git a/rmf_demos_fleet_adapter/rmf_demos_fleet_adapter/fleet_adapter.py b/rmf_demos_fleet_adapter/rmf_demos_fleet_adapter/fleet_adapter.py index 1656fd6b..f83bd007 100644 --- a/rmf_demos_fleet_adapter/rmf_demos_fleet_adapter/fleet_adapter.py +++ b/rmf_demos_fleet_adapter/rmf_demos_fleet_adapter/fleet_adapter.py @@ -14,6 +14,7 @@ import argparse import asyncio +import faulthandler import math import sys import threading @@ -46,6 +47,7 @@ # Main # ------------------------------------------------------------------------------ def main(argv=sys.argv): + faulthandler.enable() # Init rclpy and adapter rclpy.init(args=argv) rmf_adapter.init_rclcpp() From c7c55fe8756ef9f947f996b7f22ee08408279813 Mon Sep 17 00:00:00 2001 From: Arjo Chakravarty Date: Wed, 21 Aug 2024 15:01:20 +0800 Subject: [PATCH 03/21] Fix office world There are a number of objects which obstruct the passage lanes in the office world. This commit removes them. Signed-off-by: Arjo Chakravarty --- rmf_demos_maps/maps/office/office.building.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/rmf_demos_maps/maps/office/office.building.yaml b/rmf_demos_maps/maps/office/office.building.yaml index 50dd3394..727a1113 100644 --- a/rmf_demos_maps/maps/office/office.building.yaml +++ b/rmf_demos_maps/maps/office/office.building.yaml @@ -163,7 +163,6 @@ levels: - {dispensable: false, model_name: OpenRobotics/Drawer, name: Drawer, static: true, x: 2625.4479999999999, y: 1094.713, yaw: 4.6216999999999997, z: 0} - {dispensable: false, model_name: OpenRobotics/ConfTable, name: ConfTable, static: true, x: 620, y: 872, yaw: 1.1016999999999999, z: 0} - {dispensable: false, model_name: OpenRobotics/WhiteCabinet, name: WhiteCabinet, static: true, x: 1775.8789999999999, y: 344.82299999999998, yaw: -0.035700000000000003, z: 0} - - {dispensable: false, model_name: OpenRobotics/SquareShelf, name: SquareShelf, static: true, x: 938.97000000000003, y: 352.11799999999999, yaw: 2.6640000000000001, z: 0} - {dispensable: false, model_name: OpenRobotics/TeleportDispenser, name: coke_dispenser, static: true, x: 2097.3649999999998, y: 649.80899999999997, yaw: 1.5708, z: 1.0800000000000001} - {dispensable: false, model_name: OpenRobotics/TeleportDispenser, name: coke_dispenser_2, static: true, x: 2095.2669999999998, y: 689.745, yaw: 1.5708, z: 0.63} - {dispensable: false, model_name: OpenRobotics/Coke, name: Coke, static: false, x: 2098.6509999999998, y: 650.52300000000002, yaw: 1.5708, z: 1.0800000000000001} @@ -171,7 +170,6 @@ levels: - {dispensable: false, model_name: OpenRobotics/TeleportIngestor, name: coke_ingestor_2, static: true, x: 668.75900000000001, y: 703.86400000000003, yaw: 1.5708, z: 0.80000000000000004} - {dispensable: false, model_name: OpenRobotics/MetalCabinet, name: OpenRobotics/MetalCabinet, static: true, x: 1946.0540000000001, y: 1238.8910000000001, yaw: 0.0092999999999999992, z: 0} - {dispensable: false, model_name: OpenRobotics/MetalCabinet, name: OpenRobotics/MetalCabinet, static: true, x: 2053.6880000000001, y: 1237.701, yaw: 0.0172, z: 0} - - {dispensable: false, model_name: OpenRobotics/RecTable, name: OpenRobotics/RecTable, static: true, x: 899.73800000000006, y: 967.89999999999998, yaw: 1.0973999999999999, z: 0} - {dispensable: false, model_name: OpenRobotics/SquareShelf, name: OpenRobotics/SquareShelf, static: true, x: 2450.9459999999999, y: 362.63799999999998, yaw: -0.0083000000000000001, z: 0} - {dispensable: false, model_name: OpenRobotics/Fridge, name: OpenRobotics/Fridge, static: true, x: 1875.9770000000001, y: 604.197, yaw: 1.5708, z: 0} - {dispensable: false, model_name: OpenRobotics/Drawer, name: OpenRobotics/Drawer, static: true, x: 1471.6030000000001, y: 1374.8610000000001, yaw: 3.1000000000000001, z: 0} @@ -190,7 +188,6 @@ levels: - {dispensable: false, model_name: OpenRobotics/MetalCabinetYellow, name: OpenRobotics/MetalCabinetYellow, static: true, x: 2562.2370000000001, y: 408.46100000000001, yaw: -0.043499999999999997, z: 0} - {dispensable: false, model_name: OpenRobotics/MetalCabinet, name: OpenRobotics/MetalCabinet, static: true, x: 758.96900000000005, y: 470.916, yaw: 2.6833999999999998, z: 0} - {dispensable: false, model_name: OpenRobotics/MetalCabinet, name: OpenRobotics/MetalCabinet, static: true, x: 696.33399999999995, y: 371.52800000000002, yaw: 1.1071, z: 0} - - {dispensable: false, model_name: OpenRobotics/MiR100, name: OpenRobotics/MiR100, static: true, x: 968.74300000000005, y: 827.98800000000006, yaw: -0.51590000000000003, z: 0} - {dispensable: false, model_name: OpenRobotics/Drawer, name: OpenRobotics/Drawer, static: true, x: 1243.4269999999999, y: 1282.3009999999999, yaw: 1.6649, z: 0} - {dispensable: false, model_name: OpenRobotics/Drawer, name: OpenRobotics/Drawer, static: true, x: 1182.452, y: 1288.9069999999999, yaw: -1.512, z: 0} - {dispensable: false, model_name: OpenRobotics/OfficeChairBlue, name: OpenRobotics/OfficeChairBlue, static: true, x: 842.88199999999995, y: 1178.6559999999999, yaw: -2.0863, z: 0} From c91fd28c3b164e026adea32bd7cc0775cb1b1f6a Mon Sep 17 00:00:00 2001 From: Arjo Chakravarty Date: Thu, 22 Aug 2024 16:21:43 +0800 Subject: [PATCH 04/21] Add a hacky wait for task completion tool Signed-off-by: Arjo Chakravarty --- rmf_demos_tasks/README.md | 6 + .../rmf_demos_tasks/wait_till_complete.py | 104 ++++++++++++++++++ rmf_demos_tasks/setup.py | 1 + 3 files changed, 111 insertions(+) create mode 100644 rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py diff --git a/rmf_demos_tasks/README.md b/rmf_demos_tasks/README.md index 50a6e533..8ff45895 100644 --- a/rmf_demos_tasks/README.md +++ b/rmf_demos_tasks/README.md @@ -105,6 +105,12 @@ The new task system allows users to construct and submit their own tasks in a mo ros2 run rmf_demos_tasks dispatch_go_to_place -p lounge -o 105 --use_sim_time ``` +- **wait_for_task_complete** + This is a tool meant only for creating test scenarios. Essentially it blocks until a specified robot is free of any tasks. This allows us to do integration tests. Example in office world: + ``` + ros2 run rmf_demos_tasks wait_for_task_complete -F tinyRobot -R tinyRobot1 + ``` + ## Quality Declaration This package claims to be in the **Quality Level 4** category, see the [Quality Declaration](./QUALITY_DECLARATION.md) for more details. diff --git a/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py b/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py new file mode 100644 index 00000000..520cef9a --- /dev/null +++ b/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 + +# Copyright 2024 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import asyncio +import json +import sys +import uuid + +import rclpy +from rclpy.node import Node +from rclpy.parameter import Parameter +from rclpy.qos import QoSDurabilityPolicy as Durability +from rclpy.qos import QoSHistoryPolicy as History +from rclpy.qos import QoSProfile +from rclpy.qos import QoSReliabilityPolicy as Reliability +from rmf_fleet_msgs.msg import FleetState +import time + +""" +This is a tool that should be used only for testing purpose! Do not ever, ever, ever +use it in production. +""" +class TaskObserver(Node): + def __init__(self, parser): + super().__init__("TaskObserver") + + self.parser = parser + self.response = asyncio.Future() + + self.subscription = self.create_subscription( + FleetState, + '/fleet_states', + self.state_watcher, + 10) + + def state_watcher(self, fleet_state: FleetState): + if fleet_state.name != self.parser.fleet: + return + for robot_state in fleet_state.robots: + if robot_state.name == self.parser.robot and robot_state.task_id == "": + self.response.set_result(robot_state) + return + +def create_parser(): + parser = argparse.ArgumentParser() + + parser.add_argument( + '-R', + '--robot', + type=str, + help='Robot name, should define together with fleet', + ) + + parser.add_argument( + '-F', + '--fleet', + type=str, + help='fleet name', + ) + + + parser.add_argument( + '--timeout', + type=int, + help='Timeout seconds', + ) + return parser + +def main(argv=sys.argv): + rclpy.init(args=sys.argv) + args_without_ros = rclpy.utilities.remove_ros_args(sys.argv) + arg_parser = create_parser() + arguments = arg_parser.parse_args(args_without_ros[1:]) + task_requester = TaskObserver(arguments) + start_time = time.time() + rclpy.spin_until_future_complete( + task_requester, task_requester.response, timeout_sec=arguments.timeout + ) + if task_requester.response.done(): + print(f'Got response:\n{task_requester.response.result()}') + end_time = time.time() + elapsed= end_time - start_time + print(f"elapsed time: {elapsed}") + else: + print('Timed out') + rclpy.shutdown() + + +if __name__ == '__main__': + main(sys.argv) \ No newline at end of file diff --git a/rmf_demos_tasks/setup.py b/rmf_demos_tasks/setup.py index fd8808c9..6ef2925a 100644 --- a/rmf_demos_tasks/setup.py +++ b/rmf_demos_tasks/setup.py @@ -40,6 +40,7 @@ 'teleop_robot = rmf_demos_tasks.teleop_robot:main', 'dispatch_json = rmf_demos_tasks.dispatch_json:main', 'api_request = rmf_demos_tasks.api_request:main', + 'wait_for_task_complete = rmf_demos_tasks.wait_till_complete:main' ], }, ) From 623b5e713c51741f4af5b1745446df8512fcdcb0 Mon Sep 17 00:00:00 2001 From: Arjo Chakravarty Date: Tue, 27 Aug 2024 12:33:01 +0800 Subject: [PATCH 05/21] Fix crashes Signed-off-by: Arjo Chakravarty --- .../rmf_demos_tasks/get_robot_location.py | 141 ++++++++++++++++++ .../rmf_demos_tasks/wait_till_complete.py | 3 +- rmf_demos_tasks/setup.py | 1 + 3 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py diff --git a/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py b/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py new file mode 100644 index 00000000..0ac6d0fb --- /dev/null +++ b/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python3 + +# Copyright 2024 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import asyncio +import json +import sys +import uuid + +import rclpy +from rclpy.node import Node +from rclpy.parameter import Parameter +from rclpy.qos import QoSDurabilityPolicy as Durability +from rclpy.qos import QoSHistoryPolicy as History +from rclpy.qos import QoSProfile +from rclpy.qos import QoSReliabilityPolicy as Reliability +from rmf_fleet_msgs.msg import FleetState +from rmf_building_map_msgs.msg import Graph +import time + +""" +This is a tool that should be used only for testing purpose! Do not ever, ever, ever +use it in production. +""" +class RobotStateObserver(Node): + def __init__(self, parser): + super().__init__("TaskObserver") + + self.parser = parser + self.response = asyncio.Future() + + self.subscription = self.create_subscription( + FleetState, + '/fleet_states', + self.state_watcher, + 10) + + nav_graph_qos = QoSProfile( + history=History.KEEP_LAST, depth=10, durability=Durability.TRANSIENT_LOCAL, reliability=Reliability.RELIABLE) + + self.nav_graph_subscription = self.create_subscription( + Graph, + '/nav_graphs', + self.nav_graph_watcher, + nav_graph_qos) + + self.nav_graph = None + + def state_watcher(self, fleet_state: FleetState): + + if self.nav_graph is None: + print ("Grapoh not found") + return + + if fleet_state.name != self.parser.fleet: + return + for robot_state in fleet_state.robots: + if robot_state.name == self.parser.robot: + for graph_node in self.nav_graph.vertices: + dist = (graph_node.x - robot_state.location.x) ** 2 + (graph_node.y - robot_state.location.y) ** 2 + if dist < 0.5: + if self.parser.block_until_reaches == "": + self.response.set_result(graph_node.name) + elif self.parser.block_until_reaches == graph_node.name: + self.response.set_result(graph_node.name) + return + + + def nav_graph_watcher(self, navgraph: Graph): + print ("Got graph") + if navgraph.name == self.parser.fleet: + self.nav_graph = navgraph + +def create_parser(): + parser = argparse.ArgumentParser() + + parser.add_argument( + '-R', + '--robot', + type=str, + help='Robot name, should define together with fleet', + ) + + parser.add_argument( + '-F', + '--fleet', + type=str, + help='fleet name', + ) + + + parser.add_argument( + '--timeout', + type=int, + help='Timeout seconds', + ) + + parser.add_argument( + '--block-until-reaches', + '-B', + type=str, + help='Block until this waypoint is reached. If empty, then the command does not block.' + ) + return parser + +def main(argv=sys.argv): + rclpy.init(args=sys.argv) + args_without_ros = rclpy.utilities.remove_ros_args(sys.argv) + arg_parser = create_parser() + arguments = arg_parser.parse_args(args_without_ros[1:]) + task_requester = RobotStateObserver(arguments) + start_time = time.time() + rclpy.spin_until_future_complete( + task_requester, task_requester.response, timeout_sec=arguments.timeout + ) + if task_requester.response.done(): + print(f'Got response:\n{task_requester.response.result()}') + end_time = time.time() + elapsed = end_time - start_time + print(f"elapsed time: {elapsed}") + else: + print('Timed out') + sys.exit(-1) + rclpy.shutdown() + + +if __name__ == '__main__': + main(sys.argv) \ No newline at end of file diff --git a/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py b/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py index 520cef9a..6cb4c1f5 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py +++ b/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py @@ -93,10 +93,11 @@ def main(argv=sys.argv): if task_requester.response.done(): print(f'Got response:\n{task_requester.response.result()}') end_time = time.time() - elapsed= end_time - start_time + elapsed = end_time - start_time print(f"elapsed time: {elapsed}") else: print('Timed out') + sys.exit(-1) rclpy.shutdown() diff --git a/rmf_demos_tasks/setup.py b/rmf_demos_tasks/setup.py index 6ef2925a..6bdf3feb 100644 --- a/rmf_demos_tasks/setup.py +++ b/rmf_demos_tasks/setup.py @@ -36,6 +36,7 @@ 'dispatch_clean = rmf_demos_tasks.dispatch_clean:main', 'dispatch_go_to_place = rmf_demos_tasks.dispatch_go_to_place:main', 'dispatch_teleop = rmf_demos_tasks.dispatch_teleop:main', + 'get_robot_location = rmf_demos_tasks.get_robot_location:main', 'mock_docker = rmf_demos_tasks.mock_docker:main', 'teleop_robot = rmf_demos_tasks.teleop_robot:main', 'dispatch_json = rmf_demos_tasks.dispatch_json:main', From c56bbe79b250b3545fa19de502f57392ef706b9d Mon Sep 17 00:00:00 2001 From: Arjo Chakravarty Date: Thu, 19 Sep 2024 10:12:44 +0800 Subject: [PATCH 06/21] Don't disturb default demos. Explicitly make chope node optional. Signed-off-by: Arjo Chakravarty --- rmf_demos/config/office/tinyRobot_config.yaml | 6 +-- .../office_chope_node/tinyRobot_config.yaml | 48 +++++++++++++++++++ rmf_demos/launch/common.launch.xml | 3 +- rmf_demos/launch/office_chope_node.launch.xml | 23 +++++++++ .../launch/office_chope_node.launch.xml | 20 ++++++++ 5 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 rmf_demos/config/office_chope_node/tinyRobot_config.yaml create mode 100644 rmf_demos/launch/office_chope_node.launch.xml create mode 100644 rmf_demos_gz/launch/office_chope_node.launch.xml diff --git a/rmf_demos/config/office/tinyRobot_config.yaml b/rmf_demos/config/office/tinyRobot_config.yaml index 43fd85d2..46802096 100644 --- a/rmf_demos/config/office/tinyRobot_config.yaml +++ b/rmf_demos/config/office/tinyRobot_config.yaml @@ -30,9 +30,9 @@ rmf_fleet: loop: True delivery: True actions: ["teleop"] - finishing_request: "nothing" # [park, charge, nothing] - responsive_wait: False # Should responsive wait be on/off for the whole fleet by default? False if not specified. - use_parking_reservations: True + finishing_request: "park" # [park, charge, nothing] + responsive_wait: True # Should responsive wait be on/off for the whole fleet by default? False if not specified. + use_parking_reservations: False reassign_task_interval: 120 # seconds, specify how often a task reassignment should be triggered in the fleet robots: tinyRobot1: diff --git a/rmf_demos/config/office_chope_node/tinyRobot_config.yaml b/rmf_demos/config/office_chope_node/tinyRobot_config.yaml new file mode 100644 index 00000000..43fd85d2 --- /dev/null +++ b/rmf_demos/config/office_chope_node/tinyRobot_config.yaml @@ -0,0 +1,48 @@ +# FLEET CONFIG ================================================================= +# RMF Fleet parameters + +rmf_fleet: + name: "tinyRobot" + limits: + linear: [0.5, 0.75] # velocity, acceleration + angular: [0.6, 2.0] # velocity, acceleration + profile: # Robot profile is modelled as a circle + footprint: 0.3 # radius in m + vicinity: 0.5 # radius in m + reversible: True # whether robots in this fleet can reverse + battery_system: + voltage: 12.0 # V + capacity: 24.0 # Ahr + charging_current: 5.0 # A + mechanical_system: + mass: 20.0 # kg + moment_of_inertia: 10.0 #kgm^2 + friction_coefficient: 0.22 + ambient_system: + power: 20.0 # W + tool_system: + power: 0.0 # W + recharge_threshold: 0.10 # Battery level below which robots in this fleet will not operate + recharge_soc: 1.0 # Battery level to which robots in this fleet should be charged up to during recharging tasks + publish_fleet_state: 10.0 # Publish frequency for fleet state, ensure that it is same as robot_state_update_frequency + account_for_battery_drain: True + task_capabilities: # Specify the types of RMF Tasks that robots in this fleet are capable of performing + loop: True + delivery: True + actions: ["teleop"] + finishing_request: "nothing" # [park, charge, nothing] + responsive_wait: False # Should responsive wait be on/off for the whole fleet by default? False if not specified. + use_parking_reservations: True + reassign_task_interval: 120 # seconds, specify how often a task reassignment should be triggered in the fleet + robots: + tinyRobot1: + charger: "tinyRobot1_charger" + tinyRobot2: + charger: "tinyRobot2_charger" + # No mention of responsive_wait means the fleet-wide setting will be used + +fleet_manager: + ip: "127.0.0.1" + port: 22011 + user: "some_user" + password: "some_password" diff --git a/rmf_demos/launch/common.launch.xml b/rmf_demos/launch/common.launch.xml index b6ff62d7..4c73ea86 100644 --- a/rmf_demos/launch/common.launch.xml +++ b/rmf_demos/launch/common.launch.xml @@ -10,6 +10,7 @@ + @@ -63,7 +64,7 @@ - + diff --git a/rmf_demos/launch/office_chope_node.launch.xml b/rmf_demos/launch/office_chope_node.launch.xml new file mode 100644 index 00000000..e56522d7 --- /dev/null +++ b/rmf_demos/launch/office_chope_node.launch.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rmf_demos_gz/launch/office_chope_node.launch.xml b/rmf_demos_gz/launch/office_chope_node.launch.xml new file mode 100644 index 00000000..3f0f1132 --- /dev/null +++ b/rmf_demos_gz/launch/office_chope_node.launch.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + From beecdfd280eae359a4e4c75a049f4bb178ce009c Mon Sep 17 00:00:00 2001 From: Arjo Chakravarty Date: Thu, 19 Sep 2024 10:22:52 +0800 Subject: [PATCH 07/21] Style Signed-off-by: Arjo Chakravarty --- rmf_demos/config/office/tinyRobot_config.yaml | 2 +- .../rmf_demos_tasks/get_robot_location.py | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/rmf_demos/config/office/tinyRobot_config.yaml b/rmf_demos/config/office/tinyRobot_config.yaml index 46802096..75d53a75 100644 --- a/rmf_demos/config/office/tinyRobot_config.yaml +++ b/rmf_demos/config/office/tinyRobot_config.yaml @@ -32,11 +32,11 @@ rmf_fleet: actions: ["teleop"] finishing_request: "park" # [park, charge, nothing] responsive_wait: True # Should responsive wait be on/off for the whole fleet by default? False if not specified. - use_parking_reservations: False reassign_task_interval: 120 # seconds, specify how often a task reassignment should be triggered in the fleet robots: tinyRobot1: charger: "tinyRobot1_charger" + responsive_wait: False # Should responsive wait be on/off for this specific robot? Overrides the fleet-wide setting. tinyRobot2: charger: "tinyRobot2_charger" # No mention of responsive_wait means the fleet-wide setting will be used diff --git a/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py b/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py index 0ac6d0fb..bc8c2c65 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py +++ b/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py @@ -32,10 +32,12 @@ import time """ -This is a tool that should be used only for testing purpose! Do not ever, ever, ever +This is a tool that should be used only for testing purpose! Do not use it in production. """ class RobotStateObserver(Node): + + def __init__(self, parser): super().__init__("TaskObserver") @@ -49,7 +51,10 @@ def __init__(self, parser): 10) nav_graph_qos = QoSProfile( - history=History.KEEP_LAST, depth=10, durability=Durability.TRANSIENT_LOCAL, reliability=Reliability.RELIABLE) + history=History.KEEP_LAST, + depth=10, + durability=Durability.TRANSIENT_LOCAL, + reliability=Reliability.RELIABLE) self.nav_graph_subscription = self.create_subscription( Graph, @@ -62,7 +67,7 @@ def __init__(self, parser): def state_watcher(self, fleet_state: FleetState): if self.nav_graph is None: - print ("Grapoh not found") + print("Nav graph not found") return if fleet_state.name != self.parser.fleet: @@ -70,7 +75,8 @@ def state_watcher(self, fleet_state: FleetState): for robot_state in fleet_state.robots: if robot_state.name == self.parser.robot: for graph_node in self.nav_graph.vertices: - dist = (graph_node.x - robot_state.location.x) ** 2 + (graph_node.y - robot_state.location.y) ** 2 + dist = (graph_node.x - robot_state.location.x) ** 2 + dist += (graph_node.y - robot_state.location.y) ** 2 if dist < 0.5: if self.parser.block_until_reaches == "": self.response.set_result(graph_node.name) @@ -112,7 +118,8 @@ def create_parser(): '--block-until-reaches', '-B', type=str, - help='Block until this waypoint is reached. If empty, then the command does not block.' + help='Block until this waypoint is reached. If empty,' + \ + ' then the command does not block.' ) return parser From c50a7b4d2b4e80cf09f4349354a2eb345ec3ea55 Mon Sep 17 00:00:00 2001 From: Arjo Chakravarty Date: Thu, 19 Sep 2024 10:27:07 +0800 Subject: [PATCH 08/21] Style Signed-off-by: Arjo Chakravarty --- .../rmf_demos_tasks/get_robot_location.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py b/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py index bc8c2c65..f3aca6a7 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py +++ b/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py @@ -31,12 +31,12 @@ from rmf_building_map_msgs.msg import Graph import time -""" -This is a tool that should be used only for testing purpose! Do not -use it in production. -""" -class RobotStateObserver(Node): +class RobotStateObserver(Node): + """ + This is a tool that should be used only for testing purpose! Do not + use it in production. + """ def __init__(self, parser): super().__init__("TaskObserver") @@ -77,16 +77,16 @@ def state_watcher(self, fleet_state: FleetState): for graph_node in self.nav_graph.vertices: dist = (graph_node.x - robot_state.location.x) ** 2 dist += (graph_node.y - robot_state.location.y) ** 2 + name = graph_node.name if dist < 0.5: if self.parser.block_until_reaches == "": - self.response.set_result(graph_node.name) - elif self.parser.block_until_reaches == graph_node.name: - self.response.set_result(graph_node.name) + self.response.set_result(name) + elif self.parser.block_until_reaches == name: + self.response.set_result(name) return def nav_graph_watcher(self, navgraph: Graph): - print ("Got graph") if navgraph.name == self.parser.fleet: self.nav_graph = navgraph From be1fe9126a946ae45fd4870e7f0eb6f5c5bc2635 Mon Sep 17 00:00:00 2001 From: Arjo Chakravarty Date: Thu, 19 Sep 2024 10:32:17 +0800 Subject: [PATCH 09/21] Hopefully fix style Signed-off-by: Arjo Chakravarty --- rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py b/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py index f3aca6a7..9c8be7c0 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py +++ b/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py @@ -85,11 +85,11 @@ def state_watcher(self, fleet_state: FleetState): self.response.set_result(name) return - def nav_graph_watcher(self, navgraph: Graph): if navgraph.name == self.parser.fleet: self.nav_graph = navgraph + def create_parser(): parser = argparse.ArgumentParser() @@ -107,7 +107,6 @@ def create_parser(): help='fleet name', ) - parser.add_argument( '--timeout', type=int, @@ -118,11 +117,12 @@ def create_parser(): '--block-until-reaches', '-B', type=str, - help='Block until this waypoint is reached. If empty,' + \ + help='Block until this waypoint is reached. If empty,' + ' then the command does not block.' ) return parser + def main(argv=sys.argv): rclpy.init(args=sys.argv) args_without_ros = rclpy.utilities.remove_ros_args(sys.argv) @@ -145,4 +145,4 @@ def main(argv=sys.argv): if __name__ == '__main__': - main(sys.argv) \ No newline at end of file + main(sys.argv) From ed4859acf0b231e13b654191b8f4573ce52b584e Mon Sep 17 00:00:00 2001 From: Arjo Chakravarty Date: Thu, 19 Sep 2024 10:38:55 +0800 Subject: [PATCH 10/21] Hopefully fix style for second file Signed-off-by: Arjo Chakravarty --- .../rmf_demos_tasks/wait_till_complete.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py b/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py index 6cb4c1f5..0a6d322b 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py +++ b/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py @@ -30,11 +30,12 @@ from rmf_fleet_msgs.msg import FleetState import time -""" -This is a tool that should be used only for testing purpose! Do not ever, ever, ever -use it in production. -""" + class TaskObserver(Node): + """ + This is a tool that should be used only for testing purpose! Do not + use it in production. + """ def __init__(self, parser): super().__init__("TaskObserver") @@ -51,10 +52,12 @@ def state_watcher(self, fleet_state: FleetState): if fleet_state.name != self.parser.fleet: return for robot_state in fleet_state.robots: - if robot_state.name == self.parser.robot and robot_state.task_id == "": + if robot_state.name == self.parser.robot \ + and robot_state.task_id == "": self.response.set_result(robot_state) return + def create_parser(): parser = argparse.ArgumentParser() @@ -72,7 +75,6 @@ def create_parser(): help='fleet name', ) - parser.add_argument( '--timeout', type=int, @@ -80,6 +82,7 @@ def create_parser(): ) return parser + def main(argv=sys.argv): rclpy.init(args=sys.argv) args_without_ros = rclpy.utilities.remove_ros_args(sys.argv) @@ -102,4 +105,4 @@ def main(argv=sys.argv): if __name__ == '__main__': - main(sys.argv) \ No newline at end of file + main(sys.argv) From 2c55b5c9425ebe5809d4b6c5c02ae5447d5bdbe6 Mon Sep 17 00:00:00 2001 From: Arjo Chakravarty Date: Thu, 19 Sep 2024 13:16:49 +0800 Subject: [PATCH 11/21] Fix style Signed-off-by: Arjo Chakravarty --- rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py b/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py index 0a6d322b..0f7006fa 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py +++ b/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py @@ -53,7 +53,7 @@ def state_watcher(self, fleet_state: FleetState): return for robot_state in fleet_state.robots: if robot_state.name == self.parser.robot \ - and robot_state.task_id == "": + and robot_state.task_id == "": self.response.set_result(robot_state) return From 3738871a9393a92d5fc50c4dd1798139804ec15a Mon Sep 17 00:00:00 2001 From: Arjo Chakravarty Date: Thu, 19 Sep 2024 14:18:25 +0800 Subject: [PATCH 12/21] Fix style Signed-off-by: Arjo Chakravarty --- rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py b/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py index 0f7006fa..7455843d 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py +++ b/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py @@ -53,9 +53,9 @@ def state_watcher(self, fleet_state: FleetState): return for robot_state in fleet_state.robots: if robot_state.name == self.parser.robot \ - and robot_state.task_id == "": - self.response.set_result(robot_state) - return + and robot_state.task_id == "": + self.response.set_result(robot_state) + return def create_parser(): From f6d199679b1f93ffede3bec0b574c7020e80d019 Mon Sep 17 00:00:00 2001 From: Arjo Chakravarty Date: Wed, 25 Sep 2024 13:03:06 +0800 Subject: [PATCH 13/21] Mega rename As per a discussion with @mxgrey we are removing references to "chope" Signed-off-by: Arjo Chakravarty --- .../tinyRobot_config.yaml | 0 rmf_demos/launch/common.launch.xml | 6 +++--- ...e_node.launch.xml => office_reservation_node.launch.xml} | 4 ++-- ...e_node.launch.xml => office_reservation_node.launch.xml} | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) rename rmf_demos/config/{office_chope_node => office_reservation_node}/tinyRobot_config.yaml (100%) rename rmf_demos/launch/{office_chope_node.launch.xml => office_reservation_node.launch.xml} (88%) rename rmf_demos_gz/launch/{office_chope_node.launch.xml => office_reservation_node.launch.xml} (87%) diff --git a/rmf_demos/config/office_chope_node/tinyRobot_config.yaml b/rmf_demos/config/office_reservation_node/tinyRobot_config.yaml similarity index 100% rename from rmf_demos/config/office_chope_node/tinyRobot_config.yaml rename to rmf_demos/config/office_reservation_node/tinyRobot_config.yaml diff --git a/rmf_demos/launch/common.launch.xml b/rmf_demos/launch/common.launch.xml index 4c73ea86..36a16908 100644 --- a/rmf_demos/launch/common.launch.xml +++ b/rmf_demos/launch/common.launch.xml @@ -10,7 +10,7 @@ - + @@ -64,8 +64,8 @@ - - + + diff --git a/rmf_demos/launch/office_chope_node.launch.xml b/rmf_demos/launch/office_reservation_node.launch.xml similarity index 88% rename from rmf_demos/launch/office_chope_node.launch.xml rename to rmf_demos/launch/office_reservation_node.launch.xml index e56522d7..284fa6db 100644 --- a/rmf_demos/launch/office_chope_node.launch.xml +++ b/rmf_demos/launch/office_reservation_node.launch.xml @@ -8,7 +8,7 @@ - + @@ -16,7 +16,7 @@ - + diff --git a/rmf_demos_gz/launch/office_chope_node.launch.xml b/rmf_demos_gz/launch/office_reservation_node.launch.xml similarity index 87% rename from rmf_demos_gz/launch/office_chope_node.launch.xml rename to rmf_demos_gz/launch/office_reservation_node.launch.xml index 3f0f1132..3bdd3e67 100644 --- a/rmf_demos_gz/launch/office_chope_node.launch.xml +++ b/rmf_demos_gz/launch/office_reservation_node.launch.xml @@ -6,7 +6,7 @@ - + From 8d17e6c2bed1ecfdeebdd21c6153f06c57502ab5 Mon Sep 17 00:00:00 2001 From: Arjo Chakravarty Date: Wed, 25 Sep 2024 13:06:38 +0800 Subject: [PATCH 14/21] Make style happy Signed-off-by: Arjo Chakravarty --- rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py b/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py index 7455843d..31514a1a 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py +++ b/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py @@ -52,8 +52,8 @@ def state_watcher(self, fleet_state: FleetState): if fleet_state.name != self.parser.fleet: return for robot_state in fleet_state.robots: - if robot_state.name == self.parser.robot \ - and robot_state.task_id == "": + if robot_state.name == self.parser.robot: + if robot_state.task_id == "": self.response.set_result(robot_state) return From 57879d9ec6268d519aefaefeb364892b587c9dc8 Mon Sep 17 00:00:00 2001 From: "Michael X. Grey" Date: Thu, 14 Nov 2024 05:24:28 +0000 Subject: [PATCH 15/21] Make script name consistent with executable name Signed-off-by: Michael X. Grey --- .../{wait_till_complete.py => wait_for_task_complete.py} | 0 rmf_demos_tasks/setup.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename rmf_demos_tasks/rmf_demos_tasks/{wait_till_complete.py => wait_for_task_complete.py} (100%) diff --git a/rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py b/rmf_demos_tasks/rmf_demos_tasks/wait_for_task_complete.py similarity index 100% rename from rmf_demos_tasks/rmf_demos_tasks/wait_till_complete.py rename to rmf_demos_tasks/rmf_demos_tasks/wait_for_task_complete.py diff --git a/rmf_demos_tasks/setup.py b/rmf_demos_tasks/setup.py index 6bdf3feb..5ca8fe45 100644 --- a/rmf_demos_tasks/setup.py +++ b/rmf_demos_tasks/setup.py @@ -41,7 +41,7 @@ 'teleop_robot = rmf_demos_tasks.teleop_robot:main', 'dispatch_json = rmf_demos_tasks.dispatch_json:main', 'api_request = rmf_demos_tasks.api_request:main', - 'wait_for_task_complete = rmf_demos_tasks.wait_till_complete:main' + 'wait_for_task_complete = rmf_demos_tasks.wait_for_task_complete:main' ], }, ) From d53906901d8d4cf9449678bdfdaf947a100d6584 Mon Sep 17 00:00:00 2001 From: "Michael X. Grey" Date: Thu, 14 Nov 2024 06:01:13 +0000 Subject: [PATCH 16/21] Clear obstacles off of pathways in office Signed-off-by: Michael X. Grey --- rmf_demos_maps/maps/office/office.building.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/rmf_demos_maps/maps/office/office.building.yaml b/rmf_demos_maps/maps/office/office.building.yaml index 727a1113..f48674f5 100644 --- a/rmf_demos_maps/maps/office/office.building.yaml +++ b/rmf_demos_maps/maps/office/office.building.yaml @@ -172,10 +172,6 @@ levels: - {dispensable: false, model_name: OpenRobotics/MetalCabinet, name: OpenRobotics/MetalCabinet, static: true, x: 2053.6880000000001, y: 1237.701, yaw: 0.0172, z: 0} - {dispensable: false, model_name: OpenRobotics/SquareShelf, name: OpenRobotics/SquareShelf, static: true, x: 2450.9459999999999, y: 362.63799999999998, yaw: -0.0083000000000000001, z: 0} - {dispensable: false, model_name: OpenRobotics/Fridge, name: OpenRobotics/Fridge, static: true, x: 1875.9770000000001, y: 604.197, yaw: 1.5708, z: 0} - - {dispensable: false, model_name: OpenRobotics/Drawer, name: OpenRobotics/Drawer, static: true, x: 1471.6030000000001, y: 1374.8610000000001, yaw: 3.1000000000000001, z: 0} - - {dispensable: false, model_name: OpenRobotics/Drawer, name: OpenRobotics/Drawer, static: true, x: 1522.318, y: 1375.692, yaw: 3.0893000000000002, z: 0} - - {dispensable: false, model_name: OpenRobotics/Drawer, name: OpenRobotics/Drawer, static: true, x: 1571.0940000000001, y: 1377.078, yaw: 3.1097000000000001, z: 0} - - {dispensable: false, model_name: OpenRobotics/Drawer, name: OpenRobotics/Drawer, static: true, x: 1679.73, y: 1373.4749999999999, yaw: -3.0832999999999999, z: 0} - {dispensable: false, model_name: OpenRobotics/AdjTable, name: OpenRobotics/AdjTable, static: true, x: 2699.48, y: 546.64800000000002, yaw: -1.7435, z: 0} - {dispensable: false, model_name: OpenRobotics/CoffeeTable, name: OpenRobotics/CoffeeTable, static: true, x: 2732.7600000000002, y: 394.072, yaw: 1.5708, z: 0} - {dispensable: false, model_name: OpenRobotics/Drawer, name: OpenRobotics/Drawer, static: true, x: 1031.5450000000001, y: 397.61099999999999, yaw: 1.1779999999999999, z: 0} @@ -188,8 +184,6 @@ levels: - {dispensable: false, model_name: OpenRobotics/MetalCabinetYellow, name: OpenRobotics/MetalCabinetYellow, static: true, x: 2562.2370000000001, y: 408.46100000000001, yaw: -0.043499999999999997, z: 0} - {dispensable: false, model_name: OpenRobotics/MetalCabinet, name: OpenRobotics/MetalCabinet, static: true, x: 758.96900000000005, y: 470.916, yaw: 2.6833999999999998, z: 0} - {dispensable: false, model_name: OpenRobotics/MetalCabinet, name: OpenRobotics/MetalCabinet, static: true, x: 696.33399999999995, y: 371.52800000000002, yaw: 1.1071, z: 0} - - {dispensable: false, model_name: OpenRobotics/Drawer, name: OpenRobotics/Drawer, static: true, x: 1243.4269999999999, y: 1282.3009999999999, yaw: 1.6649, z: 0} - - {dispensable: false, model_name: OpenRobotics/Drawer, name: OpenRobotics/Drawer, static: true, x: 1182.452, y: 1288.9069999999999, yaw: -1.512, z: 0} - {dispensable: false, model_name: OpenRobotics/OfficeChairBlue, name: OpenRobotics/OfficeChairBlue, static: true, x: 842.88199999999995, y: 1178.6559999999999, yaw: -2.0863, z: 0} - {dispensable: false, model_name: OpenRobotics/MetalCabinet, name: OpenRobotics/MetalCabinet, static: true, x: 2463.2600000000002, y: 758.13, yaw: -0.014500000000000001, z: 0} - {dispensable: false, model_name: OpenRobotics/MetalCabinet, name: OpenRobotics/MetalCabinet, static: true, x: 2561.8960000000002, y: 759.04300000000001, yaw: -0.024400000000000002, z: 0} From 500e20d960022478da5985cc253507b3045116c5 Mon Sep 17 00:00:00 2001 From: "Michael X. Grey" Date: Thu, 14 Nov 2024 06:10:46 +0000 Subject: [PATCH 17/21] Fix style issues Signed-off-by: Michael X. Grey --- rmf_demos_tasks/rmf_demos_tasks/api_request.py | 2 +- rmf_demos_tasks/rmf_demos_tasks/dispatch_action.py | 2 +- .../rmf_demos_tasks/dispatch_cart_delivery.py | 2 +- rmf_demos_tasks/rmf_demos_tasks/dispatch_clean.py | 2 +- rmf_demos_tasks/rmf_demos_tasks/dispatch_delivery.py | 2 +- rmf_demos_tasks/rmf_demos_tasks/dispatch_go_to_place.py | 2 +- rmf_demos_tasks/rmf_demos_tasks/dispatch_json.py | 2 +- rmf_demos_tasks/rmf_demos_tasks/dispatch_patrol.py | 2 +- rmf_demos_tasks/rmf_demos_tasks/dispatch_teleop.py | 2 +- rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py | 9 +++------ .../rmf_demos_tasks/wait_for_task_complete.py | 2 +- rmf_demos_tasks/setup.py | 3 ++- 12 files changed, 15 insertions(+), 17 deletions(-) diff --git a/rmf_demos_tasks/rmf_demos_tasks/api_request.py b/rmf_demos_tasks/rmf_demos_tasks/api_request.py index 8a44a219..1454d805 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/api_request.py +++ b/rmf_demos_tasks/rmf_demos_tasks/api_request.py @@ -96,7 +96,7 @@ def main(argv=sys.argv): rclpy.spin_until_future_complete( task_requester, task_requester.response, timeout_sec=5.0) if task_requester.response.done(): - print(f'Got response:\n{task_requester.response.result()}') + print(f'Got response: \n{task_requester.response.result()}') else: print('Did not get a response') rclpy.shutdown() diff --git a/rmf_demos_tasks/rmf_demos_tasks/dispatch_action.py b/rmf_demos_tasks/rmf_demos_tasks/dispatch_action.py index 8fbba6c0..f3412f2d 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/dispatch_action.py +++ b/rmf_demos_tasks/rmf_demos_tasks/dispatch_action.py @@ -218,7 +218,7 @@ def main(argv=sys.argv): task_requester, task_requester.response, timeout_sec=5.0 ) if task_requester.response.done(): - print(f'Got response:\n{task_requester.response.result()}') + print(f'Got response: \n{task_requester.response.result()}') else: print('Did not get a response') rclpy.shutdown() diff --git a/rmf_demos_tasks/rmf_demos_tasks/dispatch_cart_delivery.py b/rmf_demos_tasks/rmf_demos_tasks/dispatch_cart_delivery.py index 5c4dc8a1..51dc4292 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/dispatch_cart_delivery.py +++ b/rmf_demos_tasks/rmf_demos_tasks/dispatch_cart_delivery.py @@ -166,7 +166,7 @@ def main(argv=sys.argv): rclpy.spin_until_future_complete( task_requester, task_requester.response, timeout_sec=5.0) if task_requester.response.done(): - print(f'Got response:\n{task_requester.response.result()}') + print(f'Got response: \n{task_requester.response.result()}') else: print('Did not get a response') rclpy.shutdown() diff --git a/rmf_demos_tasks/rmf_demos_tasks/dispatch_clean.py b/rmf_demos_tasks/rmf_demos_tasks/dispatch_clean.py index bb38cca9..9420c2cb 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/dispatch_clean.py +++ b/rmf_demos_tasks/rmf_demos_tasks/dispatch_clean.py @@ -193,7 +193,7 @@ def main(argv=sys.argv): task_requester, task_requester.response, timeout_sec=5.0 ) if task_requester.response.done(): - print(f'Got response:\n{task_requester.response.result()}') + print(f'Got response: \n{task_requester.response.result()}') else: print('Did not get a response') rclpy.shutdown() diff --git a/rmf_demos_tasks/rmf_demos_tasks/dispatch_delivery.py b/rmf_demos_tasks/rmf_demos_tasks/dispatch_delivery.py index a6b9c127..83f3599d 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/dispatch_delivery.py +++ b/rmf_demos_tasks/rmf_demos_tasks/dispatch_delivery.py @@ -286,7 +286,7 @@ def main(argv=sys.argv): task_requester, task_requester.response, timeout_sec=5.0 ) if task_requester.response.done(): - print(f'Got response:\n{task_requester.response.result()}') + print(f'Got response: \n{task_requester.response.result()}') else: print('Did not get a response') rclpy.shutdown() diff --git a/rmf_demos_tasks/rmf_demos_tasks/dispatch_go_to_place.py b/rmf_demos_tasks/rmf_demos_tasks/dispatch_go_to_place.py index 3c30251e..a42de84a 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/dispatch_go_to_place.py +++ b/rmf_demos_tasks/rmf_demos_tasks/dispatch_go_to_place.py @@ -197,7 +197,7 @@ def main(argv=sys.argv): task_requester, task_requester.response, timeout_sec=5.0 ) if task_requester.response.done(): - print(f'Got response:\n{task_requester.response.result()}') + print(f'Got response: \n{task_requester.response.result()}') else: print('Did not get a response') rclpy.shutdown() diff --git a/rmf_demos_tasks/rmf_demos_tasks/dispatch_json.py b/rmf_demos_tasks/rmf_demos_tasks/dispatch_json.py index 402ade34..1863c9a0 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/dispatch_json.py +++ b/rmf_demos_tasks/rmf_demos_tasks/dispatch_json.py @@ -154,7 +154,7 @@ def main(argv=sys.argv): rclpy.spin_until_future_complete( task_requester, task_requester.response, timeout_sec=5.0) if task_requester.response.done(): - print(f'Got response:\n{task_requester.response.result()}') + print(f'Got response: \n{task_requester.response.result()}') else: print('Did not get a response') rclpy.shutdown() diff --git a/rmf_demos_tasks/rmf_demos_tasks/dispatch_patrol.py b/rmf_demos_tasks/rmf_demos_tasks/dispatch_patrol.py index 0ad6bfdc..f86b68d0 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/dispatch_patrol.py +++ b/rmf_demos_tasks/rmf_demos_tasks/dispatch_patrol.py @@ -173,7 +173,7 @@ def main(argv=sys.argv): task_requester, task_requester.response, timeout_sec=5.0 ) if task_requester.response.done(): - print(f'Got response:\n{task_requester.response.result()}') + print(f'Got response: \n{task_requester.response.result()}') else: print('Did not get a response') rclpy.shutdown() diff --git a/rmf_demos_tasks/rmf_demos_tasks/dispatch_teleop.py b/rmf_demos_tasks/rmf_demos_tasks/dispatch_teleop.py index de6a4961..a6fe04a5 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/dispatch_teleop.py +++ b/rmf_demos_tasks/rmf_demos_tasks/dispatch_teleop.py @@ -178,7 +178,7 @@ def main(argv=sys.argv): task_requester, task_requester.response, timeout_sec=5.0 ) if task_requester.response.done(): - print(f'Got response:\n{task_requester.response.result()}') + print(f'Got response: \n{task_requester.response.result()}') else: print('Did not get a response') rclpy.shutdown() diff --git a/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py b/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py index 9c8be7c0..131cc8fb 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py +++ b/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py @@ -16,20 +16,17 @@ import argparse import asyncio -import json import sys -import uuid +import time import rclpy from rclpy.node import Node -from rclpy.parameter import Parameter from rclpy.qos import QoSDurabilityPolicy as Durability from rclpy.qos import QoSHistoryPolicy as History from rclpy.qos import QoSProfile from rclpy.qos import QoSReliabilityPolicy as Reliability -from rmf_fleet_msgs.msg import FleetState from rmf_building_map_msgs.msg import Graph -import time +from rmf_fleet_msgs.msg import FleetState class RobotStateObserver(Node): @@ -134,7 +131,7 @@ def main(argv=sys.argv): task_requester, task_requester.response, timeout_sec=arguments.timeout ) if task_requester.response.done(): - print(f'Got response:\n{task_requester.response.result()}') + print(f'Got response: \n{task_requester.response.result()}') end_time = time.time() elapsed = end_time - start_time print(f"elapsed time: {elapsed}") diff --git a/rmf_demos_tasks/rmf_demos_tasks/wait_for_task_complete.py b/rmf_demos_tasks/rmf_demos_tasks/wait_for_task_complete.py index 31514a1a..8c3d2278 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/wait_for_task_complete.py +++ b/rmf_demos_tasks/rmf_demos_tasks/wait_for_task_complete.py @@ -94,7 +94,7 @@ def main(argv=sys.argv): task_requester, task_requester.response, timeout_sec=arguments.timeout ) if task_requester.response.done(): - print(f'Got response:\n{task_requester.response.result()}') + print(f'Got response: \n{task_requester.response.result()}') end_time = time.time() elapsed = end_time - start_time print(f"elapsed time: {elapsed}") diff --git a/rmf_demos_tasks/setup.py b/rmf_demos_tasks/setup.py index 5ca8fe45..fad34ff2 100644 --- a/rmf_demos_tasks/setup.py +++ b/rmf_demos_tasks/setup.py @@ -41,7 +41,8 @@ 'teleop_robot = rmf_demos_tasks.teleop_robot:main', 'dispatch_json = rmf_demos_tasks.dispatch_json:main', 'api_request = rmf_demos_tasks.api_request:main', - 'wait_for_task_complete = rmf_demos_tasks.wait_for_task_complete:main' + 'wait_for_task_complete = \ + rmf_demos_tasks.wait_for_task_complete:main' ], }, ) From 3e20443e9c3cbbb8f8717846eec411c0deaceabe Mon Sep 17 00:00:00 2001 From: "Michael X. Grey" Date: Thu, 14 Nov 2024 06:30:49 +0000 Subject: [PATCH 18/21] Fix immediate mode for get_robot_location Signed-off-by: Michael X. Grey --- rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py b/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py index 131cc8fb..a591d6e7 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py +++ b/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py @@ -62,7 +62,6 @@ def __init__(self, parser): self.nav_graph = None def state_watcher(self, fleet_state: FleetState): - if self.nav_graph is None: print("Nav graph not found") return @@ -76,7 +75,7 @@ def state_watcher(self, fleet_state: FleetState): dist += (graph_node.y - robot_state.location.y) ** 2 name = graph_node.name if dist < 0.5: - if self.parser.block_until_reaches == "": + if not self.parser.block_until_reaches: self.response.set_result(name) elif self.parser.block_until_reaches == name: self.response.set_result(name) From ac634db9c5902ab95d88dda3210b23293b0504df Mon Sep 17 00:00:00 2001 From: "Michael X. Grey" Date: Thu, 14 Nov 2024 09:04:15 +0000 Subject: [PATCH 19/21] Merge the reservation office demo into the usual office demo Signed-off-by: Michael X. Grey --- rmf_demos/config/office/tinyRobot_config.yaml | 6 +-- .../tinyRobot_config.yaml | 48 ------------------- rmf_demos/launch/office.launch.xml | 1 + .../launch/office_reservation_node.launch.xml | 23 --------- 4 files changed, 4 insertions(+), 74 deletions(-) delete mode 100644 rmf_demos/config/office_reservation_node/tinyRobot_config.yaml delete mode 100644 rmf_demos/launch/office_reservation_node.launch.xml diff --git a/rmf_demos/config/office/tinyRobot_config.yaml b/rmf_demos/config/office/tinyRobot_config.yaml index 75d53a75..4f4d5ac5 100644 --- a/rmf_demos/config/office/tinyRobot_config.yaml +++ b/rmf_demos/config/office/tinyRobot_config.yaml @@ -30,13 +30,13 @@ rmf_fleet: loop: True delivery: True actions: ["teleop"] - finishing_request: "park" # [park, charge, nothing] - responsive_wait: True # Should responsive wait be on/off for the whole fleet by default? False if not specified. + finishing_request: "charge" # [park, charge, nothing] + responsive_wait: False # Should responsive wait be on/off for the whole fleet by default? False if not specified. + use_parking_reservations: True reassign_task_interval: 120 # seconds, specify how often a task reassignment should be triggered in the fleet robots: tinyRobot1: charger: "tinyRobot1_charger" - responsive_wait: False # Should responsive wait be on/off for this specific robot? Overrides the fleet-wide setting. tinyRobot2: charger: "tinyRobot2_charger" # No mention of responsive_wait means the fleet-wide setting will be used diff --git a/rmf_demos/config/office_reservation_node/tinyRobot_config.yaml b/rmf_demos/config/office_reservation_node/tinyRobot_config.yaml deleted file mode 100644 index 43fd85d2..00000000 --- a/rmf_demos/config/office_reservation_node/tinyRobot_config.yaml +++ /dev/null @@ -1,48 +0,0 @@ -# FLEET CONFIG ================================================================= -# RMF Fleet parameters - -rmf_fleet: - name: "tinyRobot" - limits: - linear: [0.5, 0.75] # velocity, acceleration - angular: [0.6, 2.0] # velocity, acceleration - profile: # Robot profile is modelled as a circle - footprint: 0.3 # radius in m - vicinity: 0.5 # radius in m - reversible: True # whether robots in this fleet can reverse - battery_system: - voltage: 12.0 # V - capacity: 24.0 # Ahr - charging_current: 5.0 # A - mechanical_system: - mass: 20.0 # kg - moment_of_inertia: 10.0 #kgm^2 - friction_coefficient: 0.22 - ambient_system: - power: 20.0 # W - tool_system: - power: 0.0 # W - recharge_threshold: 0.10 # Battery level below which robots in this fleet will not operate - recharge_soc: 1.0 # Battery level to which robots in this fleet should be charged up to during recharging tasks - publish_fleet_state: 10.0 # Publish frequency for fleet state, ensure that it is same as robot_state_update_frequency - account_for_battery_drain: True - task_capabilities: # Specify the types of RMF Tasks that robots in this fleet are capable of performing - loop: True - delivery: True - actions: ["teleop"] - finishing_request: "nothing" # [park, charge, nothing] - responsive_wait: False # Should responsive wait be on/off for the whole fleet by default? False if not specified. - use_parking_reservations: True - reassign_task_interval: 120 # seconds, specify how often a task reassignment should be triggered in the fleet - robots: - tinyRobot1: - charger: "tinyRobot1_charger" - tinyRobot2: - charger: "tinyRobot2_charger" - # No mention of responsive_wait means the fleet-wide setting will be used - -fleet_manager: - ip: "127.0.0.1" - port: 22011 - user: "some_user" - password: "some_password" diff --git a/rmf_demos/launch/office.launch.xml b/rmf_demos/launch/office.launch.xml index 6895dcee..26317842 100644 --- a/rmf_demos/launch/office.launch.xml +++ b/rmf_demos/launch/office.launch.xml @@ -8,6 +8,7 @@ + diff --git a/rmf_demos/launch/office_reservation_node.launch.xml b/rmf_demos/launch/office_reservation_node.launch.xml deleted file mode 100644 index 284fa6db..00000000 --- a/rmf_demos/launch/office_reservation_node.launch.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - From 9d98b9553fa2e47d0b829f2f3ac12ecdb2dcbc83 Mon Sep 17 00:00:00 2001 From: "Michael X. Grey" Date: Thu, 14 Nov 2024 09:41:44 +0000 Subject: [PATCH 20/21] Satisfy flake8 Signed-off-by: Michael X. Grey --- rmf_demos_tasks/rmf_demos_tasks/__init__.py | 1 + .../rmf_demos_tasks/api_request.py | 4 +++ .../rmf_demos_tasks/cancel_task.py | 5 ++++ .../rmf_demos_tasks/dispatch_action.py | 5 ++++ .../rmf_demos_tasks/dispatch_cart_delivery.py | 4 +++ .../rmf_demos_tasks/dispatch_clean.py | 5 ++++ .../rmf_demos_tasks/dispatch_delivery.py | 5 ++++ .../rmf_demos_tasks/dispatch_go_to_place.py | 5 ++++ .../rmf_demos_tasks/dispatch_json.py | 4 +++ .../rmf_demos_tasks/dispatch_loop.py | 7 +++++ .../rmf_demos_tasks/dispatch_patrol.py | 5 ++++ .../rmf_demos_tasks/dispatch_teleop.py | 5 ++++ .../rmf_demos_tasks/get_robot_location.py | 19 +++++++++---- .../rmf_demos_tasks/mock_docker.py | 9 +++++++ .../rmf_demos_tasks/request_lift.py | 6 ++++- .../rmf_demos_tasks/request_loop.py | 6 +++++ .../rmf_demos_tasks/teleop_robot.py | 5 ++++ .../rmf_demos_tasks/wait_for_task_complete.py | 27 ++++++++++--------- rmf_demos_tasks/setup.py | 1 + rmf_demos_tasks/test/__init__.py | 1 + rmf_demos_tasks/test/test_copyright.py | 3 +++ rmf_demos_tasks/test/test_flake8.py | 3 +++ rmf_demos_tasks/test/test_pep257.py | 3 +++ 23 files changed, 119 insertions(+), 19 deletions(-) diff --git a/rmf_demos_tasks/rmf_demos_tasks/__init__.py b/rmf_demos_tasks/rmf_demos_tasks/__init__.py index e69de29b..114fa77c 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/__init__.py +++ b/rmf_demos_tasks/rmf_demos_tasks/__init__.py @@ -0,0 +1 @@ +"""Scripts for issuing tasks to Open-RMF from the command line.""" diff --git a/rmf_demos_tasks/rmf_demos_tasks/api_request.py b/rmf_demos_tasks/rmf_demos_tasks/api_request.py index 1454d805..6e4cf7ee 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/api_request.py +++ b/rmf_demos_tasks/rmf_demos_tasks/api_request.py @@ -13,6 +13,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""Send a generic API request.""" import argparse import asyncio @@ -32,8 +33,10 @@ ############################################################################### class ApiRequester(Node): + """API requester.""" def __init__(self, argv=sys.argv): + """Initialize an API requester.""" super().__init__('task_requester') parser = argparse.ArgumentParser() parser.add_argument( @@ -89,6 +92,7 @@ def receive_response(response_msg: ApiResponse): def main(argv=sys.argv): + """Send a generic API request.""" rclpy.init(args=sys.argv) args_without_ros = rclpy.utilities.remove_ros_args(sys.argv) diff --git a/rmf_demos_tasks/rmf_demos_tasks/cancel_task.py b/rmf_demos_tasks/rmf_demos_tasks/cancel_task.py index 3ca14153..598078b1 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/cancel_task.py +++ b/rmf_demos_tasks/rmf_demos_tasks/cancel_task.py @@ -13,6 +13,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""Cancel a task.""" import argparse import json @@ -25,14 +26,17 @@ from rclpy.qos import QoSHistoryPolicy as History from rclpy.qos import QoSProfile from rclpy.qos import QoSReliabilityPolicy as Reliability + from rmf_task_msgs.msg import ApiRequest ############################################################################### class TaskRequester(Node): + """Task requester.""" def __init__(self, argv=sys.argv): + """Initialize a task requester.""" super().__init__('task_requester') parser = argparse.ArgumentParser() parser.add_argument( @@ -73,6 +77,7 @@ def __init__(self, argv=sys.argv): def main(argv=sys.argv): + """Cancel a task.""" rclpy.init(args=sys.argv) args_without_ros = rclpy.utilities.remove_ros_args(sys.argv) diff --git a/rmf_demos_tasks/rmf_demos_tasks/dispatch_action.py b/rmf_demos_tasks/rmf_demos_tasks/dispatch_action.py index f3412f2d..33d4be0b 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/dispatch_action.py +++ b/rmf_demos_tasks/rmf_demos_tasks/dispatch_action.py @@ -13,6 +13,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""Dispatch an action.""" import argparse import asyncio @@ -27,6 +28,7 @@ from rclpy.qos import QoSHistoryPolicy as History from rclpy.qos import QoSProfile from rclpy.qos import QoSReliabilityPolicy as Reliability + from rmf_task_msgs.msg import ApiRequest from rmf_task_msgs.msg import ApiResponse @@ -34,8 +36,10 @@ class TaskRequester(Node): + """Task requester.""" def __init__(self, argv=sys.argv): + """Initialize a task requester.""" super().__init__('task_requester') parser = argparse.ArgumentParser() parser.add_argument( @@ -210,6 +214,7 @@ def receive_response(response_msg: ApiResponse): def main(argv=sys.argv): + """Dispatch an action.""" rclpy.init(args=sys.argv) args_without_ros = rclpy.utilities.remove_ros_args(sys.argv) diff --git a/rmf_demos_tasks/rmf_demos_tasks/dispatch_cart_delivery.py b/rmf_demos_tasks/rmf_demos_tasks/dispatch_cart_delivery.py index 51dc4292..acf25a52 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/dispatch_cart_delivery.py +++ b/rmf_demos_tasks/rmf_demos_tasks/dispatch_cart_delivery.py @@ -13,6 +13,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""Dispatch a cart delivery.""" import argparse import asyncio @@ -34,8 +35,10 @@ ############################################################################### class TaskRequester(Node): + """Task requester.""" def __init__(self, argv=sys.argv): + """Initialize a task requester.""" super().__init__('task_requester') parser = argparse.ArgumentParser() parser.add_argument('-p', '--pickup', required=True, @@ -159,6 +162,7 @@ def receive_response(response_msg: ApiResponse): def main(argv=sys.argv): + """Dispatch a cart delivery.""" rclpy.init(args=sys.argv) args_without_ros = rclpy.utilities.remove_ros_args(sys.argv) diff --git a/rmf_demos_tasks/rmf_demos_tasks/dispatch_clean.py b/rmf_demos_tasks/rmf_demos_tasks/dispatch_clean.py index 9420c2cb..11b4bc47 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/dispatch_clean.py +++ b/rmf_demos_tasks/rmf_demos_tasks/dispatch_clean.py @@ -13,6 +13,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""Dispatch a cleaning.""" import argparse import asyncio @@ -27,6 +28,7 @@ from rclpy.qos import QoSHistoryPolicy as History from rclpy.qos import QoSProfile from rclpy.qos import QoSReliabilityPolicy as Reliability + from rmf_task_msgs.msg import ApiRequest from rmf_task_msgs.msg import ApiResponse @@ -34,8 +36,10 @@ class TaskRequester(Node): + """Task requester.""" def __init__(self, argv=sys.argv): + """Initialize a task requester.""" super().__init__('task_requester') parser = argparse.ArgumentParser() parser.add_argument( @@ -185,6 +189,7 @@ def receive_response(response_msg: ApiResponse): def main(argv=sys.argv): + """Dispatch a cleaning.""" rclpy.init(args=sys.argv) args_without_ros = rclpy.utilities.remove_ros_args(sys.argv) diff --git a/rmf_demos_tasks/rmf_demos_tasks/dispatch_delivery.py b/rmf_demos_tasks/rmf_demos_tasks/dispatch_delivery.py index 83f3599d..94ea8280 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/dispatch_delivery.py +++ b/rmf_demos_tasks/rmf_demos_tasks/dispatch_delivery.py @@ -13,6 +13,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""Dispatch a delivery.""" import argparse import asyncio @@ -27,6 +28,7 @@ from rclpy.qos import QoSHistoryPolicy as History from rclpy.qos import QoSProfile from rclpy.qos import QoSReliabilityPolicy as Reliability + from rmf_task_msgs.msg import ApiRequest from rmf_task_msgs.msg import ApiResponse @@ -34,8 +36,10 @@ class TaskRequester(Node): + """Task requester.""" def __init__(self, argv=sys.argv): + """Initialize a task requester.""" super().__init__('task_requester') parser = argparse.ArgumentParser() parser.add_argument( @@ -278,6 +282,7 @@ def receive_response(response_msg: ApiResponse): def main(argv=sys.argv): + """Dispatch a delivery.""" rclpy.init(args=sys.argv) args_without_ros = rclpy.utilities.remove_ros_args(sys.argv) diff --git a/rmf_demos_tasks/rmf_demos_tasks/dispatch_go_to_place.py b/rmf_demos_tasks/rmf_demos_tasks/dispatch_go_to_place.py index a42de84a..f8b4a583 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/dispatch_go_to_place.py +++ b/rmf_demos_tasks/rmf_demos_tasks/dispatch_go_to_place.py @@ -13,6 +13,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""Go to place.""" import argparse import asyncio @@ -28,6 +29,7 @@ from rclpy.qos import QoSHistoryPolicy as History from rclpy.qos import QoSProfile from rclpy.qos import QoSReliabilityPolicy as Reliability + from rmf_task_msgs.msg import ApiRequest from rmf_task_msgs.msg import ApiResponse @@ -35,8 +37,10 @@ class TaskRequester(Node): + """Task requester.""" def __init__(self, argv=sys.argv): + """Initialize a task requester.""" super().__init__('task_requester') parser = argparse.ArgumentParser() parser.add_argument('-F', '--fleet', type=str, help='Fleet name') @@ -189,6 +193,7 @@ def receive_response(response_msg: ApiResponse): def main(argv=sys.argv): + """Go to place.""" rclpy.init(args=sys.argv) args_without_ros = rclpy.utilities.remove_ros_args(sys.argv) diff --git a/rmf_demos_tasks/rmf_demos_tasks/dispatch_json.py b/rmf_demos_tasks/rmf_demos_tasks/dispatch_json.py index 1863c9a0..6d75286e 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/dispatch_json.py +++ b/rmf_demos_tasks/rmf_demos_tasks/dispatch_json.py @@ -13,6 +13,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""Dispatch any json task description.""" import argparse import asyncio @@ -34,8 +35,10 @@ ############################################################################### class TaskRequester(Node): + """Task requester.""" def __init__(self, argv=sys.argv): + """Initialize a task requester.""" super().__init__('task_requester') parser = argparse.ArgumentParser() parser.add_argument( @@ -147,6 +150,7 @@ def receive_response(response_msg: ApiResponse): def main(argv=sys.argv): + """Dispatch any json task description.""" rclpy.init(args=sys.argv) args_without_ros = rclpy.utilities.remove_ros_args(sys.argv) diff --git a/rmf_demos_tasks/rmf_demos_tasks/dispatch_loop.py b/rmf_demos_tasks/rmf_demos_tasks/dispatch_loop.py index d0ad6503..af552026 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/dispatch_loop.py +++ b/rmf_demos_tasks/rmf_demos_tasks/dispatch_loop.py @@ -13,12 +13,14 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""Dispatch a loop task.""" import argparse import sys import rclpy from rclpy.parameter import Parameter + from rmf_task_msgs.msg import Loop from rmf_task_msgs.msg import TaskType from rmf_task_msgs.srv import SubmitTask @@ -27,8 +29,10 @@ class TaskRequester: + """Task requester.""" def __init__(self, argv=sys.argv): + """Initialize a task requester.""" parser = argparse.ArgumentParser() parser.add_argument( '-s', '--start', required=True, type=str, help='Start waypoint' @@ -80,6 +84,7 @@ def __init__(self, argv=sys.argv): self.node.set_parameters([param]) def generate_task_req_msg(self): + """Generate a task request message.""" req_msg = SubmitTask.Request() req_msg.description.task_type.type = TaskType.TYPE_LOOP @@ -97,6 +102,7 @@ def generate_task_req_msg(self): return req_msg def main(self): + """Dispatch a loop task.""" if not self.submit_task_srv.wait_for_service(timeout_sec=3.0): self.node.get_logger().error('Dispatcher Node is not available') return @@ -131,6 +137,7 @@ def main(self): def main(argv=sys.argv): + """Dispatch a loop task.""" rclpy.init(args=sys.argv) args_without_ros = rclpy.utilities.remove_ros_args(sys.argv) diff --git a/rmf_demos_tasks/rmf_demos_tasks/dispatch_patrol.py b/rmf_demos_tasks/rmf_demos_tasks/dispatch_patrol.py index f86b68d0..356fbdd6 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/dispatch_patrol.py +++ b/rmf_demos_tasks/rmf_demos_tasks/dispatch_patrol.py @@ -13,6 +13,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""Dispatch a patrol task.""" import argparse import asyncio @@ -27,6 +28,7 @@ from rclpy.qos import QoSHistoryPolicy as History from rclpy.qos import QoSProfile from rclpy.qos import QoSReliabilityPolicy as Reliability + from rmf_task_msgs.msg import ApiRequest from rmf_task_msgs.msg import ApiResponse @@ -34,8 +36,10 @@ class TaskRequester(Node): + """Dispatch patrol task requester.""" def __init__(self, argv=sys.argv): + """Initialize task requester.""" super().__init__('task_requester') parser = argparse.ArgumentParser() parser.add_argument( @@ -165,6 +169,7 @@ def receive_response(response_msg: ApiResponse): def main(argv=sys.argv): + """Dispatch a patrol task.""" rclpy.init(args=sys.argv) args_without_ros = rclpy.utilities.remove_ros_args(sys.argv) diff --git a/rmf_demos_tasks/rmf_demos_tasks/dispatch_teleop.py b/rmf_demos_tasks/rmf_demos_tasks/dispatch_teleop.py index a6fe04a5..fd1d62d4 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/dispatch_teleop.py +++ b/rmf_demos_tasks/rmf_demos_tasks/dispatch_teleop.py @@ -13,6 +13,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""Dispatch a teleop task.""" import argparse import asyncio @@ -27,6 +28,7 @@ from rclpy.qos import QoSHistoryPolicy as History from rclpy.qos import QoSProfile from rclpy.qos import QoSReliabilityPolicy as Reliability + from rmf_task_msgs.msg import ApiRequest from rmf_task_msgs.msg import ApiResponse @@ -34,8 +36,10 @@ class TaskRequester(Node): + """Task requester.""" def __init__(self, argv=sys.argv): + """Initialize task requester.""" super().__init__('task_requester') parser = argparse.ArgumentParser() parser.add_argument( @@ -170,6 +174,7 @@ def receive_response(response_msg: ApiResponse): def main(argv=sys.argv): + """Dispatch a teleop task.""" rclpy.init(args=sys.argv) args_without_ros = rclpy.utilities.remove_ros_args(sys.argv) diff --git a/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py b/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py index a591d6e7..cba9515f 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py +++ b/rmf_demos_tasks/rmf_demos_tasks/get_robot_location.py @@ -13,6 +13,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""Get the location of a robot.""" import argparse import asyncio @@ -25,18 +26,22 @@ from rclpy.qos import QoSHistoryPolicy as History from rclpy.qos import QoSProfile from rclpy.qos import QoSReliabilityPolicy as Reliability + from rmf_building_map_msgs.msg import Graph + from rmf_fleet_msgs.msg import FleetState class RobotStateObserver(Node): """ - This is a tool that should be used only for testing purpose! Do not - use it in production. + This is a tool that should be used only for testing purpose. + + Do not use it in production! """ def __init__(self, parser): - super().__init__("TaskObserver") + """Initialize the observer.""" + super().__init__('TaskObserver') self.parser = parser self.response = asyncio.Future() @@ -62,8 +67,9 @@ def __init__(self, parser): self.nav_graph = None def state_watcher(self, fleet_state: FleetState): + """Watch the fleet state.""" if self.nav_graph is None: - print("Nav graph not found") + print('Nav graph not found') return if fleet_state.name != self.parser.fleet: @@ -82,11 +88,13 @@ def state_watcher(self, fleet_state: FleetState): return def nav_graph_watcher(self, navgraph: Graph): + """Watch the nav graph.""" if navgraph.name == self.parser.fleet: self.nav_graph = navgraph def create_parser(): + """Create the parser.""" parser = argparse.ArgumentParser() parser.add_argument( @@ -120,6 +128,7 @@ def create_parser(): def main(argv=sys.argv): + """Get a robot location.""" rclpy.init(args=sys.argv) args_without_ros = rclpy.utilities.remove_ros_args(sys.argv) arg_parser = create_parser() @@ -133,7 +142,7 @@ def main(argv=sys.argv): print(f'Got response: \n{task_requester.response.result()}') end_time = time.time() elapsed = end_time - start_time - print(f"elapsed time: {elapsed}") + print(f'elapsed time: {elapsed}') else: print('Timed out') sys.exit(-1) diff --git a/rmf_demos_tasks/rmf_demos_tasks/mock_docker.py b/rmf_demos_tasks/rmf_demos_tasks/mock_docker.py index f03afe19..9f93ffa7 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/mock_docker.py +++ b/rmf_demos_tasks/rmf_demos_tasks/mock_docker.py @@ -11,6 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""Mock docker.""" import argparse import math @@ -23,6 +24,7 @@ from rclpy.qos import QoSHistoryPolicy as History from rclpy.qos import QoSProfile from rclpy.qos import QoSReliabilityPolicy as Reliability + from rmf_fleet_msgs.msg import Dock from rmf_fleet_msgs.msg import DockParameter from rmf_fleet_msgs.msg import DockSummary @@ -31,10 +33,12 @@ from rmf_fleet_msgs.msg import PathRequest from rmf_fleet_msgs.msg import RobotMode from rmf_fleet_msgs.msg import RobotState + import yaml def make_location(p, level_name): + """Make location.""" location = Location() location.x = p[0] location.y = p[1] @@ -44,6 +48,7 @@ def make_location(p, level_name): def close(l0: Location, l1: Location): + """Are the locations close.""" x_2 = (l1.x - l0.x) ** 2 y_2 = (l1.y - l0.y) ** 2 dist = math.sqrt(x_2 + y_2) @@ -71,6 +76,7 @@ class MockDocker(Node): """ def __init__(self, config_yaml): + """Initialize the mock docker.""" super().__init__('mock_docker') self.get_logger().info('Greetings, I am mock docker') self.config_yaml = config_yaml @@ -131,6 +137,7 @@ def __init__(self, config_yaml): self.dock_summary_publisher.publish(dock_summary) def mode_request_cb(self, msg: ModeRequest): + """React to a mode request.""" if msg.mode.mode != RobotMode.MODE_DOCKING: return @@ -173,6 +180,7 @@ def mode_request_cb(self, msg: ModeRequest): self.path_request_publisher.publish(path_request) def robot_state_cb(self, msg: RobotState): + """React to a new robot state.""" robot_name = msg.name if robot_name not in self.watching: return @@ -201,6 +209,7 @@ def robot_state_cb(self, msg: RobotState): def main(argv=sys.argv): + """Mock docker.""" rclpy.init(args=argv) args_without_ros = rclpy.utilities.remove_ros_args(argv) parser = argparse.ArgumentParser( diff --git a/rmf_demos_tasks/rmf_demos_tasks/request_lift.py b/rmf_demos_tasks/rmf_demos_tasks/request_lift.py index bdbab30d..9d0f5374 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/request_lift.py +++ b/rmf_demos_tasks/rmf_demos_tasks/request_lift.py @@ -11,16 +11,19 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""Request a lift to move somewhere.""" import sys -from time import sleep import uuid +from time import sleep import rclpy + from rmf_lift_msgs.msg import LiftRequest def print_instructions(): + """Print instructions.""" print( 'Invalid number of arguments, please pass in lift_name, desired ', 'level and door state after the script in that order, only supports', @@ -34,6 +37,7 @@ def print_instructions(): def main(argv=sys.argv): + """Request a lift to move somewhere.""" rclpy.init(args=argv) if len(argv) != 4: diff --git a/rmf_demos_tasks/rmf_demos_tasks/request_loop.py b/rmf_demos_tasks/rmf_demos_tasks/request_loop.py index e8965335..26d02d3f 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/request_loop.py +++ b/rmf_demos_tasks/rmf_demos_tasks/request_loop.py @@ -13,6 +13,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""Request a loop.""" import argparse import sys @@ -20,12 +21,15 @@ import uuid import rclpy + from rmf_task_msgs.msg import Loop class LoopRequester: + """Request a loop.""" def __init__(self, argv=sys.argv): + """Request a loop.""" parser = argparse.ArgumentParser() parser.add_argument('-s', '--start', help='Start waypoint') parser.add_argument('-f', '--finish', help='Finish waypoint') @@ -59,6 +63,7 @@ def __init__(self, argv=sys.argv): self.publisher = self.node.create_publisher(Loop, 'loop_requests', 10) def main(self): + """Request a loop.""" request = Loop() request.robot_type = self.robot_type request.start_name = self.start_wp @@ -80,6 +85,7 @@ def main(self): def main(argv=sys.argv): + """Request a loop.""" rclpy.init(args=sys.argv) args_without_ros = rclpy.utilities.remove_ros_args(sys.argv) diff --git a/rmf_demos_tasks/rmf_demos_tasks/teleop_robot.py b/rmf_demos_tasks/rmf_demos_tasks/teleop_robot.py index 5c2bce11..1339ee46 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/teleop_robot.py +++ b/rmf_demos_tasks/rmf_demos_tasks/teleop_robot.py @@ -13,6 +13,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""Teleop a robot.""" import argparse import asyncio @@ -25,6 +26,7 @@ from rclpy.qos import QoSHistoryPolicy as History from rclpy.qos import QoSProfile from rclpy.qos import QoSReliabilityPolicy as Reliability + from rmf_fleet_msgs.msg import Location from rmf_fleet_msgs.msg import PathRequest @@ -32,8 +34,10 @@ class Requester(Node): + """Teleop requester.""" def __init__(self, argv=sys.argv): + """Initialize the requester.""" super().__init__('teleop_publisher') parser = argparse.ArgumentParser() @@ -87,6 +91,7 @@ def __init__(self, argv=sys.argv): def main(argv=sys.argv): + """Teleop a robot.""" rclpy.init(args=sys.argv) args_without_ros = rclpy.utilities.remove_ros_args(sys.argv) requester = Requester(args_without_ros) diff --git a/rmf_demos_tasks/rmf_demos_tasks/wait_for_task_complete.py b/rmf_demos_tasks/rmf_demos_tasks/wait_for_task_complete.py index 8c3d2278..5f42a03b 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/wait_for_task_complete.py +++ b/rmf_demos_tasks/rmf_demos_tasks/wait_for_task_complete.py @@ -13,31 +13,29 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""Wait for a task to be completed.""" import argparse import asyncio -import json import sys -import uuid +import time import rclpy from rclpy.node import Node -from rclpy.parameter import Parameter -from rclpy.qos import QoSDurabilityPolicy as Durability -from rclpy.qos import QoSHistoryPolicy as History -from rclpy.qos import QoSProfile -from rclpy.qos import QoSReliabilityPolicy as Reliability + from rmf_fleet_msgs.msg import FleetState -import time class TaskObserver(Node): """ - This is a tool that should be used only for testing purpose! Do not - use it in production. + This is a tool that should be used only for testing purpose. + + Do not use it in production! """ + def __init__(self, parser): - super().__init__("TaskObserver") + """Initialize the TaskObserver.""" + super().__init__('TaskObserver') self.parser = parser self.response = asyncio.Future() @@ -49,16 +47,18 @@ def __init__(self, parser): 10) def state_watcher(self, fleet_state: FleetState): + """Watch the fleet state.""" if fleet_state.name != self.parser.fleet: return for robot_state in fleet_state.robots: if robot_state.name == self.parser.robot: - if robot_state.task_id == "": + if robot_state.task_id == '': self.response.set_result(robot_state) return def create_parser(): + """Create the parser for the script.""" parser = argparse.ArgumentParser() parser.add_argument( @@ -84,6 +84,7 @@ def create_parser(): def main(argv=sys.argv): + """Wait for a task to be complete.""" rclpy.init(args=sys.argv) args_without_ros = rclpy.utilities.remove_ros_args(sys.argv) arg_parser = create_parser() @@ -97,7 +98,7 @@ def main(argv=sys.argv): print(f'Got response: \n{task_requester.response.result()}') end_time = time.time() elapsed = end_time - start_time - print(f"elapsed time: {elapsed}") + print(f'elapsed time: {elapsed}') else: print('Timed out') sys.exit(-1) diff --git a/rmf_demos_tasks/setup.py b/rmf_demos_tasks/setup.py index fad34ff2..1b37d322 100644 --- a/rmf_demos_tasks/setup.py +++ b/rmf_demos_tasks/setup.py @@ -1,3 +1,4 @@ +"""A set of scripts to issue tasks to Open-RMF from the command line.""" from setuptools import setup package_name = 'rmf_demos_tasks' diff --git a/rmf_demos_tasks/test/__init__.py b/rmf_demos_tasks/test/__init__.py index e69de29b..9a85a96e 100644 --- a/rmf_demos_tasks/test/__init__.py +++ b/rmf_demos_tasks/test/__init__.py @@ -0,0 +1 @@ +"""Scripts for testing.""" diff --git a/rmf_demos_tasks/test/test_copyright.py b/rmf_demos_tasks/test/test_copyright.py index 361213cd..56ad44f9 100644 --- a/rmf_demos_tasks/test/test_copyright.py +++ b/rmf_demos_tasks/test/test_copyright.py @@ -11,13 +11,16 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""Find copyright errors.""" from ament_copyright.main import main + import pytest @pytest.mark.copyright @pytest.mark.linter def test_copyright(): + """Find copyright errors.""" rc = main(argv=['.', 'test']) assert rc == 0, 'Found errors' diff --git a/rmf_demos_tasks/test/test_flake8.py b/rmf_demos_tasks/test/test_flake8.py index d2e3b59f..47249e0e 100644 --- a/rmf_demos_tasks/test/test_flake8.py +++ b/rmf_demos_tasks/test/test_flake8.py @@ -11,14 +11,17 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""Find flake8 errors.""" from ament_flake8.main import main_with_errors + import pytest @pytest.mark.flake8 @pytest.mark.linter def test_flake8(): + """Find flake8 errors.""" rc, errors = main_with_errors(argv=[]) assert rc == 0, 'Found %d code style errors / warnings:\n' % len( errors diff --git a/rmf_demos_tasks/test/test_pep257.py b/rmf_demos_tasks/test/test_pep257.py index 5300ccf1..892c8a66 100644 --- a/rmf_demos_tasks/test/test_pep257.py +++ b/rmf_demos_tasks/test/test_pep257.py @@ -11,13 +11,16 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""Find PEP 257 errors.""" from ament_pep257.main import main + import pytest @pytest.mark.linter @pytest.mark.pep257 def test_pep257(): + """Find PEP 257 errors.""" rc = main(argv=['.', 'test']) assert rc == 0, 'Found code style errors / warnings' From f0af37d95121038a8c0d7435c26422685ce4e2b2 Mon Sep 17 00:00:00 2001 From: "Michael X. Grey" Date: Thu, 14 Nov 2024 12:38:55 +0000 Subject: [PATCH 21/21] Fix linting tests Signed-off-by: Michael X. Grey --- rmf_demos_tasks/rmf_demos_tasks/__init__.py | 13 +++++++++++++ rmf_demos_tasks/rmf_demos_tasks/request_lift.py | 2 +- rmf_demos_tasks/test/__init__.py | 13 +++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/rmf_demos_tasks/rmf_demos_tasks/__init__.py b/rmf_demos_tasks/rmf_demos_tasks/__init__.py index 114fa77c..366e4313 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/__init__.py +++ b/rmf_demos_tasks/rmf_demos_tasks/__init__.py @@ -1 +1,14 @@ +# Copyright 2024 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. """Scripts for issuing tasks to Open-RMF from the command line.""" diff --git a/rmf_demos_tasks/rmf_demos_tasks/request_lift.py b/rmf_demos_tasks/rmf_demos_tasks/request_lift.py index 9d0f5374..4ae0ad89 100644 --- a/rmf_demos_tasks/rmf_demos_tasks/request_lift.py +++ b/rmf_demos_tasks/rmf_demos_tasks/request_lift.py @@ -14,8 +14,8 @@ """Request a lift to move somewhere.""" import sys -import uuid from time import sleep +import uuid import rclpy diff --git a/rmf_demos_tasks/test/__init__.py b/rmf_demos_tasks/test/__init__.py index 9a85a96e..6627fabb 100644 --- a/rmf_demos_tasks/test/__init__.py +++ b/rmf_demos_tasks/test/__init__.py @@ -1 +1,14 @@ +# Copyright 2024 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. """Scripts for testing."""