diff --git a/.rosinstall b/.rosinstall index 43cc7e9b8..17d75d6c7 100644 --- a/.rosinstall +++ b/.rosinstall @@ -18,6 +18,11 @@ uri: https://github.com/ignc-research/stable-baselines3 version: master +- git: + local-name: ../forks/marl/stable-baselines3 + uri: https://github.com/ignc-research/stable-baselines3 + version: marl + - git: local-name: ../forks/navigation/local_planner/teb uri: https://github.com/rst-tu-dortmund/teb_local_planner diff --git a/HPP/model/model.py b/HPP/model/model.py new file mode 100644 index 000000000..e69de29bb diff --git a/HPP/record.py b/HPP/record.py new file mode 100644 index 000000000..193803975 --- /dev/null +++ b/HPP/record.py @@ -0,0 +1,16 @@ +from arena_marl.marl_agent.utils.supersuit_utils import MarkovVectorEnv_patched + + +def store_data(): + """ + Store data in a csv file + """ + + +class Env_Recorder(MarkovVectorEnv_patched): + """ + A wrapper for the environment that records the state and action + """ + + def __init__(self): + super(Env_Recorder, self).step(self, actions) diff --git a/HPP/train.py b/HPP/train.py new file mode 100644 index 000000000..e69de29bb diff --git a/arena_bringup/launch/marl_start_flatland.launch b/arena_bringup/launch/marl_start_flatland.launch new file mode 100644 index 000000000..7dacf4f69 --- /dev/null +++ b/arena_bringup/launch/marl_start_flatland.launch @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/arena_bringup/launch/marl_start_training.launch b/arena_bringup/launch/marl_start_training.launch new file mode 100644 index 000000000..5b27d17e0 --- /dev/null +++ b/arena_bringup/launch/marl_start_training.launch @@ -0,0 +1,215 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/arena_bringup/launch/start_arena_flatland.launch b/arena_bringup/launch/start_arena_flatland.launch index 2aac3af96..e026cb07b 100755 --- a/arena_bringup/launch/start_arena_flatland.launch +++ b/arena_bringup/launch/start_arena_flatland.launch @@ -38,7 +38,7 @@ - + diff --git a/arena_bringup/launch/sublaunch_training/marl_fake_localization.launch b/arena_bringup/launch/sublaunch_training/marl_fake_localization.launch new file mode 100644 index 000000000..e3d5ed46c --- /dev/null +++ b/arena_bringup/launch/sublaunch_training/marl_fake_localization.launch @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/arena_bringup/launch/sublaunch_training/marl_single_env_training.launch b/arena_bringup/launch/sublaunch_training/marl_single_env_training.launch new file mode 100644 index 000000000..4a0eb1add --- /dev/null +++ b/arena_bringup/launch/sublaunch_training/marl_single_env_training.launch @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/arena_bringup/rviz/nav_LP_2.rviz b/arena_bringup/rviz/nav_LP_2.rviz new file mode 100644 index 000000000..efb888592 --- /dev/null +++ b/arena_bringup/rviz/nav_LP_2.rviz @@ -0,0 +1,1039 @@ +Panels: + - Class: rviz/Displays + Help Height: 84 + Name: Displays + Property Tree Widget: + Expanded: + - /Map1 + - /obstacles1 + - /Plan Manager1/subgoal1 + - /Tracking-Visuals1/TrackedPersons1 + - /Tracking-Visuals1/TrackedPersons1/History as line1 + - /Tracking-Visuals1/TrackedGroups1 + - /AIO1/Dynamic Scan1 + - /Agent path taken1 + Splitter Ratio: 0.4374079406261444 + Tree Height: 357 + - Class: rviz/Selection + Name: Selection + - Class: rviz/Tool Properties + Expanded: + - /2D Pose Estimate1 + - /2D Nav Goal1 + - /Publish Point1 + Name: Tool Properties + Splitter Ratio: 0.4285709857940674 + - Class: rviz/Views + Expanded: + - /Current View1 + Name: Views + Splitter Ratio: 0.5 + - Class: rviz/Time + Experimental: false + Name: Time + SyncMode: 0 + SyncSource: LaserScan +Preferences: + PromptSaveOnExit: false +Toolbars: + toolButtonStyle: 2 +Visualization Manager: + Class: "" + Displays: + - Class: rviz/Marker + Enabled: true + Marker Topic: /visualizer/path + Name: Path_Marker + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/Group + Displays: + - Class: rviz/TF + Enabled: true + Frame Timeout: 15 + Frames: + All Enabled: false + base_link: + Value: true + chassis_link: + Value: true + front_fender_link: + Value: true + front_laser: + Value: true + front_laser_mount: + Value: true + front_left_wheel_link: + Value: true + front_mount: + Value: true + front_right_wheel_link: + Value: true + imu_link: + Value: true + map: + Value: true + mid_mount: + Value: true + navsat_link: + Value: true + odom: + Value: true + rear_fender_link: + Value: true + rear_left_wheel_link: + Value: true + rear_mount: + Value: true + rear_right_wheel_link: + Value: true + Marker Alpha: 1 + Marker Scale: 1 + Name: TF + Show Arrows: true + Show Axes: true + Show Names: true + Tree: + map: + odom: + base_link: + chassis_link: + front_fender_link: + {} + front_left_wheel_link: + {} + front_right_wheel_link: + {} + imu_link: + {} + mid_mount: + front_mount: + front_laser_mount: + front_laser: + {} + rear_mount: + {} + navsat_link: + {} + rear_fender_link: + {} + rear_left_wheel_link: + {} + rear_right_wheel_link: + {} + Update Interval: 0 + Value: true + - Alpha: 1 + Class: rviz/RobotModel + Collision Enabled: false + Enabled: true + Links: + All Links Enabled: true + Expand Joint Details: false + Expand Link Details: false + Expand Tree: false + Link Tree Style: Links in Alphabetic Order + base_link: + Alpha: 1 + Show Axes: false + Show Trail: false + chassis_link: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + front_fender_link: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + front_laser: + Alpha: 1 + Show Axes: false + Show Trail: false + front_laser_mount: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + front_left_wheel_link: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + front_mount: + Alpha: 1 + Show Axes: false + Show Trail: false + front_right_wheel_link: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + imu_link: + Alpha: 1 + Show Axes: false + Show Trail: false + mid_mount: + Alpha: 1 + Show Axes: false + Show Trail: false + navsat_link: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + rear_fender_link: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + rear_left_wheel_link: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + rear_mount: + Alpha: 1 + Show Axes: false + Show Trail: false + rear_right_wheel_link: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + Name: RobotModel + Robot Description: robot_description + TF Prefix: "" + Update Interval: 0 + Value: true + Visual Enabled: true + - Alpha: 1 + Axes Length: 1 + Axes Radius: 0.10000000149011612 + Class: rviz/Pose + Color: 0; 255; 0 + Enabled: false + Head Length: 0.10000000149011612 + Head Radius: 0.15000000596046448 + Name: Goal Pose + Queue Size: 10 + Shaft Length: 0.5 + Shaft Radius: 0.029999999329447746 + Shape: Arrow + Topic: /move_base_simple/goal + Unreliable: false + Value: false + Enabled: true + Name: robot + - Class: rviz/Group + Displays: + - Class: rviz/Marker + Enabled: true + Marker Topic: /cadrl/goal_path_marker + Name: Marker + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /cadrl/other_agents_markers + Name: MarkerArray + Namespaces: + {} + Queue Size: 100 + Value: true + Enabled: false + Name: cadrl + - Class: rviz/Group + Displays: + - Alpha: 0.699999988079071 + Class: rviz/Map + Color Scheme: map + Draw Behind: false + Enabled: true + Name: Map + Topic: /map + Unreliable: false + Use Timestamp: false + Value: true + - Alpha: 0.699999988079071 + Class: rviz/Map + Color Scheme: map + Draw Behind: false + Enabled: false + Name: Global_costmap + Topic: /move_base/global_costmap/costmap + Unreliable: false + Use Timestamp: false + Value: false + - Alpha: 0.699999988079071 + Class: rviz/Map + Color Scheme: costmap + Draw Behind: false + Enabled: false + Name: Local_costmap + Topic: /move_base/local_costmap/costmap + Unreliable: false + Use Timestamp: false + Value: false + Enabled: true + Name: Map + - Class: rviz/Group + Displays: + - Alpha: 1 + Buffer Length: 1 + Class: rviz/Path + Color: 255; 0; 0 + Enabled: true + Head Diameter: 0.30000001192092896 + Head Length: 0.20000000298023224 + Length: 0.30000001192092896 + Line Style: Billboards + Line Width: 0.05000000074505806 + Name: teb + Offset: + X: 0 + Y: 0 + Z: 0 + Pose Color: 255; 0; 0 + Pose Style: None + Queue Size: 10 + Radius: 0.029999999329447746 + Shaft Diameter: 0.10000000149011612 + Shaft Length: 0.10000000149011612 + Topic: /move_base/TebLocalPlannerROS/local_plan + Unreliable: false + Value: true + - Alpha: 1 + Buffer Length: 1 + Class: rviz/Path + Color: 85; 0; 127 + Enabled: true + Head Diameter: 0.30000001192092896 + Head Length: 0.20000000298023224 + Length: 0.30000001192092896 + Line Style: Billboards + Line Width: 0.05000000074505806 + Name: mpc + Offset: + X: 0 + Y: 0 + Z: 0 + Pose Color: 255; 85; 255 + Pose Style: None + Queue Size: 10 + Radius: 0.029999999329447746 + Shaft Diameter: 0.10000000149011612 + Shaft Length: 0.10000000149011612 + Topic: /move_base/MpcLocalPlannerROS/local_plan + Unreliable: false + Value: true + - Alpha: 1 + Buffer Length: 1 + Class: rviz/Path + Color: 0; 0; 0 + Enabled: true + Head Diameter: 0.30000001192092896 + Head Length: 0.20000000298023224 + Length: 0.30000001192092896 + Line Style: Billboards + Line Width: 0.029999999329447746 + Name: dwa + Offset: + X: 0 + Y: 0 + Z: 0 + Pose Color: 255; 85; 255 + Pose Style: None + Queue Size: 10 + Radius: 0.029999999329447746 + Shaft Diameter: 0.10000000149011612 + Shaft Length: 0.10000000149011612 + Topic: /move_base/DWAPlannerROS/local_plan + Unreliable: false + Value: true + Enabled: true + Name: Local plan + - Class: rviz/Group + Displays: + - Alpha: 1 + Buffer Length: 1 + Class: rviz/Path + Color: 0; 170; 0 + Enabled: true + Head Diameter: 0.30000001192092896 + Head Length: 0.20000000298023224 + Length: 0.30000001192092896 + Line Style: Billboards + Line Width: 0.05000000074505806 + Name: teb + Offset: + X: 0 + Y: 0 + Z: 0 + Pose Color: 255; 0; 0 + Pose Style: None + Queue Size: 10 + Radius: 0.029999999329447746 + Shaft Diameter: 0.10000000149011612 + Shaft Length: 0.10000000149011612 + Topic: /move_base/TebLocalPlannerROS/global_plan + Unreliable: false + Value: true + - Alpha: 1 + Buffer Length: 1 + Class: rviz/Path + Color: 0; 170; 0 + Enabled: true + Head Diameter: 0.30000001192092896 + Head Length: 0.20000000298023224 + Length: 0.30000001192092896 + Line Style: Billboards + Line Width: 0.05000000074505806 + Name: mpc + Offset: + X: 0 + Y: 0 + Z: 0 + Pose Color: 255; 85; 255 + Pose Style: None + Queue Size: 10 + Radius: 0.029999999329447746 + Shaft Diameter: 0.10000000149011612 + Shaft Length: 0.10000000149011612 + Topic: /move_base/MpcLocalPlannerROS/global_plan + Unreliable: false + Value: true + - Alpha: 1 + Buffer Length: 1 + Class: rviz/Path + Color: 0; 170; 0 + Enabled: true + Head Diameter: 0.30000001192092896 + Head Length: 0.20000000298023224 + Length: 0.30000001192092896 + Line Style: Billboards + Line Width: 0.029999999329447746 + Name: dwa + Offset: + X: 0 + Y: 0 + Z: 0 + Pose Color: 255; 85; 255 + Pose Style: None + Queue Size: 10 + Radius: 0.029999999329447746 + Shaft Diameter: 0.10000000149011612 + Shaft Length: 0.10000000149011612 + Topic: /move_base/DWAPlannerROS/global_plan + Unreliable: false + Value: true + Enabled: true + Name: Global Plan + - Class: rviz/Group + Displays: + - Alpha: 1 + Autocompute Intensity Bounds: true + Autocompute Value Bounds: + Max Value: 0.30399999022483826 + Min Value: 0.30399999022483826 + Value: true + Axis: Z + Channel Name: intensity + Class: rviz/LaserScan + Color: 255; 0; 0 + Color Transformer: FlatColor + Decay Time: 0 + Enabled: true + Invert Rainbow: false + Max Color: 255; 255; 255 + Min Color: 0; 0; 0 + Name: LaserScan + Position Transformer: XYZ + Queue Size: 10 + Selectable: true + Size (Pixels): 8 + Size (m): 0.009999999776482582 + Style: Points + Topic: /scan + Unreliable: false + Use Fixed Frame: true + Use rainbow: true + Value: true + Enabled: true + Name: Sensors + - Class: rviz/Marker + Enabled: true + Marker Topic: /action + Name: Marker + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/Group + Displays: ~ + Enabled: true + Name: obstacles + - Class: rviz/Group + Displays: + - Class: rviz/Marker + Enabled: true + Marker Topic: /cadrl/goal_path_marker + Name: Marker + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /other_agents_markers + Name: MarkerArray + Namespaces: + {} + Queue Size: 100 + Value: true + Enabled: true + Name: crowdnav + - Class: rviz/Group + Displays: + - Alpha: 1 + Buffer Length: 1 + Class: rviz/Path + Color: 25; 255; 0 + Enabled: true + Head Diameter: 0.30000001192092896 + Head Length: 0.20000000298023224 + Length: 0.30000001192092896 + Line Style: Lines + Line Width: 0.029999999329447746 + Name: global_path + Offset: + X: 0 + Y: 0 + Z: 0 + Pose Color: 255; 85; 255 + Pose Style: None + Queue Size: 10 + Radius: 0.029999999329447746 + Shaft Diameter: 0.10000000149011612 + Shaft Length: 0.10000000149011612 + Topic: /vis_global_path + Unreliable: false + Value: true + - Alpha: 1 + Buffer Length: 1 + Class: rviz/Path + Color: 85; 170; 255 + Enabled: true + Head Diameter: 0.30000001192092896 + Head Length: 0.20000000298023224 + Length: 0.30000001192092896 + Line Style: Billboards + Line Width: 0.30000001192092896 + Name: local_traj + Offset: + X: 0 + Y: 0 + Z: 0 + Pose Color: 255; 85; 255 + Pose Style: None + Queue Size: 10 + Radius: 0.029999999329447746 + Shaft Diameter: 0.10000000149011612 + Shaft Length: 0.10000000149011612 + Topic: /vis_path_timed_astar + Unreliable: false + Value: true + - Class: rviz/Marker + Enabled: true + Marker Topic: /vis_goal + Name: goal + Namespaces: + "": true + Queue Size: 100 + Value: true + - Class: rviz/Marker + Enabled: true + Marker Topic: /planning_vis/subgoal + Name: subgoal + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/Marker + Enabled: true + Marker Topic: /vis_landmarks_ + Name: landmarks + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/Marker + Enabled: true + Marker Topic: /vis_triangle + Name: triangulation_map + Namespaces: + {} + Queue Size: 100 + Value: true + - Alpha: 1 + Autocompute Intensity Bounds: true + Autocompute Value Bounds: + Max Value: 10 + Min Value: -10 + Value: true + Axis: Z + Channel Name: intensity + Class: rviz/PointCloud2 + Color: 255; 255; 255 + Color Transformer: Intensity + Decay Time: 0 + Enabled: false + Invert Rainbow: false + Max Color: 255; 255; 255 + Min Color: 0; 0; 0 + Name: occmap_local_only + Position Transformer: XYZ + Queue Size: 10 + Selectable: true + Size (Pixels): 3 + Size (m): 0.009999999776482582 + Style: Points + Topic: /sdf_map/occupancy + Unreliable: false + Use Fixed Frame: true + Use rainbow: true + Value: false + - Alpha: 1 + Autocompute Intensity Bounds: true + Autocompute Value Bounds: + Max Value: 10 + Min Value: -10 + Value: true + Axis: Z + Channel Name: intensity + Class: rviz/PointCloud2 + Color: 255; 255; 255 + Color Transformer: Intensity + Decay Time: 0 + Enabled: false + Invert Rainbow: false + Max Color: 255; 255; 255 + Min Color: 0; 0; 0 + Name: occmap_dynamic_only + Position Transformer: XYZ + Queue Size: 10 + Selectable: true + Size (Pixels): 3 + Size (m): 0.009999999776482582 + Style: Points + Topic: /sdf_map/occupancy_dynamic + Unreliable: false + Use Fixed Frame: true + Use rainbow: true + Value: false + - Alpha: 1 + Autocompute Intensity Bounds: true + Autocompute Value Bounds: + Max Value: 10 + Min Value: -10 + Value: true + Axis: Z + Channel Name: intensity + Class: rviz/PointCloud2 + Color: 255; 255; 255 + Color Transformer: Intensity + Decay Time: 0 + Enabled: false + Invert Rainbow: false + Max Color: 255; 255; 255 + Min Color: 0; 0; 0 + Name: occmap_static_only + Position Transformer: XYZ + Queue Size: 10 + Selectable: true + Size (Pixels): 3 + Size (m): 0.009999999776482582 + Style: Points + Topic: /sdf_map/occupancy_static + Unreliable: false + Use Fixed Frame: true + Use rainbow: true + Value: false + - Alpha: 1 + Autocompute Intensity Bounds: true + Autocompute Value Bounds: + Max Value: 10 + Min Value: -10 + Value: true + Axis: Z + Channel Name: intensity + Class: rviz/PointCloud2 + Color: 255; 255; 255 + Color Transformer: Intensity + Decay Time: 0 + Enabled: false + Invert Rainbow: false + Max Color: 255; 255; 255 + Min Color: 0; 0; 0 + Name: esdfmap_local_fused + Position Transformer: XYZ + Queue Size: 10 + Selectable: true + Size (Pixels): 3 + Size (m): 0.009999999776482582 + Style: Points + Topic: /sdf_map/esdf + Unreliable: false + Use Fixed Frame: true + Use rainbow: true + Value: false + - Alpha: 1 + Autocompute Intensity Bounds: true + Autocompute Value Bounds: + Max Value: 10 + Min Value: -10 + Value: true + Axis: Z + Channel Name: intensity + Class: rviz/PointCloud2 + Color: 255; 255; 255 + Color Transformer: Intensity + Decay Time: 0 + Enabled: false + Invert Rainbow: false + Max Color: 255; 255; 255 + Min Color: 0; 0; 0 + Name: esdfmap_static_only + Position Transformer: XYZ + Queue Size: 10 + Selectable: true + Size (Pixels): 3 + Size (m): 0.009999999776482582 + Style: Points + Topic: /sdf_map/esdf_static + Unreliable: false + Use Fixed Frame: true + Use rainbow: true + Value: false + Enabled: true + Name: Plan Manager + - Alpha: 1 + Axes Length: 1 + Axes Radius: 0.10000000149011612 + Class: rviz/Pose + Color: 255; 25; 0 + Enabled: false + Head Length: 0.30000001192092896 + Head Radius: 0.10000000149011612 + Name: Goal Pose + Queue Size: 10 + Shaft Length: 1 + Shaft Radius: 0.05000000074505806 + Shape: Axes + Topic: /goal + Unreliable: false + Value: false + - Class: rviz/Marker + Enabled: true + Marker Topic: /time_space/vis_visted_samples + Name: samples + Namespaces: + {} + Queue Size: 1 + Value: true + - Class: rviz/Marker + Enabled: true + Marker Topic: /planning_vis/goal + Name: Marker + Namespaces: + "": true + Queue Size: 100 + Value: true + - Alpha: 1 + Buffer Length: 1 + Class: rviz/Path + Color: 25; 255; 0 + Enabled: true + Head Diameter: 0.30000001192092896 + Head Length: 0.20000000298023224 + Length: 0.30000001192092896 + Line Style: Lines + Line Width: 0.029999999329447746 + Name: Path + Offset: + X: 0 + Y: 0 + Z: 0 + Pose Color: 255; 85; 255 + Pose Style: None + Queue Size: 10 + Radius: 0.029999999329447746 + Shaft Diameter: 0.10000000149011612 + Shaft Length: 0.10000000149011612 + Topic: /globalPlan + Unreliable: false + Value: true + - Class: rviz/Marker + Enabled: true + Marker Topic: /planning_vis/subgoal + Name: Marker + Namespaces: + {} + Queue Size: 100 + Value: true + - Alpha: 1 + Axes Length: 1 + Axes Radius: 0.10000000149011612 + Class: rviz/Pose + Color: 255; 25; 0 + Enabled: true + Head Length: 0.30000001192092896 + Head Radius: 0.10000000149011612 + Name: Pose + Queue Size: 10 + Shaft Length: 1 + Shaft Radius: 0.05000000074505806 + Shape: Arrow + Topic: /subgoal + Unreliable: false + Value: true + - Class: rviz/Group + Displays: + - Alpha: 1 + Class: spencer_tracking_rviz_plugin/TrackedPersons + Color: 130; 130; 130 + Color map offset: 0 + Color transform: SRL Tracking Colors + Delete after no. cycles: 5 + Enabled: true + Excluded person IDs: "" + Font color: 255; 255; 255 + Font color style: Same color + Font scale: 2 + History as line: + Line width: 0.05000000074505806 + Value: true + History size: 10 + Included person IDs: "" + Min. history point distance: 0.4000000059604645 + Missed alpha: 1 + Name: TrackedPersons + Occlusion alpha: 1 + Queue Size: 10 + Render covariances: + Line width: 0.10000000149011612 + Value: false + Render detection IDs: false + Render history: false + Render person visual: true + Render track IDs: true + Render track state: false + Render velocities: true + Show DELETED tracks: false + Show MATCHED tracks: true + Show MISSED tracks: true + Show OCCLUDED tracks: true + Style: + Line width: 0.05000000074505806 + Scaling factor: 1 + Value: Bounding boxes + Topic: /pedsim_visualizer/tracked_persons + Unreliable: false + Value: true + Z offset: + Use Z position from message: false + Value: 0 + - Alpha: 0.699999988079071 + Class: spencer_tracking_rviz_plugin/TrackedGroups + Color: 130; 130; 130 + Color map offset: 0 + Color transform: Flat + Connect group members: true + Enabled: true + Excluded group IDs: "" + Excluded person IDs: "" + Font color: 255; 255; 255 + Font color style: Same color + Font scale: 2 + Global history size: 5 + Group ID Z offset: 2 + Included group IDs: "" + Included person IDs: "" + Name: TrackedGroups + Occlusion alpha: 1 + Queue Size: 10 + Render group IDs: + Hide IDs of single-person groups: false + Value: true + Render history: false + Single-person groups in constant color: false + Style: + Line width: 0.05000000074505806 + Scaling factor: 1 + Value: Simple + Topic: /pedsim_visualizer/tracked_groups + Tracked persons topic: /pedsim_visualizer/tracked_persons + Unreliable: false + Value: true + Z offset: + Use Z position from message: false + Value: 0 + Enabled: true + Name: Tracking-Visuals + - Alpha: 1 + Autocompute Intensity Bounds: true + Autocompute Value Bounds: + Max Value: 10 + Min Value: -10 + Value: true + Axis: Z + Channel Name: intensity + Class: rviz/LaserScan + Color: 255; 255; 255 + Color Transformer: Intensity + Decay Time: 0 + Enabled: true + Invert Rainbow: false + Max Color: 255; 255; 255 + Min Color: 0; 0; 0 + Name: LaserScan + Position Transformer: XYZ + Queue Size: 10 + Selectable: true + Size (Pixels): 3 + Size (m): 0.03999999910593033 + Style: Flat Squares + Topic: /scan_new + Unreliable: false + Use Fixed Frame: true + Use rainbow: true + Value: true + - Class: rviz/Group + Displays: + - Class: rviz/Marker + Enabled: true + Marker Topic: /all_in_one_planner/all_in_one_action_trajectory_vis + Name: Planner Selection over Path + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/Marker + Enabled: true + Marker Topic: /all_in_one_planner/all_in_one_action_vis + Name: Planner Selection + Namespaces: + {} + Queue Size: 100 + Value: true + - Alpha: 1 + Autocompute Intensity Bounds: true + Autocompute Value Bounds: + Max Value: 10 + Min Value: -10 + Value: true + Axis: Z + Channel Name: intensity + Class: rviz/LaserScan + Color: 252; 233; 79 + Color Transformer: FlatColor + Decay Time: 0 + Enabled: true + Invert Rainbow: false + Max Color: 255; 255; 255 + Min Color: 0; 0; 0 + Name: Dynamic Scan + Position Transformer: XYZ + Queue Size: 10 + Selectable: true + Size (Pixels): 3 + Size (m): 0.3499999940395355 + Style: Flat Squares + Topic: /all_in_one_planner/scan_dynamic + Unreliable: false + Use Fixed Frame: true + Use rainbow: true + Value: true + - Class: rviz/Marker + Enabled: true + Marker Topic: /all_in_one_planner/vis_subgoal + Name: Subgoal + Namespaces: + {} + Queue Size: 100 + Value: true + Enabled: true + Name: AIO + - Class: rviz/Marker + Enabled: true + Marker Topic: /viz_agent_pose + Name: Agent path taken + Namespaces: + agent: true + Queue Size: 100 + Value: true + Enabled: true + Global Options: + Background Color: 0; 0; 0 + Default Light: true + Fixed Frame: map + Frame Rate: 30 + Name: root + Tools: + - Class: rviz/MoveCamera + - Class: rviz/Interact + Hide Inactive Objects: true + - Class: rviz/Select + - Class: rviz/SetInitialPose + Theta std deviation: 0.2617993950843811 + Topic: /initialpose + X std deviation: 0.5 + Y std deviation: 0.5 + - Class: rviz/SetGoal + Topic: /move_base_simple/goal + - Class: rviz_plugins/Goal3DTool + Topic: manual_goal + - Class: rviz/PublishPoint + Single click: true + Topic: /clicked_point + Value: true + Views: + Current: + Angle: -7.859952449798584 + Class: rviz/TopDownOrtho + Enable Stereo Rendering: + Stereo Eye Separation: 0.05999999865889549 + Stereo Focal Distance: 1 + Swap Stereo Eyes: false + Value: false + Invert Z Axis: false + Name: Current View + Near Clip Distance: 0.009999999776482582 + Scale: 40.95969772338867 + Target Frame: + X: 0.17317672073841095 + Y: -2.2967824935913086 + Saved: ~ +Window Geometry: + Displays: + collapsed: true + Height: 1367 + Hide Left Dock: true + Hide Right Dock: false + QMainWindow State: 000000ff00000000fd00000004000000000000016a00000266fc0200000005fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000003be0000025d00000198000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073000000003d00000266000000c900ffffff000000010000010f00000270fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000002800000270000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004a00000003efc0100000002fb0000000800540069006d00650000000000000004a0000004f300fffffffb0000000800540069006d00650100000000000004500000000000000000000009b8000004fd00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 + Selection: + collapsed: false + Time: + collapsed: false + Tool Properties: + collapsed: false + Views: + collapsed: false + Width: 2488 + X: 72 + Y: 27 \ No newline at end of file diff --git a/arena_bringup/rviz/nav_MARL.rviz b/arena_bringup/rviz/nav_MARL.rviz new file mode 100644 index 000000000..82f8bb367 --- /dev/null +++ b/arena_bringup/rviz/nav_MARL.rviz @@ -0,0 +1,1602 @@ +Panels: + - Class: rviz/Displays + Help Height: 78 + Name: Displays + Property Tree Widget: + Expanded: + - /Sensors1 + - /obstacles1 + - /obstacles1/dynamic1/01 + - /obstacles1/dynamic1/11 + - /obstacles1/dynamic1/21 + - /obstacles1/dynamic1/31 + - /obstacles1/dynamic1/41 + - /obstacles1/dynamic1/51 + - /obstacles1/dynamic1/61 + - /obstacles1/dynamic1/71 + - /obstacles1/dynamic1/81 + - /obstacles1/dynamic1/91 + - /crowdnav1/Marker1 + - /Plan Manager1/goal1 + - /Plan Manager1/subgoal1 + - /MARL1 + - /MARL1/robot_11 + - /MARL1/robot_21/my_robot1 + - /MARL1/robot_21/Goal Pose1 + - /MARL1/robot_31 + - /MARL1/robot_31/my_robot1 + - /MARL1/robot_31/Goal Pose1 + - /MARL1/robot_41 + - /MARL1/robot_51 + - /MARL1/robot_61/my_robot1 + - /MARL1/robot_61/Goal Pose1 + - /MARL1/robot_71/my_robot1 + - /MARL1/robot_71/Goal Pose1 + - /MARL1/robot_81/my_robot1 + - /MARL1/robot_81/Goal Pose1 + Splitter Ratio: 0.4374079406261444 + Tree Height: 814 + - Class: rviz/Selection + Name: Selection + - Class: rviz/Tool Properties + Expanded: + - /2D Pose Estimate1 + - /2D Nav Goal1 + - /Publish Point1 + Name: Tool Properties + Splitter Ratio: 0.4285709857940674 + - Class: rviz/Views + Expanded: + - /Current View1 + Name: Views + Splitter Ratio: 0.5 + - Class: rviz/Time + Experimental: false + Name: Time + SyncMode: 0 + SyncSource: "" +Preferences: + PromptSaveOnExit: true +Toolbars: + toolButtonStyle: 2 +Visualization Manager: + Class: "" + Displays: + - Class: rviz/Marker + Enabled: true + Marker Topic: /visualizer/path + Name: Path_Marker + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/Group + Displays: + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/layer/static + Name: static_layer + Namespaces: + {} + Queue Size: 100 + Value: true + - Alpha: 0.699999988079071 + Class: rviz/Map + Color Scheme: map + Draw Behind: false + Enabled: true + Name: Map + Topic: /map + Unreliable: false + Use Timestamp: false + Value: true + - Alpha: 0.699999988079071 + Class: rviz/Map + Color Scheme: map + Draw Behind: false + Enabled: false + Name: Global_costmap + Topic: /move_base/global_costmap/costmap + Unreliable: false + Use Timestamp: false + Value: false + - Alpha: 0.699999988079071 + Class: rviz/Map + Color Scheme: costmap + Draw Behind: false + Enabled: false + Name: Local_costmap + Topic: /move_base/local_costmap/costmap + Unreliable: false + Use Timestamp: false + Value: false + Enabled: true + Name: Map + - Class: rviz/Group + Displays: + - Class: rviz/Marker + Enabled: true + Marker Topic: /cadrl/goal_path_marker + Name: Marker + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /cadrl/other_agents_markers + Name: MarkerArray + Namespaces: + {} + Queue Size: 100 + Value: true + Enabled: false + Name: cadrl + - Class: rviz/Group + Displays: + - Alpha: 1 + Buffer Length: 1 + Class: rviz/Path + Color: 255; 0; 0 + Enabled: true + Head Diameter: 0.30000001192092896 + Head Length: 0.20000000298023224 + Length: 0.30000001192092896 + Line Style: Billboards + Line Width: 0.05000000074505806 + Name: teb + Offset: + X: 0 + Y: 0 + Z: 0 + Pose Color: 255; 0; 0 + Pose Style: None + Queue Size: 10 + Radius: 0.029999999329447746 + Shaft Diameter: 0.10000000149011612 + Shaft Length: 0.10000000149011612 + Topic: /move_base/TebLocalPlannerROS/local_plan + Unreliable: false + Value: true + - Alpha: 1 + Buffer Length: 1 + Class: rviz/Path + Color: 85; 0; 127 + Enabled: true + Head Diameter: 0.30000001192092896 + Head Length: 0.20000000298023224 + Length: 0.30000001192092896 + Line Style: Billboards + Line Width: 0.05000000074505806 + Name: mpc + Offset: + X: 0 + Y: 0 + Z: 0 + Pose Color: 255; 85; 255 + Pose Style: None + Queue Size: 10 + Radius: 0.029999999329447746 + Shaft Diameter: 0.10000000149011612 + Shaft Length: 0.10000000149011612 + Topic: /move_base/MpcLocalPlannerROS/local_plan + Unreliable: false + Value: true + - Alpha: 1 + Buffer Length: 1 + Class: rviz/Path + Color: 0; 0; 0 + Enabled: true + Head Diameter: 0.30000001192092896 + Head Length: 0.20000000298023224 + Length: 0.30000001192092896 + Line Style: Billboards + Line Width: 0.029999999329447746 + Name: dwa + Offset: + X: 0 + Y: 0 + Z: 0 + Pose Color: 255; 85; 255 + Pose Style: None + Queue Size: 10 + Radius: 0.029999999329447746 + Shaft Diameter: 0.10000000149011612 + Shaft Length: 0.10000000149011612 + Topic: /move_base/DWAPlannerROS/local_plan + Unreliable: false + Value: true + Enabled: true + Name: Local plan + - Class: rviz/Group + Displays: + - Alpha: 1 + Buffer Length: 1 + Class: rviz/Path + Color: 0; 170; 0 + Enabled: true + Head Diameter: 0.30000001192092896 + Head Length: 0.20000000298023224 + Length: 0.30000001192092896 + Line Style: Billboards + Line Width: 0.05000000074505806 + Name: teb + Offset: + X: 0 + Y: 0 + Z: 0 + Pose Color: 255; 0; 0 + Pose Style: None + Queue Size: 10 + Radius: 0.029999999329447746 + Shaft Diameter: 0.10000000149011612 + Shaft Length: 0.10000000149011612 + Topic: /move_base/TebLocalPlannerROS/global_plan + Unreliable: false + Value: true + - Alpha: 1 + Buffer Length: 1 + Class: rviz/Path + Color: 0; 170; 0 + Enabled: true + Head Diameter: 0.30000001192092896 + Head Length: 0.20000000298023224 + Length: 0.30000001192092896 + Line Style: Billboards + Line Width: 0.05000000074505806 + Name: mpc + Offset: + X: 0 + Y: 0 + Z: 0 + Pose Color: 255; 85; 255 + Pose Style: None + Queue Size: 10 + Radius: 0.029999999329447746 + Shaft Diameter: 0.10000000149011612 + Shaft Length: 0.10000000149011612 + Topic: /move_base/MpcLocalPlannerROS/global_plan + Unreliable: false + Value: true + - Alpha: 1 + Buffer Length: 1 + Class: rviz/Path + Color: 0; 170; 0 + Enabled: true + Head Diameter: 0.30000001192092896 + Head Length: 0.20000000298023224 + Length: 0.30000001192092896 + Line Style: Billboards + Line Width: 0.029999999329447746 + Name: dwa + Offset: + X: 0 + Y: 0 + Z: 0 + Pose Color: 255; 85; 255 + Pose Style: None + Queue Size: 10 + Radius: 0.029999999329447746 + Shaft Diameter: 0.10000000149011612 + Shaft Length: 0.10000000149011612 + Topic: /move_base/DWAPlannerROS/global_plan + Unreliable: false + Value: true + Enabled: true + Name: Global Plan + - Class: rviz/Group + Displays: + - Alpha: 1 + Autocompute Intensity Bounds: true + Autocompute Value Bounds: + Max Value: 0.30399999022483826 + Min Value: 0.30399999022483826 + Value: true + Axis: Z + Channel Name: intensity + Class: rviz/LaserScan + Color: 255; 0; 0 + Color Transformer: FlatColor + Decay Time: 0 + Enabled: true + Invert Rainbow: false + Max Color: 255; 255; 255 + Min Color: 0; 0; 0 + Name: LaserScan + Position Transformer: XYZ + Queue Size: 10 + Selectable: true + Size (Pixels): 8 + Size (m): 0.009999999776482582 + Style: Points + Topic: /scan + Unreliable: false + Use Fixed Frame: true + Use rainbow: true + Value: true + Enabled: true + Name: Sensors + - Class: rviz/Marker + Enabled: true + Marker Topic: /action + Name: Marker + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/Group + Displays: + - Class: rviz/Group + Displays: + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_00 + Name: 0 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_01 + Name: 1 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_02 + Name: 2 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_03 + Name: 3 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_04 + Name: 4 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_05 + Name: 5 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_06 + Name: 6 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_07 + Name: 7 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_08 + Name: 8 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_09 + Name: 9 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_10 + Name: 10 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_11 + Name: 11 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_12 + Name: 12 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_13 + Name: 13 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_14 + Name: 14 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_15 + Name: 15 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_16 + Name: 16 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_17 + Name: 17 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_18 + Name: 18 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_19 + Name: 19 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_20 + Name: 20 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_21 + Name: 21 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_22 + Name: 22 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_23 + Name: 23 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_circle_static_24 + Name: 24 + Namespaces: + {} + Queue Size: 100 + Value: true + Enabled: true + Name: static + - Class: rviz/Group + Displays: + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /sim_1/flatland_server/debug/model/obstacle__random_dynamic_00 + Name: 0 + Namespaces: + "": true + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /sim_1/flatland_server/debug/model/obstacle__random_dynamic_01 + Name: 1 + Namespaces: + "": true + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /sim_1/flatland_server/debug/model/obstacle__random_dynamic_02 + Name: 2 + Namespaces: + "": true + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /sim_1/flatland_server/debug/model/obstacle__random_dynamic_03 + Name: 3 + Namespaces: + "": true + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /sim_1/flatland_server/debug/model/obstacle__random_dynamic_05 + Name: 4 + Namespaces: + "": true + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /sim_1/flatland_server/debug/model/obstacle__random_dynamic_06 + Name: 5 + Namespaces: + "": true + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /sim_1/flatland_server/debug/model/obstacle__random_dynamic_07 + Name: 6 + Namespaces: + "": true + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /sim_1/flatland_server/debug/model/obstacle__random_dynamic_08 + Name: 7 + Namespaces: + "": true + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /sim_1/flatland_server/debug/model/obstacle__random_dynamic_09 + Name: 8 + Namespaces: + "": true + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /sim_1/flatland_server/debug/model/obstacle__random_dynamic_04 + Name: 9 + Namespaces: + "": true + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_10 + Name: 10 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_11 + Name: 11 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_12 + Name: 12 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_13 + Name: 13 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_15 + Name: 14 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_05 + Name: 15 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_16 + Name: 16 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_17 + Name: 17 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_18 + Name: 18 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_19 + Name: 19 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_20 + Name: 20 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_21 + Name: 21 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_22 + Name: 22 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_23 + Name: 23 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_24 + Name: 24 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_25 + Name: 25 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_26 + Name: 26 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_27 + Name: 27 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_28 + Name: 28 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_29 + Name: 29 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_30 + Name: 30 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_31 + Name: 31 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_32 + Name: 32 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_33 + Name: 33 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_34 + Name: 34 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_35 + Name: 35 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_36 + Name: 36 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_37 + Name: 37 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_38 + Name: 38 + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /flatland_server/debug/model/obstacle_dynamic_with_traj_39 + Name: 39 + Namespaces: + {} + Queue Size: 100 + Value: true + Enabled: true + Name: dynamic + Enabled: true + Name: obstacles + - Class: rviz/Group + Displays: + - Class: rviz/Marker + Enabled: true + Marker Topic: /cadrl/goal_path_marker + Name: Marker + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /other_agents_markers + Name: MarkerArray + Namespaces: + {} + Queue Size: 100 + Value: true + Enabled: true + Name: crowdnav + - Class: rviz/Group + Displays: + - Alpha: 1 + Buffer Length: 1 + Class: rviz/Path + Color: 25; 255; 0 + Enabled: true + Head Diameter: 0.30000001192092896 + Head Length: 0.20000000298023224 + Length: 0.30000001192092896 + Line Style: Lines + Line Width: 0.029999999329447746 + Name: global_path + Offset: + X: 0 + Y: 0 + Z: 0 + Pose Color: 255; 85; 255 + Pose Style: None + Queue Size: 10 + Radius: 0.029999999329447746 + Shaft Diameter: 0.10000000149011612 + Shaft Length: 0.10000000149011612 + Topic: /vis_global_path + Unreliable: false + Value: true + - Alpha: 1 + Buffer Length: 1 + Class: rviz/Path + Color: 85; 170; 255 + Enabled: true + Head Diameter: 0.30000001192092896 + Head Length: 0.20000000298023224 + Length: 0.30000001192092896 + Line Style: Billboards + Line Width: 0.30000001192092896 + Name: local_traj + Offset: + X: 0 + Y: 0 + Z: 0 + Pose Color: 255; 85; 255 + Pose Style: None + Queue Size: 10 + Radius: 0.029999999329447746 + Shaft Diameter: 0.10000000149011612 + Shaft Length: 0.10000000149011612 + Topic: /vis_path_timed_astar + Unreliable: false + Value: true + - Class: rviz/Marker + Enabled: true + Marker Topic: /vis_goal + Name: goal + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/Marker + Enabled: true + Marker Topic: /planning_vis/subgoal + Name: subgoal + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/Marker + Enabled: true + Marker Topic: /vis_landmarks_ + Name: landmarks + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/Marker + Enabled: true + Marker Topic: /vis_triangle + Name: triangulation_map + Namespaces: + {} + Queue Size: 100 + Value: true + - Alpha: 1 + Autocompute Intensity Bounds: true + Autocompute Value Bounds: + Max Value: 10 + Min Value: -10 + Value: true + Axis: Z + Channel Name: intensity + Class: rviz/PointCloud2 + Color: 255; 255; 255 + Color Transformer: Intensity + Decay Time: 0 + Enabled: false + Invert Rainbow: false + Max Color: 255; 255; 255 + Min Color: 0; 0; 0 + Name: occmap_local_only + Position Transformer: XYZ + Queue Size: 10 + Selectable: true + Size (Pixels): 3 + Size (m): 0.009999999776482582 + Style: Points + Topic: /sdf_map/occupancy + Unreliable: false + Use Fixed Frame: true + Use rainbow: true + Value: false + - Alpha: 1 + Autocompute Intensity Bounds: true + Autocompute Value Bounds: + Max Value: 10 + Min Value: -10 + Value: true + Axis: Z + Channel Name: intensity + Class: rviz/PointCloud2 + Color: 255; 255; 255 + Color Transformer: Intensity + Decay Time: 0 + Enabled: false + Invert Rainbow: false + Max Color: 255; 255; 255 + Min Color: 0; 0; 0 + Name: occmap_dynamic_only + Position Transformer: XYZ + Queue Size: 10 + Selectable: true + Size (Pixels): 3 + Size (m): 0.009999999776482582 + Style: Points + Topic: /sdf_map/occupancy_dynamic + Unreliable: false + Use Fixed Frame: true + Use rainbow: true + Value: false + - Alpha: 1 + Autocompute Intensity Bounds: true + Autocompute Value Bounds: + Max Value: 10 + Min Value: -10 + Value: true + Axis: Z + Channel Name: intensity + Class: rviz/PointCloud2 + Color: 255; 255; 255 + Color Transformer: Intensity + Decay Time: 0 + Enabled: false + Invert Rainbow: false + Max Color: 255; 255; 255 + Min Color: 0; 0; 0 + Name: occmap_static_only + Position Transformer: XYZ + Queue Size: 10 + Selectable: true + Size (Pixels): 3 + Size (m): 0.009999999776482582 + Style: Points + Topic: /sdf_map/occupancy_static + Unreliable: false + Use Fixed Frame: true + Use rainbow: true + Value: false + - Alpha: 1 + Autocompute Intensity Bounds: true + Autocompute Value Bounds: + Max Value: 10 + Min Value: -10 + Value: true + Axis: Z + Channel Name: intensity + Class: rviz/PointCloud2 + Color: 255; 255; 255 + Color Transformer: Intensity + Decay Time: 0 + Enabled: false + Invert Rainbow: false + Max Color: 255; 255; 255 + Min Color: 0; 0; 0 + Name: esdfmap_local_fused + Position Transformer: XYZ + Queue Size: 10 + Selectable: true + Size (Pixels): 3 + Size (m): 0.009999999776482582 + Style: Points + Topic: /sdf_map/esdf + Unreliable: false + Use Fixed Frame: true + Use rainbow: true + Value: false + - Alpha: 1 + Autocompute Intensity Bounds: true + Autocompute Value Bounds: + Max Value: 10 + Min Value: -10 + Value: true + Axis: Z + Channel Name: intensity + Class: rviz/PointCloud2 + Color: 255; 255; 255 + Color Transformer: Intensity + Decay Time: 0 + Enabled: false + Invert Rainbow: false + Max Color: 255; 255; 255 + Min Color: 0; 0; 0 + Name: esdfmap_static_only + Position Transformer: XYZ + Queue Size: 10 + Selectable: true + Size (Pixels): 3 + Size (m): 0.009999999776482582 + Style: Points + Topic: /sdf_map/esdf_static + Unreliable: false + Use Fixed Frame: true + Use rainbow: true + Value: false + Enabled: true + Name: Plan Manager + - Class: rviz/Marker + Enabled: true + Marker Topic: /time_space/vis_visted_samples + Name: samples + Namespaces: + {} + Queue Size: 1 + Value: true + - Class: rviz/Marker + Enabled: true + Marker Topic: /planning_vis/goal + Name: Marker + Namespaces: + {} + Queue Size: 100 + Value: true + - Alpha: 1 + Buffer Length: 1 + Class: rviz/Path + Color: 25; 255; 0 + Enabled: true + Head Diameter: 0.30000001192092896 + Head Length: 0.20000000298023224 + Length: 0.30000001192092896 + Line Style: Lines + Line Width: 0.029999999329447746 + Name: Path + Offset: + X: 0 + Y: 0 + Z: 0 + Pose Color: 255; 85; 255 + Pose Style: None + Queue Size: 10 + Radius: 0.029999999329447746 + Shaft Diameter: 0.10000000149011612 + Shaft Length: 0.10000000149011612 + Topic: /globalPlan + Unreliable: false + Value: true + - Class: rviz/Marker + Enabled: true + Marker Topic: /planning_vis/goal + Name: Marker + Namespaces: + {} + Queue Size: 100 + Value: true + - Alpha: 1 + Axes Length: 1 + Axes Radius: 0.10000000149011612 + Class: rviz/Pose + Color: 117; 80; 123 + Enabled: true + Head Length: 0.5 + Head Radius: 0.10000000149011612 + Name: Pose + Queue Size: 10 + Shaft Length: 3 + Shaft Radius: 0.05000000074505806 + Shape: Arrow + Topic: /sim_1/goal + Unreliable: false + Value: true + - Class: rviz/TF + Enabled: true + Frame Timeout: 15 + Frames: + All Enabled: false + eval_sim_robot1_base_footprint: + Value: true + eval_sim_robot1_laser_link: + Value: true + eval_sim_robot1_odom: + Value: true + eval_sim_robot2_base_footprint: + Value: true + eval_sim_robot2_laser_link: + Value: true + eval_sim_robot2_odom: + Value: true + eval_sim_robot3_base_footprint: + Value: true + eval_sim_robot3_laser_link: + Value: true + eval_sim_robot3_odom: + Value: true + eval_sim_robot4_odom: + Value: true + eval_sim_robot5_odom: + Value: true + eval_sim_robot6_odom: + Value: true + eval_sim_robot7_odom: + Value: true + eval_sim_robot8_odom: + Value: true + map: + Value: true + sim_1_robot1_base_footprint: + Value: true + sim_1_robot1_laser_link: + Value: true + sim_1_robot1_odom: + Value: true + sim_1_robot2_base_footprint: + Value: true + sim_1_robot2_laser_link: + Value: true + sim_1_robot2_odom: + Value: true + sim_1_robot3_base_footprint: + Value: true + sim_1_robot3_laser_link: + Value: true + sim_1_robot3_odom: + Value: true + sim_1_robot4_odom: + Value: true + sim_1_robot5_odom: + Value: true + sim_1_robot6_odom: + Value: true + sim_1_robot7_odom: + Value: true + sim_1_robot8_odom: + Value: true + Marker Alpha: 1 + Marker Scale: 1 + Name: TF + Show Arrows: true + Show Axes: true + Show Names: true + Tree: + map: + eval_sim_robot1_odom: + eval_sim_robot1_base_footprint: + eval_sim_robot1_laser_link: + {} + eval_sim_robot2_odom: + eval_sim_robot2_base_footprint: + eval_sim_robot2_laser_link: + {} + eval_sim_robot3_odom: + eval_sim_robot3_base_footprint: + eval_sim_robot3_laser_link: + {} + eval_sim_robot4_odom: + {} + eval_sim_robot5_odom: + {} + eval_sim_robot6_odom: + {} + eval_sim_robot7_odom: + {} + eval_sim_robot8_odom: + {} + sim_1_robot1_odom: + sim_1_robot1_base_footprint: + sim_1_robot1_laser_link: + {} + sim_1_robot2_odom: + sim_1_robot2_base_footprint: + sim_1_robot2_laser_link: + {} + sim_1_robot3_odom: + sim_1_robot3_base_footprint: + sim_1_robot3_laser_link: + {} + sim_1_robot4_odom: + {} + sim_1_robot5_odom: + {} + sim_1_robot6_odom: + {} + sim_1_robot7_odom: + {} + sim_1_robot8_odom: + {} + Update Interval: 0 + Value: true + - Class: rviz/Group + Displays: + - Class: rviz/Group + Displays: + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /eval_sim/flatland_server/debug/model/robot1 + Name: my_robot + Namespaces: + "": true + Queue Size: 100 + Value: true + - Alpha: 1 + Axes Length: 1 + Axes Radius: 0.10000000149011612 + Class: rviz/Pose + Color: 0; 255; 0 + Enabled: true + Head Length: 0.10000000149011612 + Head Radius: 0.15000000596046448 + Name: Goal Pose + Queue Size: 10 + Shaft Length: 0.5 + Shaft Radius: 0.029999999329447746 + Shape: Arrow + Topic: /eval_sim/robot1/goal + Unreliable: false + Value: true + Enabled: true + Name: robot_1 + - Class: rviz/Group + Displays: + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /eval_sim/flatland_server/debug/model/robot2 + Name: my_robot + Namespaces: + "": true + Queue Size: 100 + Value: true + - Alpha: 1 + Axes Length: 1 + Axes Radius: 0.10000000149011612 + Class: rviz/Pose + Color: 0; 255; 0 + Enabled: true + Head Length: 0.10000000149011612 + Head Radius: 0.15000000596046448 + Name: Goal Pose + Queue Size: 10 + Shaft Length: 0.5 + Shaft Radius: 0.029999999329447746 + Shape: Arrow + Topic: /eval_sim/robot2/goal + Unreliable: false + Value: true + Enabled: true + Name: robot_2 + - Class: rviz/Group + Displays: + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /eval_sim/flatland_server/debug/model/robot3 + Name: my_robot + Namespaces: + "": true + Queue Size: 100 + Value: true + - Alpha: 1 + Axes Length: 1 + Axes Radius: 0.10000000149011612 + Class: rviz/Pose + Color: 0; 255; 0 + Enabled: true + Head Length: 0.10000000149011612 + Head Radius: 0.15000000596046448 + Name: Goal Pose + Queue Size: 10 + Shaft Length: 0.5 + Shaft Radius: 0.029999999329447746 + Shape: Arrow + Topic: /eval_sim/robot3/goal + Unreliable: false + Value: true + Enabled: true + Name: robot_3 + - Class: rviz/Group + Displays: + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /sim_1/flatland_server/debug/model/robot4 + Name: my_robot + Namespaces: + {} + Queue Size: 100 + Value: true + - Alpha: 1 + Axes Length: 1 + Axes Radius: 0.10000000149011612 + Class: rviz/Pose + Color: 0; 255; 0 + Enabled: true + Head Length: 0.10000000149011612 + Head Radius: 0.15000000596046448 + Name: Goal Pose + Queue Size: 10 + Shaft Length: 0.5 + Shaft Radius: 0.029999999329447746 + Shape: Arrow + Topic: /sim_1/robot4/goal + Unreliable: false + Value: true + Enabled: true + Name: robot_4 + - Class: rviz/Group + Displays: + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /sim_1/flatland_server/debug/model/robot5 + Name: my_robot + Namespaces: + {} + Queue Size: 100 + Value: true + - Alpha: 1 + Axes Length: 1 + Axes Radius: 0.10000000149011612 + Class: rviz/Pose + Color: 0; 255; 0 + Enabled: true + Head Length: 0.10000000149011612 + Head Radius: 0.15000000596046448 + Name: Goal Pose + Queue Size: 10 + Shaft Length: 0.5 + Shaft Radius: 0.029999999329447746 + Shape: Arrow + Topic: /sim_1/robot6/goal + Unreliable: false + Value: true + Enabled: true + Name: robot_5 + - Class: rviz/Group + Displays: + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /sim_1/flatland_server/debug/model/obstacle__random_dynamic_06 + Name: my_robot + Namespaces: + "": true + Queue Size: 100 + Value: true + - Alpha: 1 + Axes Length: 1 + Axes Radius: 0.10000000149011612 + Class: rviz/Pose + Color: 0; 255; 0 + Enabled: true + Head Length: 0.10000000149011612 + Head Radius: 0.15000000596046448 + Name: Goal Pose + Queue Size: 10 + Shaft Length: 0.5 + Shaft Radius: 0.029999999329447746 + Shape: Arrow + Topic: /sim_1/robot6/goal + Unreliable: false + Value: true + Enabled: true + Name: robot_6 + - Class: rviz/Group + Displays: + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /sim_1/flatland_server/debug/model/robot7 + Name: my_robot + Namespaces: + {} + Queue Size: 100 + Value: true + - Alpha: 1 + Axes Length: 1 + Axes Radius: 0.10000000149011612 + Class: rviz/Pose + Color: 0; 255; 0 + Enabled: true + Head Length: 0.10000000149011612 + Head Radius: 0.15000000596046448 + Name: Goal Pose + Queue Size: 10 + Shaft Length: 0.5 + Shaft Radius: 0.029999999329447746 + Shape: Arrow + Topic: /sim_1/robot7/goal + Unreliable: false + Value: true + Enabled: true + Name: robot_7 + - Class: rviz/Group + Displays: + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /sim_1/flatland_server/debug/model/robot8 + Name: my_robot + Namespaces: + {} + Queue Size: 100 + Value: true + - Alpha: 1 + Axes Length: 1 + Axes Radius: 0.10000000149011612 + Class: rviz/Pose + Color: 0; 255; 0 + Enabled: true + Head Length: 0.10000000149011612 + Head Radius: 0.15000000596046448 + Name: Goal Pose + Queue Size: 10 + Shaft Length: 0.5 + Shaft Radius: 0.029999999329447746 + Shape: Arrow + Topic: /sim_1/robot8/goal + Unreliable: false + Value: true + Enabled: true + Name: robot_8 + - Class: rviz/Group + Displays: + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /sim_1/flatland_server/debug/model/robot4 + Name: my_robot + Namespaces: + {} + Queue Size: 100 + Value: true + - Alpha: 1 + Axes Length: 1 + Axes Radius: 0.10000000149011612 + Class: rviz/Pose + Color: 0; 255; 0 + Enabled: true + Head Length: 0.10000000149011612 + Head Radius: 0.15000000596046448 + Name: Goal Pose + Queue Size: 10 + Shaft Length: 0.5 + Shaft Radius: 0.029999999329447746 + Shape: Arrow + Topic: /sim_1/robot4/goal + Unreliable: false + Value: true + Enabled: true + Name: robot_9 + Enabled: true + Name: MARL + Enabled: true + Global Options: + Background Color: 0; 0; 0 + Default Light: true + Fixed Frame: map + Frame Rate: 30 + Name: root + Tools: + - Class: rviz/MoveCamera + - Class: rviz/Interact + Hide Inactive Objects: true + - Class: rviz/Select + - Class: rviz/SetInitialPose + Theta std deviation: 0.2617993950843811 + Topic: /initialpose + X std deviation: 0.5 + Y std deviation: 0.5 + - Class: rviz/SetGoal + Topic: /move_base_simple/goal + - Class: flatland_viz/SpawnModel + - Class: rviz_plugins/Goal3DTool + Topic: goal + - Class: flatland_viz/PauseSim + - Class: rviz_plugins/TaskGenerator + - Class: rviz/PublishPoint + Single click: true + Topic: /clicked_point + Value: true + Views: + Current: + Angle: -1.569939136505127 + Class: rviz/TopDownOrtho + Enable Stereo Rendering: + Stereo Eye Separation: 0.05999999865889549 + Stereo Focal Distance: 1 + Swap Stereo Eyes: false + Value: false + Invert Z Axis: false + Name: Current View + Near Clip Distance: 0.009999999776482582 + Scale: 38.79127883911133 + Target Frame: + X: 2.8734543323516846 + Y: -0.42915862798690796 + Saved: ~ +Window Geometry: + Displays: + collapsed: false + Height: 1043 + Hide Left Dock: false + Hide Right Dock: false + QMainWindow State: 000000ff00000000fd0000000400000000000002b4000003b9fc0200000005fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000005e80000039500000198000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d000003b9000000c900ffffff000000010000010f00000270fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000002800000270000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004a00000003efc0100000002fb0000000800540069006d00650000000000000004a0000004f300fffffffb0000000800540069006d00650100000000000004500000000000000000000004c6000003b900000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 + Selection: + collapsed: false + Time: + collapsed: false + Tool Properties: + collapsed: false + Views: + collapsed: false + Width: 1920 + X: 0 + Y: 0 \ No newline at end of file diff --git a/arena_bringup/rviz/nav_jackal.rviz b/arena_bringup/rviz/nav_jackal.rviz index 29ef5766a..aebb5f98c 100755 --- a/arena_bringup/rviz/nav_jackal.rviz +++ b/arena_bringup/rviz/nav_jackal.rviz @@ -5,14 +5,13 @@ Panels: Property Tree Widget: Expanded: - /robot1 - - /robot1/my_robot1 - /robot1/Goal Pose1 - /Global Plan1/teb1 - /Sensors1/LaserScan1 - /obstacles1 - /obstacles1/dynamic1/301 Splitter Ratio: 0.4374079406261444 - Tree Height: 787 + Tree Height: 475 - Class: rviz/Selection Name: Selection - Class: rviz/Tool Properties @@ -1252,18 +1251,18 @@ Visualization Manager: Invert Z Axis: false Name: Current View Near Clip Distance: 0.009999999776482582 - Scale: 46.09282302856445 + Scale: 25.905818939208984 Target Frame: - X: 3.297379970550537 - Y: 2.1553478240966797 + X: 11.80865478515625 + Y: 8.243291854858398 Saved: ~ Window Geometry: Displays: collapsed: false - Height: 1016 + Height: 704 Hide Left Dock: false Hide Right Dock: false - QMainWindow State: 000000ff00000000fd00000004000000000000029e0000039efc0200000005fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000003be0000025d00000198000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d0000039e000000c900ffffff000000010000010f00000270fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000002800000270000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004a00000003efc0100000002fb0000000800540069006d00650000000000000004a0000004f300fffffffb0000000800540069006d00650100000000000004500000000000000000000004940000039e00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 + QMainWindow State: 000000ff00000000fd0000000400000000000001ab00000266fc0200000005fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000003be0000025d00000198000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d00000266000000c900ffffff000000010000010f00000270fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000002800000270000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004a00000003efc0100000002fb0000000800540069006d00650000000000000004a0000004f300fffffffb0000000800540069006d006501000000000000045000000000000000000000035d0000026600000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 Selection: collapsed: false Time: @@ -1272,6 +1271,6 @@ Window Geometry: collapsed: false Views: collapsed: false - Width: 1848 + Width: 1294 X: 72 Y: 27 diff --git a/arena_marl/CMakeLists.txt b/arena_marl/CMakeLists.txt new file mode 100755 index 000000000..7fd10c43d --- /dev/null +++ b/arena_marl/CMakeLists.txt @@ -0,0 +1,213 @@ +cmake_minimum_required(VERSION 3.0.2) +project(arena_marl) + +## Compile as C++11, supported in ROS Kinetic and newer +# add_compile_options(-std=c++11) + +## Find catkin macros and libraries +## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) +## is used, also find other catkin packages +find_package(catkin REQUIRED COMPONENTS + geometry_msgs + nav_msgs + roscpp + rospy + sensor_msgs + tf2 + tf2_geometry_msgs + tf2_ros + flatland_msgs +) + +## System dependencies are found with CMake's conventions +# find_package(Boost REQUIRED COMPONENTS system) + + +## Uncomment this if the package has a setup.py. This macro ensures +## modules and global scripts declared therein get installed +## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html +catkin_python_setup() + +################################################ +## Declare ROS messages, services and actions ## +################################################ + +## To declare and build messages, services or actions from within this +## package, follow these steps: +## * Let MSG_DEP_SET be the set of packages whose message types you use in +## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). +## * In the file package.xml: +## * add a build_depend tag for "message_generation" +## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET +## * If MSG_DEP_SET isn't empty the following dependency has been pulled in +## but can be declared for certainty nonetheless: +## * add a exec_depend tag for "message_runtime" +## * In this file (CMakeLists.txt): +## * add "message_generation" and every package in MSG_DEP_SET to +## find_package(catkin REQUIRED COMPONENTS ...) +## * add "message_runtime" and every package in MSG_DEP_SET to +## catkin_package(CATKIN_DEPENDS ...) +## * uncomment the add_*_files sections below as needed +## and list every .msg/.srv/.action file to be processed +## * uncomment the generate_messages entry below +## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) + +## Generate messages in the 'msg' folder +# add_message_files( +# FILES +# Message1.msg +# Message2.msg +# ) + +## Generate services in the 'srv' folder +# add_service_files( +# FILES +# Service1.srv +# Service2.srv +# ) + +## Generate actions in the 'action' folder +# add_action_files( +# FILES +# Action1.action +# Action2.action +# ) + +## Generate added messages and services with any dependencies listed here +# generate_messages( +# DEPENDENCIES +# geometry_msgs# nav_msgs# sensor_msgs# tf2_geometry_msgs +# ) + +################################################ +## Declare ROS dynamic reconfigure parameters ## +################################################ + +## To declare and build dynamic reconfigure parameters within this +## package, follow these steps: +## * In the file package.xml: +## * add a build_depend and a exec_depend tag for "dynamic_reconfigure" +## * In this file (CMakeLists.txt): +## * add "dynamic_reconfigure" to +## find_package(catkin REQUIRED COMPONENTS ...) +## * uncomment the "generate_dynamic_reconfigure_options" section below +## and list every .cfg file to be processed + +## Generate dynamic reconfigure parameters in the 'cfg' folder +# generate_dynamic_reconfigure_options( +# cfg/DynReconf1.cfg +# cfg/DynReconf2.cfg +# ) + +################################### +## catkin specific configuration ## +################################### +## The catkin_package macro generates cmake config files for your package +## Declare things to be passed to dependent projects +## INCLUDE_DIRS: uncomment this if your package contains header files +## LIBRARIES: libraries you create in this project that dependent projects also need +## CATKIN_DEPENDS: catkin_packages dependent projects also need +## DEPENDS: system dependencies of this project that dependent projects also need +catkin_package( +# INCLUDE_DIRS include +# LIBRARIES arena_local_planner_drl +# CATKIN_DEPENDS geometry_msgs nav_msgs roscpp rospy sensor_msgs tf2 tf2_geometry_msgs tf2_ros +# DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( +# include + scripts + ${catkin_INCLUDE_DIRS} +) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/arena_local_planner_drl.cpp +# ) + +## Add cmake target dependencies of the library +## as an example, code may need to be generated before libraries +## either from message generation or dynamic reconfigure +# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Declare a C++ executable +## With catkin_make all packages are built within a single CMake context +## The recommended prefix ensures that target names across packages don't collide +# add_executable(${PROJECT_NAME}_node src/arena_local_planner_drl_node.cpp) + +## Rename C++ executable without prefix +## The above recommended prefix causes long target names, the following renames the +## target back to the shorter version for ease of user use +## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" +# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") + +## Add cmake target dependencies of the executable +## same as for the library above +# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Specify libraries to link a library or executable target against +# target_link_libraries(${PROJECT_NAME}_node +# ${catkin_LIBRARIES} +# ) + +############# +## Install ## +############# + +# all install targets should use catkin DESTINATION variables +# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html + +## Mark executable scripts (Python etc.) for installation +## in contrast to setup.py, you can choose the destination +catkin_install_python(PROGRAMS +# scripts/env/flatland_gym_env.py + DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) + +## Mark executables for installation +## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html +# install(TARGETS ${PROJECT_NAME}_node +# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark libraries for installation +## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html +# install(TARGETS ${PROJECT_NAME} +# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION} +# ) + +## Mark cpp header files for installation +# install(DIRECTORY include/${PROJECT_NAME}/ +# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} +# FILES_MATCHING PATTERN "*.h" +# PATTERN ".svn" EXCLUDE +# ) + +## Mark other files for installation (e.g. launch and bag files, etc.) +# install(FILES +# # myfile1 +# # myfile2 +# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +# ) + +############# +## Testing ## +############# + +## Add gtest based cpp test target and link libraries +# catkin_add_gtest(${PROJECT_NAME}-test test/test_arena_local_planner_drl.cpp) +# if(TARGET ${PROJECT_NAME}-test) +# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) +# endif() + +## Add folders to be run by python nosetests +# catkin_add_nosetests(test) diff --git a/arena_marl/marl_agent/__init__.py b/arena_marl/marl_agent/__init__.py new file mode 100755 index 000000000..e69de29bb diff --git a/arena_marl/marl_agent/envs/__init__.py b/arena_marl/marl_agent/envs/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/arena_marl/marl_agent/envs/pettingzoo_env.py b/arena_marl/marl_agent/envs/pettingzoo_env.py new file mode 100644 index 000000000..572365e4a --- /dev/null +++ b/arena_marl/marl_agent/envs/pettingzoo_env.py @@ -0,0 +1,390 @@ +"""PettingZoo Environment for Single-/Multi Agent Reinforcement Learning""" +import numpy as np +import rospy +from time import sleep +from typing import List, Tuple, Dict, Any, Union, Callable +from gym import spaces +from pettingzoo import * +from pettingzoo.utils import from_parallel, to_parallel +from warnings import warn + +import supersuit as ss + +from arena_marl.marl_agent.utils.supersuit_utils import MarkovVectorEnv_patched +from arena_navigation.arena_local_planner.learning_based.arena_local_planner_drl.rl_agent.training_agent_wrapper import ( + TrainingDRLAgent, +) +from task_generator.task_generator.marl_tasks import get_MARL_task +from flatland_msgs.srv import StepWorld, StepWorldRequest + +# from marl_agent.utils.supersuit_utils import * +# from rl_agent.utils.supersuit_utils import MarkovVectorEnv_patched + + +def env_fn(**kwargs: Dict[str, Any]): # -> VecEnv: + """ + The env function wraps the environment in 3 wrappers by default. These + wrappers contain logic that is common to many pettingzoo environments. + We recommend you use at least the OrderEnforcingWrapper on your own environment + to provide sane error messages. You can find full documentation for these methods + elsewhere in the developer documentation. + """ + env = FlatlandPettingZooEnv(**kwargs) + env = from_parallel(env) + env = ss.pad_action_space_v0(env) + env = ss.pad_observations_v0(env) + env = to_parallel(env) + env = MarkovVectorEnv_patched(env, black_death=True) + return env + + +class FlatlandPettingZooEnv(ParallelEnv): + """The SuperSuit Parallel environment steps every live agent at once.""" + + def __init__( + self, + num_agents: int, + agent_list_fn: Callable[[int, str, str, str, str], List[TrainingDRLAgent]], + PATHS: dict, + ns: str = None, + task_mode: str = "staged", + max_num_moves_per_eps: int = 1000, + agent_list_kwargs: Dict[str, Any] = None, + ) -> None: + """Initialization method for the Arena-Rosnav Pettingzoo Environment. + + Args: + num_agents (int): Number of possible agents. + agent_list_fn (Callable[ [int, str, str, str, str], List[TrainingDRLAgent] ]): Initialization function for the agents. \ + Returns a list of agent instances. + ns (str, optional): Environments' ROS namespace. There should only be one env per ns. Defaults to None. + task_mode (str, optional): Navigation task mode for the agents. Modes to chose from: ['random', 'staged']. \ + Defaults to "random". + max_num_moves_per_eps (int, optional): Maximum number of moves per episode. Defaults to 1000. + + Note: + These attributes should not be changed after initialization: + - possible_agents + - action_spaces + - observation_spaces + """ + self._ns = "" if ns is None or not ns else f"{ns}/" + self._is_train_mode = rospy.get_param("/train_mode") + self.metadata = {} + + self.agent_list: List[TrainingDRLAgent] = agent_list_fn( + num_agents, ns=ns, **(agent_list_kwargs or {}) + ) + + self.agents = [] + # list containing the unique robot namespaces + # used as identifier + self.possible_agents = [a._robot_sim_ns for a in self.agent_list] + self.agent_name_mapping = dict( + zip(self.possible_agents, list(range(len(self.possible_agents)))) + ) + self.agent_object_mapping = dict(zip(self.possible_agents, self.agent_list)) + self.terminal_observation = {} + + self._validate_agent_list() + + # task manager + self.task_manager = get_MARL_task( + ns=ns, + mode=task_mode, + robot_ids=[a._robot_sim_ns for a in self.agent_list], + PATHS=PATHS, + ) + + # service clients + if self._is_train_mode: + self._service_name_step = f"{self._ns}step_world" + self._sim_step_client = rospy.ServiceProxy( + self._service_name_step, StepWorld + ) + + self._max_num_moves = max_num_moves_per_eps + self.action_provided, self.curr_actions = False, {} + + def observation_space(self, agent: str) -> spaces.Box: + """Returns specific agents' observation space. + + Args: + agent (str): Agent name as given in ``self.possible_agents``. + + Returns: + spaces.Box: Observation space of type _gym.spaces_. + """ + return self.agent_object_mapping[agent].observation_space + + def action_space(self, agent: str) -> spaces.Box: + """Returns specific agents' action space. + + Args: + agent (str): Agent name as given in ``self.possible_agents``. + + Returns: + spaces.Box: Action space of type _gym.spaces_. + """ + return self.agent_object_mapping[agent].action_space + + def _validate_agent_list(self) -> None: + """Validates the agent list. + + Description: + Checks if all agents are named differently. That means each robot adresses its own namespace. + """ + assert len(self.possible_agents) == len( + set(self.possible_agents) + ), "Robot names and thus their namespaces, have to be unique!" + + def reset(self) -> Dict[str, np.ndarray]: + """Resets the environment and returns the new set of observations (keyed by the agent name) + + Description: + This method is called when all agents reach an end criterion. End criterions are: exceeding the \ + max number of steps per episode, crash or reaching the end criterion. + The scene is then reseted. + + Returns: + Dict[str, np.ndarray]: Observations dictionary in {_agent name_: _respective observations_}. + """ + self.agents, self.num_moves, self.terminal_observation = ( + self.possible_agents[:], + 0, + {}, + ) + + # reset the reward calculator + for agent in self.agents: + self.agent_object_mapping[agent].reward_calculator.reset() + + # reset the task manager + self.task_manager.reset() + # step one timestep in the simulation to update the scene + if self._is_train_mode: + self._sim_step_client() + + # get first observations for the next episode + observations = { + agent: self.agent_object_mapping[agent].get_observations()[0] + for agent in self.agents + } + + self.action_provided, self.curr_actions = False, {} + return observations + + def step( + self, actions: Dict[str, np.ndarray] + ) -> Tuple[ + Dict[str, np.ndarray], + Dict[str, float], + Dict[str, bool], + Dict[str, Dict[str, Any]], + ]: + """Simulates one timestep and returns the most recent environment information. + + Description: + This function takes in velocity commands and applies those to the simulation. + Afterwards, agents' observations are retrieved from the current timestep and \ + the reward is calculated. \ + Proceeding with the ``RewardCalculator`` processing the observations and detecting certain events like \ + if a crash occured, a goal was reached. Those informations are returned in the '*reward\_info*' \ + which itself is a dictionary. \ + Eventually, dictionaries containing every agents' observations, rewards, done flags and \ + episode information is returned. + + Args: + actions (Dict[str, np.ndarray]): Actions dictionary in {_agent name_: _respective observations_}. + + Returns: + Tuple[ Dict[str, np.ndarray], Dict[str, float], Dict[str, bool], Dict[str, Dict[str, Any]], ]: Observations, \ + rewards, done flags and episode informations dictionary. + + Note: + Done reasons are mapped as follows: __0__ - episode length exceeded, __1__ - agent crashed, \ + __2__ - agent reached its goal. + """ + # If a user passes in actions with no agents, then just return empty observations, etc. + if not actions: + self.agents = [] + return {}, {}, {}, {} + + # actions + for agent in self.possible_agents: + if agent in actions: + self.agent_object_mapping[agent].publish_action(actions[agent]) + else: + noop = np.zeros(shape=self.action_space(agent).shape) + self.agent_object_mapping[agent].publish_action(noop) + + # fast-forward simulation + self.call_service_takeSimStep() + self.num_moves += 1 + + merged_obs, rewards, reward_infos = {}, {}, {} + + for agent in actions: + # observations + merged, _dict = self.agent_object_mapping[agent].get_observations() + merged_obs[agent] = merged + + # rewards and infos + reward, reward_info = self.agent_object_mapping[agent].get_reward( + action=actions[agent], obs_dict=_dict + ) + rewards[agent], reward_infos[agent] = reward, reward_info + + # dones & infos + dones, infos = self._get_dones(reward_infos), self._get_infos(reward_infos) + + # remove done agents from the active agents list + self.agents = [agent for agent in self.agents if not dones[agent]] + + for agent in self.possible_agents: + # agent is done in this episode + if agent in dones and dones[agent]: + self.terminal_observation[agent] = merged_obs[agent] + infos[agent]["terminal_observation"] = merged_obs[agent] + # agent is done since atleast last episode + elif agent not in self.agents: + if agent not in infos: + infos[agent] = {} + infos[agent]["terminal_observation"] = self.terminal_observation[agent] + + return merged_obs, rewards, dones, infos + + def apply_action(self, actions: np.ndarray) -> None: + """_summary_ + + Args: + action (np.ndarray): _description_ + + Returns: + _type_: _description_ + """ + if self.action_provided: + warn( + "Disobeyed method order. Called 'apply_action' multiple times without retrieving states." + ) + + # If a user passes in actions with no agents, then just return empty observations, etc. + if not actions: + self.agents = [] + return {}, {}, {}, {} + + # actions + for agent in self.possible_agents: + if agent in actions: + self.agent_object_mapping[agent].publish_action(actions[agent]) + else: + noop = np.zeros(shape=self.action_space(agent).shape) + self.agent_object_mapping[agent].publish_action(noop) + + self.num_moves += 1 + self.action_provided, self.curr_actions = True, actions + + def get_states( + self, + ) -> Tuple[ + Dict[str, np.ndarray], Dict[str, float], Dict[str, bool], Dict[str, Any] + ]: + assert self.action_provided, "No actions provided" + merged_obs, rewards, reward_infos = {}, {}, {} + + for agent in self.curr_actions: + # observations + merged, _dict = self.agent_object_mapping[agent].get_observations() + merged_obs[agent] = merged + + # rewards and infos + reward, reward_info = self.agent_object_mapping[agent].get_reward( + action=self.curr_actions[agent], obs_dict=_dict + ) + rewards[agent], reward_infos[agent] = reward, reward_info + + # dones & infos + dones, infos = self._get_dones(reward_infos), self._get_infos(reward_infos) + + # remove done agents from the active agents list + self.agents = [agent for agent in self.agents if not dones[agent]] + + for agent in self.possible_agents: + # agent is done in this episode + if agent in dones and dones[agent]: + self.terminal_observation[agent] = merged_obs[agent] + infos[agent]["terminal_observation"] = merged_obs[agent] + # agent is done since atleast last episode + elif agent not in self.agents: + if agent not in infos: + infos[agent] = {} + infos[agent]["terminal_observation"] = self.terminal_observation[agent] + + return merged_obs, rewards, dones, infos + + @property + def max_num_agents(self): + return len(self.agents) + + def call_service_takeSimStep(self, t: float = None): + """Fast-forwards the simulation. + + Description: + Simulates the Flatland simulation for a certain amount of seconds. + + Args: + t (float, optional): Time in seconds. When ``t`` is None, time is forwarded by ``step_size`` s \ + (ROS parameter). Defaults to None. + """ + request = StepWorldRequest() if t is None else StepWorldRequest(t) + + try: + response = self._sim_step_client(request) + rospy.logdebug("step service=", response) + except rospy.ServiceException as e: + rospy.logdebug(f"step Service call failed: {e}") + + def _get_dones(self, reward_infos: Dict[str, Dict[str, Any]]) -> Dict[str, bool]: + """Extracts end flags from the reward information dictionary. + + Args: + reward_infos (Dict[str, Dict[str, Any]]): Episode information from the ``RewardCalculator`` in \ + {_agent name_: _reward infos_}. + + Returns: + Dict[str, bool]: Dones dictionary in {_agent name_: _done flag_} + + Note: + Relevant dictionary keys are: "is_done", "is_success", "done_reason" + """ + return ( + {agent: reward_infos[agent]["is_done"] for agent in self.agents} + if self.num_moves < self._max_num_moves + else {agent: True for agent in self.agents} + ) + + def _get_infos( + self, reward_infos: Dict[str, Dict[str, Any]] + ) -> Dict[str, Dict[str, Any]]: + """Extracts the current episode information from the reward information dictionary. + + Args: + reward_infos (Dict[str, Dict[str, Any]]): Episode information from the ``RewardCalculator`` in \ + {_agent name_: _reward infos_}. + + Returns: + Dict[str, Dict[str, Any]]: Info dictionary in {_agent name_: _done flag_} + + Note: + Relevant dictionary keys are: "is_done", "is_success", "done_reason" + """ + infos = {agent: {} for agent in self.agents} + for agent in self.agents: + if reward_infos[agent]["is_done"]: + infos[agent] = reward_infos[agent] + elif self.num_moves >= self._max_num_moves: + infos[agent] = { + "done_reason": 0, + "is_success": 0, + } + return infos diff --git a/arena_marl/marl_agent/utils/__init__.py b/arena_marl/marl_agent/utils/__init__.py new file mode 100755 index 000000000..e69de29bb diff --git a/arena_marl/marl_agent/utils/action_collector.py b/arena_marl/marl_agent/utils/action_collector.py new file mode 100755 index 000000000..7c95eea27 --- /dev/null +++ b/arena_marl/marl_agent/utils/action_collector.py @@ -0,0 +1,68 @@ +import rospy +import numpy as np + +from tf.transformations import * +from geometry_msgs.msg import Twist +from gym import spaces + + +class ActionCollector: + def __init__(self): + self.v_max_ = 0.8 + self.w_max_ = 1.2 + self.action_library = { + 0: {"linear": 0.0, "angular": -self.w_max_}, + 1: {"linear": self.v_max_, "angular": 0.0}, + 2: {"linear": 0.0, "angular": self.w_max_}, + 3: {"linear": self.v_max_, "angular": self.w_max_ / 2}, + 4: {"linear": self.v_max_, "angular": -self.w_max_ / 2}, + 5: {"linear": 0.0, "angular": 0.0}, + } + self.N_DISCRETE_ACTIONS = len(self.action_library) + self.action_space = spaces.Discrete(self.N_DISCRETE_ACTIONS) + + def get_action_space(self): + return self.action_space + + def get_cmd_vel(self, action_id): + vel_msg = Twist() + vel_msg.linear.x = self.action_library[action_id]["linear"] + vel_msg.angular.z = self.action_library[action_id]["angular"] + return vel_msg + + +if __name__ == "__main__": + action_collector = ActionCollector() + print(action_collector.get_cmd_vel(1)) + + box = spaces.Box(low=3.0, high=4, shape=(2, 2)) + print(box) + box.seed(4) + for _ in range(1): + print(box.sample()) + + min_position = 0 + max_position = 10 + max_speed = 2 + goal_position = 0.5 + low = np.array([min_position, -max_speed]) + high = np.array([max_position, max_speed]) + action_space = spaces.Discrete(3) # action space + observation_space = spaces.Box(low, high) # + print("*" * 10) + print(observation_space) + for _ in range(2): + print(observation_space.sample()) + + observation_space = spaces.Tuple( + ( + spaces.Box(low=0, high=10, shape=(10,), dtype=np.float32), + spaces.Box(low=-10, high=0, shape=(3 + 2,), dtype=np.float32), + ) + ) + print("2" * 10) + print(observation_space.sample()) + print(type(observation_space.sample())) + + reward = spaces.Discrete(4) + print(type(reward.sample())) diff --git a/arena_marl/marl_agent/utils/debug.py b/arena_marl/marl_agent/utils/debug.py new file mode 100755 index 000000000..0349734d2 --- /dev/null +++ b/arena_marl/marl_agent/utils/debug.py @@ -0,0 +1,16 @@ +import time +from functools import wraps + + +def timeit(f): + @wraps(f) + def timed(*args, **kw): + + ts = time.time() + result = f(*args, **kw) + te = time.time() + + print("func:%r args:[%r, %r] took: %2.4f sec" % (f.__name__, args, kw, te - ts)) + return result + + return timed diff --git a/arena_marl/marl_agent/utils/observation_collector.py b/arena_marl/marl_agent/utils/observation_collector.py new file mode 100755 index 000000000..7181ed443 --- /dev/null +++ b/arena_marl/marl_agent/utils/observation_collector.py @@ -0,0 +1,300 @@ +#! /usr/bin/env python +from typing import Tuple + +from numpy.core.numeric import normalize_axis_tuple +import rospy +import random +import numpy as np +from collections import deque + +import time # for debuging +import threading + +# observation msgs +from sensor_msgs.msg import LaserScan +from geometry_msgs.msg import Pose2D, PoseStamped, Twist +from nav_msgs.msg import Path +from rosgraph_msgs.msg import Clock +from nav_msgs.msg import Odometry + +# message filter +import message_filters + +# for transformations +from tf.transformations import * + +from gym import spaces +import numpy as np + + +class ObservationCollector: + def __init__( + self, + ns: str, + num_lidar_beams: int, + lidar_range: float, + ): + """a class to collect and merge observations + + Args: + num_lidar_beams (int): [description] + lidar_range (float): [description] + """ + """SET A METHOD TO EXTRACT IF MARL IS BEIN REQUESTED""" + MARL = rospy.get_param("num_robots") > 1 + + self.ns = ns + if ns is None or ns == "": + self.ns_prefix = "" + else: + self.ns_prefix = ( + "/" + ns + "/" if not ns.endswith("/") else "/" + ns + ) + + # define observation_space + self.observation_space = ObservationCollector._stack_spaces( + ( + spaces.Box( + low=0, + high=lidar_range, + shape=(num_lidar_beams,), + dtype=np.float32, + ), + spaces.Box(low=0, high=10, shape=(1,), dtype=np.float32), + spaces.Box( + low=-np.pi, high=np.pi, shape=(1,), dtype=np.float32 + ), + ) + ) + + self._laser_num_beams = num_lidar_beams + + self._clock = Clock() + self._scan = LaserScan() + self._robot_pose = Pose2D() + self._robot_vel = Twist() + self._subgoal = Pose2D() + self._globalplan = np.array([]) + + # subscriptions + self._scan_sub = rospy.Subscriber( + f"{self.ns_prefix}scan", + LaserScan, + self.callback_scan, + tcp_nodelay=True, + ) + self._robot_state_sub = rospy.Subscriber( + f"{self.ns_prefix}odom", + Odometry, + self.callback_robot_state, + tcp_nodelay=True, + ) + + # self._clock_sub = rospy.Subscriber( + # f'{self.ns_prefix}clock', Clock, self.callback_clock, tcp_nodelay=True) + + # when using MARL listen to goal directly since no intermediate planner is considered + goal_topic = ( + f"{self.ns_prefix}goal" if MARL else f"{self.ns_prefix}subgoal" + ) + self._subgoal_sub = rospy.Subscriber( + f"{goal_topic}", PoseStamped, self.callback_subgoal + ) + self._globalplan_sub = rospy.Subscriber( + f"{self.ns_prefix}globalPlan", Path, self.callback_global_plan + ) + + # synchronization parameters + self._first_sync_obs = ( + True # whether to return first sync'd obs or most recent + ) + self.max_deque_size = 10 + self._sync_slop = 0.1 + + self._laser_deque = deque() + self._rs_deque = deque() + + def get_observation_space(self): + return self.observation_space + + def get_observations(self): + # try to retrieve sync'ed obs + laser_scan, robot_pose = self.get_sync_obs() + if laser_scan is not None and robot_pose is not None: + # print("Synced successfully") + self._scan = laser_scan + self._robot_pose = robot_pose + # else: + # print("Not synced") + if len(self._scan.ranges) > 0: + scan = self._scan.ranges.astype(np.float32) + else: + scan = np.zeros(self._laser_num_beams, dtype=float) + + rho, theta = ObservationCollector._get_goal_pose_in_robot_frame( + self._subgoal, self._robot_pose + ) + merged_obs = np.hstack([scan, np.array([rho, theta])]) + + obs_dict = { + "laser_scan": scan, + "goal_in_robot_frame": [rho, theta], + "global_plan": self._globalplan, + "robot_pose": self._robot_pose, + } + + self._laser_deque.clear() + self._rs_deque.clear() + return merged_obs, obs_dict + + @staticmethod + def _get_goal_pose_in_robot_frame( + goal_pos: Pose2D, robot_pos: Pose2D + ) -> Tuple[float, float]: + y_relative = goal_pos.y - robot_pos.y + x_relative = goal_pos.x - robot_pos.x + rho = (x_relative ** 2 + y_relative ** 2) ** 0.5 + theta = ( + np.arctan2(y_relative, x_relative) - robot_pos.theta + 4 * np.pi + ) % (2 * np.pi) - np.pi + return rho, theta + + def get_sync_obs(self): + laser_scan = None + robot_pose = None + + # print(f"laser deque: {len(self._laser_deque)}, robot state deque: {len(self._rs_deque)}") + while len(self._rs_deque) > 0 and len(self._laser_deque) > 0: + laser_scan_msg = self._laser_deque.popleft() + robot_pose_msg = self._rs_deque.popleft() + + laser_stamp = laser_scan_msg.header.stamp.to_sec() + robot_stamp = robot_pose_msg.header.stamp.to_sec() + + while abs(laser_stamp - robot_stamp) > self._sync_slop: + if laser_stamp > robot_stamp: + if len(self._rs_deque) == 0: + return laser_scan, robot_pose + robot_pose_msg = self._rs_deque.popleft() + robot_stamp = robot_pose_msg.header.stamp.to_sec() + else: + if len(self._laser_deque) == 0: + return laser_scan, robot_pose + laser_scan_msg = self._laser_deque.popleft() + laser_stamp = laser_scan_msg.header.stamp.to_sec() + + laser_scan = self.process_scan_msg(laser_scan_msg) + robot_pose, _ = self.process_robot_state_msg(robot_pose_msg) + + if self._first_sync_obs: + break + + # print(f"Laser_stamp: {laser_stamp}, Robot_stamp: {robot_stamp}") + return laser_scan, robot_pose + + def callback_clock(self, msg_Clock): + self._clock = msg_Clock.clock.to_sec() + return + + def callback_subgoal(self, msg_Subgoal): + self._subgoal = self.process_subgoal_msg(msg_Subgoal) + return + + def callback_global_plan(self, msg_global_plan): + self._globalplan = ObservationCollector.process_global_plan_msg( + msg_global_plan + ) + return + + def callback_scan(self, msg_laserscan): + if len(self._laser_deque) == self.max_deque_size: + self._laser_deque.popleft() + self._laser_deque.append(msg_laserscan) + + def callback_robot_state(self, msg_robotstate): + if len(self._rs_deque) == self.max_deque_size: + self._rs_deque.popleft() + self._rs_deque.append(msg_robotstate) + + def callback_observation_received( + self, msg_LaserScan, msg_RobotStateStamped + ): + # process sensor msg + self._scan = self.process_scan_msg(msg_LaserScan) + self._robot_pose, self._robot_vel = self.process_robot_state_msg( + msg_RobotStateStamped + ) + self.obs_received = True + return + + def process_scan_msg(self, msg_LaserScan: LaserScan): + # remove_nans_from_scan + self._scan_stamp = msg_LaserScan.header.stamp.to_sec() + scan = np.array(msg_LaserScan.ranges) + scan[np.isnan(scan)] = msg_LaserScan.range_max + msg_LaserScan.ranges = scan + return msg_LaserScan + + def process_robot_state_msg(self, msg_Odometry): + pose3d = msg_Odometry.pose.pose + twist = msg_Odometry.twist.twist + return self.pose3D_to_pose2D(pose3d), twist + + def process_pose_msg(self, msg_PoseWithCovarianceStamped): + # remove Covariance + pose_with_cov = msg_PoseWithCovarianceStamped.pose + pose = pose_with_cov.pose + return self.pose3D_to_pose2D(pose) + + def process_subgoal_msg(self, msg_Subgoal): + return self.pose3D_to_pose2D(msg_Subgoal.pose) + + @staticmethod + def process_global_plan_msg(globalplan): + global_plan_2d = list( + map( + lambda p: ObservationCollector.pose3D_to_pose2D(p.pose), + globalplan.poses, + ) + ) + return np.array(list(map(lambda p2d: [p2d.x, p2d.y], global_plan_2d))) + + @staticmethod + def pose3D_to_pose2D(pose3d): + pose2d = Pose2D() + pose2d.x = pose3d.position.x + pose2d.y = pose3d.position.y + quaternion = ( + pose3d.orientation.x, + pose3d.orientation.y, + pose3d.orientation.z, + pose3d.orientation.w, + ) + euler = euler_from_quaternion(quaternion) + yaw = euler[2] + pose2d.theta = yaw + return pose2d + + @staticmethod + def _stack_spaces(ss: Tuple[spaces.Box]): + low = [] + high = [] + for space in ss: + low.extend(space.low.tolist()) + high.extend(space.high.tolist()) + return spaces.Box(np.array(low).flatten(), np.array(high).flatten()) + + +if __name__ == "__main__": + + rospy.init_node("states", anonymous=True) + print("start") + + state_collector = ObservationCollector("sim1/", 360, 10) + i = 0 + r = rospy.Rate(100) + while i <= 1000: + i = i + 1 + obs = state_collector.get_observations() + + time.sleep(0.001) diff --git a/arena_marl/marl_agent/utils/reward.py b/arena_marl/marl_agent/utils/reward.py new file mode 100755 index 000000000..d4b53cb16 --- /dev/null +++ b/arena_marl/marl_agent/utils/reward.py @@ -0,0 +1,472 @@ +"""Reward Calculator for DRL""" +import numpy as np +import scipy.spatial + +from geometry_msgs.msg import Pose2D +from typing import Dict, Tuple, Union + +from rl_agent.utils.reward import RewardCalculator + +class RewardCalculator(RewardCalculator): + def __init__( + self, + robot_radius: float, + safe_dist: float, + goal_radius: float, + rule: str = "rule_00", + extended_eval: bool = False, + ): + """A facotry class for reward calculation. Holds various reward functions. + + An overview of the reward functions can be found under: + https://github.com/ignc-research/arena-rosnav/blob/local_planner_subgoalmode/docs/DRL-Training.md#reward-functions + + Possible reward functions: "_rule_00_", "_rule_01_", "_rule_02_", "_rule_03_", "_rule_04_" + + Args: + robot_radius (float): Robots' radius in meters. + safe_dist (float): Robots' safe distance in meters. + goal_radius (float): Radius of the goal. + rule (str, optional): The desired reward function name. Defaults to "rule_00". + extended_eval (bool, optional): Extended evaluation mode. Defaults to False. + """ + self.curr_reward = 0 + # additional info will be stored here and be returned alonge with reward. + self.info = {} + self.robot_radius = robot_radius + self.goal_radius = goal_radius + self.last_goal_dist = None + self.last_dist_to_path = None + self.last_action = None + self.safe_dist = robot_radius + safe_dist + self._extended_eval = extended_eval + + self.kdtree = None + + self._cal_funcs = { + "rule_00": RewardCalculator._cal_reward_rule_00, + "rule_01": RewardCalculator._cal_reward_rule_01, + "rule_02": RewardCalculator._cal_reward_rule_02, + "rule_03": RewardCalculator._cal_reward_rule_03, + "rule_04": RewardCalculator._cal_reward_rule_04, + } + self.cal_func = self._cal_funcs[rule] + + def reset(self) -> None: + """Resets variables related to the episode.""" + self.last_goal_dist = None + self.last_dist_to_path = None + self.last_action = None + self.kdtree = None + + def _reset(self) -> None: + """Resets variables related to current step.""" + self.curr_reward = 0 + self.info = {} + + def get_reward( + self, + laser_scan: np.ndarray, + goal_in_robot_frame: Tuple[float, float], + *args, + **kwargs + ) -> Tuple[float, Dict[str, Union[str, int, bool]]]: + """Returns reward and info to the gym environment. + + Args: + laser_scan (np.ndarray): 2D laser scan data. + goal_in_robot_frame (Tuple[float, float]): Position (rho, theta) of the goal in the robot frame (polar coordinate). + + Returns: + Tuple[float, Dict[str, Union[str, int, bool]]]: Tuple of calculated rewards for the current step, \ + and the reward information dictionary. + """ + self._reset() + self.cal_func(self, laser_scan, goal_in_robot_frame, *args, **kwargs) + return self.curr_reward, self.info + + def _cal_reward_rule_00( + self, + laser_scan: np.ndarray, + goal_in_robot_frame: Tuple[float, float], + *args, + **kwargs + ): + """Reward function: '_rule\_00_' + + Description: + "rule_00" incorporates the most instinctive characteristics for learning navigation into its \ + reward calculation. The reward function is made up of only 4 summands, namely the success \ + reward, the collision reward, the danger reward and the progress reward. Similar reward functions \ + were utilized in numerous research projects and produced promising results. Thus, this \ + rule is chosen to be the basis for further experiments with extended versions of it. \ + + Args: + laser_scan (np.ndarray): 2D laser scan data. + goal_in_robot_frame (Tuple[float, float]): Position (rho, theta) of the goal in the robot frame (polar coordinate). + """ + self._reward_goal_reached(goal_in_robot_frame) + self._reward_safe_dist(laser_scan, punishment=0.25) + self._reward_collision(laser_scan) + self._reward_goal_approached( + goal_in_robot_frame, reward_factor=0.3, penalty_factor=0.4 + ) + + def _cal_reward_rule_01( + self, + laser_scan: np.ndarray, + goal_in_robot_frame: Tuple[float, float], + *args, + **kwargs + ): + """Reward function: '_rule\_01_' + + Description: + This reward function extends "rule 00" by adding a penalty factor that affects the current \ + reward like an abstract fuel consumption factor. In principle, a certain penalty is applied \ + for each action taken depending on the velocity and thus imposes a severer punishment for \ + dissipated driving. + + Args: + laser_scan (np.ndarray): 2D laser scan data. + goal_in_robot_frame (Tuple[float, float]): Position (rho, theta) of the goal in the robot frame (polar coordinate). + """ + self._reward_distance_traveled( + kwargs["action"], consumption_factor=0.0075 + ) + self._reward_goal_reached(goal_in_robot_frame, reward=15) + self._reward_safe_dist(laser_scan, punishment=0.25) + self._reward_collision(laser_scan, punishment=10) + self._reward_goal_approached( + goal_in_robot_frame, reward_factor=0.3, penalty_factor=0.4 + ) + + def _cal_reward_rule_02( + self, + laser_scan: np.ndarray, + goal_in_robot_frame: Tuple[float, float], + *args, + **kwargs + ): + """Reward function: '_rule\_02_' + + Description: + Previous reward functions required only basic information from the simulation. For this rule, \ + which builds on the reward function "rule 01", we introduced the assessment of the progress \ + regarding the global plan. The additional summand essentially rewards the agent for following \ + the global plan. It was implemented in order to test the effect of including the global plan in \ + the reward calculation. \ + Since "rule 02" shares almost the same reward function composition as "rule 01", similar performance \ + was expected to some extent. The desired behavior for this agent was to learn faster and \ + to drive more goal-oriented than the agent of "rule 01", as this rule was provided the global plan. \ + + Args: + laser_scan (np.ndarray): 2D laser scan data. + goal_in_robot_frame (Tuple[float, float]): Position (rho, theta) of the goal in the robot frame (polar coordinate). + """ + self._reward_distance_traveled( + kwargs["action"], consumption_factor=0.0075 + ) + self._reward_following_global_plan( + kwargs["global_plan"], kwargs["robot_pose"] + ) + self._reward_goal_reached(goal_in_robot_frame, reward=15) + self._reward_safe_dist(laser_scan, punishment=0.25) + self._reward_collision(laser_scan, punishment=10) + self._reward_goal_approached( + goal_in_robot_frame, reward_factor=0.3, penalty_factor=0.4 + ) + + def _cal_reward_rule_03( + self, + laser_scan: np.ndarray, + goal_in_robot_frame: Tuple[float, float], + *args, + **kwargs + ): + """Reward function: '_rule\_03_' + + Description: + The base of this rule is made up of summands from "rule 00". The two extra factors were \ + introduced in order to further leverage the global plan information for reward generation. \ + One that rewards the following of the global path and one for valuing the agents’ action - \ + positively, when it approaches the global plan - negatively when the robot distances itself \ + from the path. \ + + Args: + laser_scan (np.ndarray): 2D laser scan data. \ + goal_in_robot_frame (Tuple[float, float]): Position (rho, theta) of the goal in the robot frame (polar coordinate). \ + """ + self._reward_following_global_plan( + kwargs["global_plan"], kwargs["robot_pose"], kwargs["action"] + ) + if laser_scan.min() > self.safe_dist: + self._reward_distance_global_plan( + kwargs["global_plan"], + kwargs["robot_pose"], + reward_factor=0.2, + penalty_factor=0.3, + ) + else: + self.last_dist_to_path = None + self._reward_goal_reached(goal_in_robot_frame, reward=15) + self._reward_safe_dist(laser_scan, punishment=0.25) + self._reward_collision(laser_scan, punishment=10) + self._reward_goal_approached( + goal_in_robot_frame, reward_factor=0.3, penalty_factor=0.4 + ) + + def _cal_reward_rule_04( + self, + laser_scan: np.ndarray, + goal_in_robot_frame: Tuple[float, float], + *args, + **kwargs + ): + """Reward function: '_rule\_04_' + + Description: + This reward function extends "rule 03" with an additional term that punishes the agent for \ + abruptly changing the direction. Previous test runs, conducted right after the implementation, \ + evidenced that although the agent performed well on different tasks, the robot tended to drive \ + in tail motion. It was aimed to adjust this behavior by including this additional penalty term. \ + + Args: + laser_scan (np.ndarray): 2D laser scan data. + goal_in_robot_frame (Tuple[float, float]): Position (rho, theta) of the goal in the robot frame (polar coordinate). + """ + self._reward_abrupt_direction_change(kwargs["action"]) + self._reward_following_global_plan( + kwargs["global_plan"], kwargs["robot_pose"], kwargs["action"] + ) + if laser_scan.min() > self.safe_dist: + self._reward_distance_global_plan( + kwargs["global_plan"], + kwargs["robot_pose"], + reward_factor=0.2, + penalty_factor=0.3, + ) + else: + self.last_dist_to_path = None + self._reward_goal_reached(goal_in_robot_frame, reward=15) + self._reward_safe_dist(laser_scan, punishment=0.25) + self._reward_collision(laser_scan, punishment=10) + self._reward_goal_approached( + goal_in_robot_frame, reward_factor=0.3, penalty_factor=0.4 + ) + + def _reward_goal_reached( + self, goal_in_robot_frame: Tuple[float, float], reward: float = 15 + ): + """Reward for reaching the goal. + + Args: + goal_in_robot_frame (Tuple[float, float], optional): Position (rho, theta) of the goal in the robot frame (polar coordinate). + reward (float, optional): Reward amount for reaching the goal. Defaults to 15. + """ + if goal_in_robot_frame[0] < self.goal_radius: + self.curr_reward = reward + self.info["is_done"] = True + self.info["done_reason"] = 2 + self.info["is_success"] = 1 + else: + self.info["is_done"] = False + + def _reward_goal_approached( + self, + goal_in_robot_frame=Tuple[float, float], + reward_factor: float = 0.3, + penalty_factor: float = 0.5, + ): + """Reward for approaching the goal. + + Args: + goal_in_robot_frame ([type], optional): Position (rho, theta) of the goal in the robot frame (polar coordinate). Defaults to Tuple[float, float]. + reward_factor (float, optional): Factor to be multiplied when the difference between current distance to goal and the previous one is positive. \ + Defaults to 0.3. + penalty_factor (float, optional): Factor to be multiplied when the difference between current distance to goal and the previous one is negative. Defaults to 0.5. + """ + if self.last_goal_dist is not None: + # goal_in_robot_frame : [rho, theta] + + # higher negative weight when moving away from goal + # (to avoid driving unnecessary circles when train in contin. action space) + if (self.last_goal_dist - goal_in_robot_frame[0]) > 0: + w = reward_factor + else: + w = penalty_factor + reward = w * (self.last_goal_dist - goal_in_robot_frame[0]) + + # print("reward_goal_approached: {}".format(reward)) + self.curr_reward += reward + self.last_goal_dist = goal_in_robot_frame[0] + + def _reward_collision(self, laser_scan: np.ndarray, punishment: float = 10): + """Reward for colliding with an obstacle. + + Args: + laser_scan (np.ndarray): 2D laser scan data. + punishment (float, optional): Punishment amount for collisions. Defaults to 10. + """ + if laser_scan.min() <= self.robot_radius: + self.curr_reward -= punishment + + if not self._extended_eval: + self.info["is_done"] = True + self.info["done_reason"] = 1 + self.info["is_success"] = 0 + else: + self.info["crash"] = True + + def _reward_safe_dist( + self, laser_scan: np.ndarray, punishment: float = 0.15 + ): + """Reward for undercutting safe distance. + + Args: + laser_scan (np.ndarray): 2D laser scan data. + punishment (float, optional): Punishment amount. Could be applied in consecutive timesteps. \ + Defaults to 0.15. + """ + if laser_scan.min() < self.safe_dist: + self.curr_reward -= punishment + + if self._extended_eval: + self.info["safe_dist"] = True + + def _reward_not_moving( + self, action: np.ndarray = None, punishment: float = 0.01 + ): + """Reward for not moving. + + Args: + action (np.ndarray, optional): Array of shape (2,). First entry, linear velocity. \ + Second entry, angular velocity. Defaults to None. + punishment (float, optional): Punishment for not moving. Defaults to 0.01. + + Note: + Only applies half of the punishment amount when angular velocity is larger than zero. + """ + if action is not None and action[0] == 0.0: + self.curr_reward -= ( + punishment if action[1] == 0.0 else punishment / 2 + ) + + def _reward_distance_traveled( + self, + action: np.array = None, + punishment: float = 0.01, + consumption_factor: float = 0.005, + ): + """Reward for driving a certain distance. Supposed to represent "fuel consumption". + + Args: + action (np.array, optional): Array of shape (2,). First entry, linear velocity. \ + Second entry, angular velocity. Defaults to None. + punishment (float, optional): Punishment when action can't be retrieved. Defaults to 0.01. + consumption_factor (float, optional): Factor for the weighted velocity punishment. Defaults to 0.005. + """ + if action is None: + self.curr_reward -= punishment + else: + lin_vel = action[0] + ang_vel = action[1] + reward = (lin_vel + (ang_vel * 0.001)) * consumption_factor + self.curr_reward -= reward + + def _reward_distance_global_plan( + self, + global_plan: np.array, + robot_pose: Pose2D, + reward_factor: float = 0.1, + penalty_factor: float = 0.15, + ): + """Reward for approaching/veering away the global plan. + + Description: + Weighted difference between prior distance to global plan and current distance to global plan. + + Args: + global_plan (np.array): Array containing 2D poses. + robot_pose (Pose2D): Robot position. + reward_factor (float, optional): Factor to be multiplied when the difference between current \ + distance to global plan and the previous one is positive. Defaults to 0.1. + penalty_factor (float, optional): Factor to be multiplied when the difference between current \ + distance to global plan and the previous one is negative. Defaults to 0.15. + """ + if global_plan is not None and len(global_plan) != 0: + curr_dist_to_path, idx = self.get_min_dist2global_kdtree( + global_plan, robot_pose + ) + + if self.last_dist_to_path is not None: + if curr_dist_to_path < self.last_dist_to_path: + w = reward_factor + else: + w = penalty_factor + + self.curr_reward += w * ( + self.last_dist_to_path - curr_dist_to_path + ) + self.last_dist_to_path = curr_dist_to_path + + def _reward_following_global_plan( + self, + global_plan: np.array, + robot_pose: Pose2D, + action: np.array = None, + dist_to_path: float = 0.5, + ): + """Reward for travelling along the global plan. + + Args: + global_plan (np.array): Array containing 2D poses. + robot_pose (Pose2D): Robot position. + action (np.array, optional): action (np.ndarray, optional): Array of shape (2,). First entry, linear velocity. \ + Second entry, angular velocity. Defaults to None. + dist_to_path (float, optional): Minimum distance to the global path. Defaults to 0.5. + """ + if ( + global_plan is not None + and len(global_plan) != 0 + and action is not None + ): + curr_dist_to_path, idx = self.get_min_dist2global_kdtree( + global_plan, robot_pose + ) + + if curr_dist_to_path <= dist_to_path: + self.curr_reward += 0.1 * action[0] + + def get_min_dist2global_kdtree( + self, global_plan: np.array, robot_pose: Pose2D + ) -> Tuple[float, int]: + """Calculates minimal distance to global plan using kd-tree-search. + + Args: + global_plan (np.array): Array containing 2D poses. + robot_pose (Pose2D): Robot position. + + Returns: + Tuple[float, int]: Distance to the closes pose and index of the closes pose. + """ + if self.kdtree is None: + self.kdtree = scipy.spatial.cKDTree(global_plan) + + dist, index = self.kdtree.query([robot_pose.x, robot_pose.y]) + return dist, index + + def _reward_abrupt_direction_change(self, action: np.array = None): + """Applies a penalty when an abrupt change of direction occured. + + Args: + action (np.array, optional): Array of shape (2,). First entry, linear velocity. \ + Second entry, angular velocity. Defaults to None. + """ + if self.last_action is not None: + curr_ang_vel = action[1] + last_ang_vel = self.last_action[1] + + vel_diff = abs(curr_ang_vel - last_ang_vel) + self.curr_reward -= (vel_diff ** 4) / 2500 + self.last_action = action diff --git a/arena_marl/marl_agent/utils/sb3agent_format_check.py b/arena_marl/marl_agent/utils/sb3agent_format_check.py new file mode 100644 index 000000000..e4d688774 --- /dev/null +++ b/arena_marl/marl_agent/utils/sb3agent_format_check.py @@ -0,0 +1,39 @@ +from typing import Type + +from stable_baselines3.common.torch_layers import BaseFeaturesExtractor +from torch.nn.modules.module import Module + +from arena_navigation.arena_local_planner.learning_based.arena_local_planner_drl.rl_agent.model.base_agent import BaseAgent, PolicyType + + +def check_format(cls: Type[BaseAgent]): + assert isinstance(cls.type, PolicyType), "Type has to be of type 'PolicyType'!" + + if cls.features_extractor_class: + assert issubclass( + cls.features_extractor_class, BaseFeaturesExtractor + ), "Feature extractors have to derive from 'BaseFeaturesExtractor'!" + + if cls.features_extractor_kwargs: + assert ( + type(cls.features_extractor_kwargs) is dict + ), "Features extractor kwargs have to be of type 'dict'!" + + if cls.net_arch: + assert ( + type(cls.net_arch) is list + ), "Network architecture kwargs have to be of type 'list'!" + for entry in cls.net_arch: + assert ( + type(entry) is dict or type(entry) is int + ), "Network architecture entries have to be of either type 'list' or 'dict'!" + if type(entry) is dict: + assert "pi" in entry or "vf" in entry, ( + "net_arch dictionaries have to contain either 'pi' or 'vf'" + "for the respective network head!" + ) + + if cls.activation_fn: + assert issubclass( + cls.activation_fn, Module + ), "Activation functions have to be taken from torch!" diff --git a/arena_marl/marl_agent/utils/supersuit_utils.py b/arena_marl/marl_agent/utils/supersuit_utils.py new file mode 100644 index 000000000..e2290ccbf --- /dev/null +++ b/arena_marl/marl_agent/utils/supersuit_utils.py @@ -0,0 +1,99 @@ +from functools import partial +from typing import Callable + +import numpy as np +import rospy + +# from stable_baselines3.common.vec_env import VecNormalize +from supersuit.vector import ConcatVecEnv, MarkovVectorEnv + + +class MarkovVectorEnv_patched(MarkovVectorEnv): + """Patched environment wrapper which creates the correct API for vector environments. Dones for dead agents are returned as True instead as False.""" + + def step(self, actions): + agent_set = set(self.par_env.agents) + act_dict = { + agent: actions[i] + for i, agent in enumerate(self.par_env.possible_agents) + if agent in agent_set + } + observations, rewards, dones, infos = self.par_env.step(act_dict) + + # adds last observation to info where user can get it + if all(dones.values()): + for agent, obs in observations.items(): + infos[agent]["terminal_observation"] = obs + + rews = np.array( + [rewards.get(agent, 0) for agent in self.par_env.possible_agents], + dtype=np.float32, + ) + # we changed the default value to true instead of false + dns = np.array( + [dones.get(agent, True) for agent in self.par_env.possible_agents], + dtype=np.uint8, + ) + infs = [infos.get(agent, {}) for agent in self.par_env.possible_agents] + + if all(dones.values()): + observations = self.reset() + else: + observations = self.concat_obs(observations) + assert ( + self.black_death or self.par_env.agents == self.par_env.possible_agents + ), "MarkovVectorEnv does not support environments with varying numbers of active agents unless black_death is set to True" + return observations, rews, dns, infs + + +def vec_env_create( + env_fn: Callable, + agent_list_fn: Callable, + num_robots: int, + task_mode: str, + num_cpus: int, + num_vec_envs: int, + PATHS: dict, + agent_list_kwargs: dict, + max_num_moves_per_eps: int, +): + """Function which vectorizes a given environment function in multiple parallel environments. + + Args: + env_fn (Callable): Function that initializes an environment with wrappers + agent_list_fn (Callable): Object containing the program arguments + robot_model (str): Name of the robot model + num_robots (int): Number of robots in the environment + task_mode (str): Navigation task mode + num_cpus (int): Maximal number of CPUs to use (Currently only process is used anyhow) + num_vec_envs (int): Number of parallel environments to spawn + PATHS (dict): Dictionary which holds hyperparameters for the experiment + + Returns: + SB3VecEnvWrapper: Vectorized environments following the SB3 VecEnv API. Each each robot in an environment \ + poses as an environment in the vector. + """ + import supersuit.vector.sb3_vector_wrapper as sb3vw + + env_list_fns = [ + partial( + env_fn, + ns=f"sim_{i}", + num_agents=num_robots, + task_mode=task_mode, + agent_list_fn=agent_list_fn, + PATHS=PATHS, + agent_list_kwargs=agent_list_kwargs, + max_num_moves_per_eps=max_num_moves_per_eps, + ) + for i in range(1, num_vec_envs + 1) + ] + env = env_list_fns[0]() + action_space = env.action_space + observation_space = env.observation_space + metadata = env.metadata + + num_cpus = min(num_cpus, num_vec_envs) + rospy.init_node("train_env", disable_signals=False, anonymous=True) + vec_env = ConcatVecEnv(env_list_fns, observation_space, action_space) + return sb3vw.SB3VecEnvWrapper(vec_env) diff --git a/arena_marl/marl_agent/utils/supersuit_utils_experimental.py b/arena_marl/marl_agent/utils/supersuit_utils_experimental.py new file mode 100644 index 000000000..1ddc3302c --- /dev/null +++ b/arena_marl/marl_agent/utils/supersuit_utils_experimental.py @@ -0,0 +1,81 @@ +class SharedArray_patched(SharedArray): + def __setstate__(self, state): + (self.shared_arr, self.dtype, self.shape) = state + self._set_np_arr() + +class ProcConcatVec_patched(ProcConcatVec): + def __init__(self, vec_env_constrs, observation_space, action_space, tot_num_envs, metadata): + self.observation_space = observation_space + self.action_space = action_space + self.num_envs = num_envs = tot_num_envs + self.metadata = metadata + + self.shared_obs = SharedArray_patched((num_envs,) + self.observation_space.shape, dtype=self.observation_space.dtype) + act_space_wrap = SpaceWrapper(self.action_space) + self.shared_act = SharedArray_patched((num_envs,) + act_space_wrap.shape, dtype=act_space_wrap.dtype) + self.shared_rews = SharedArray_patched((num_envs,), dtype=np.float32) + self.shared_dones = SharedArray_patched((num_envs,), dtype=np.uint8) + + pipes = [] + procs = [] + for constr in vec_env_constrs: + inpt, outpt = mp.Pipe() + constr = gym.vector.async_vector_env.CloudpickleWrapper(constr) + proc = mp.Process( + target=async_loop, args=(constr, inpt, outpt, self.shared_obs, self.shared_act, self.shared_rews, self.shared_dones) + ) + proc.start() + outpt.close() + pipes.append(inpt) + procs.append(proc) + + self.pipes = pipes + self.procs = procs + + num_envs = 0 + env_nums = self._receive_info() + idx_starts = [] + for pipe, cnum_env in zip(self.pipes, env_nums): + cur_env_idx = num_envs + num_envs += cnum_env + pipe.send(cur_env_idx) + idx_starts.append(cur_env_idx) + + assert num_envs == tot_num_envs, f"num_envs={num_envs} und tot_num_envs={tot_num_envs}" + self.idx_starts = idx_starts + +class call_wrap_patched: + def __init__(self, fn, data, i): + self.fn = fn + self.data = data + self.i = i + + def __call__(self, *args): + rospy.init_node(f"train_env_{self.i}", disable_signals=False, anonymous=True) + return self.fn(self.data) + +def MakeCPUAsyncConstructor_patched(max_num_cpus, metadata): + if True: + rospy.init_node("train_env", disable_signals=False, anonymous=True) + return ConcatVecEnv + else: + + def constructor(env_fn_list, obs_space, act_space): + num_fns = len(env_fn_list) + envs_per_cpu = (num_fns + max_num_cpus - 1) // max_num_cpus + alloced_num_cpus = (num_fns + envs_per_cpu - 1) // envs_per_cpu + + env_cpu_div = [] + num_envs_alloced = 0 + while num_envs_alloced < num_fns: + start_idx = num_envs_alloced + end_idx = min(num_fns, start_idx + envs_per_cpu) + env_cpu_div.append(env_fn_list[start_idx:end_idx]) + num_envs_alloced = end_idx + + assert alloced_num_cpus == len(env_cpu_div) + + cat_env_fns = [call_wrap_patched(ConcatVecEnv, env_fns, i) for i, env_fns in enumerate(env_cpu_div)] + return ProcConcatVec_patched(cat_env_fns, obs_space, act_space, num_fns, metadata) + + return constructor \ No newline at end of file diff --git a/arena_marl/marl_agent/utils/utils.py b/arena_marl/marl_agent/utils/utils.py new file mode 100644 index 000000000..0741a5cea --- /dev/null +++ b/arena_marl/marl_agent/utils/utils.py @@ -0,0 +1,101 @@ +import sys +import os, sys, rospy, time + +from typing import Callable, List + +import rospy +import rospkg + +from rl_agent.training_agent_wrapper import TrainingDRLAgent +from rl_agent.base_agent_wrapper import BaseDRLAgent + + +def get_hyperparameter_file(filename: str) -> str: + """Function which returns the path to the hyperparameter file. + + Args: + filename (str): Name of the hyperparameter file. + + Returns: + str: Path to the hyperparameter file. + """ + return os.path.join( + rospkg.RosPack().get_path("arena_local_planner_drl"), + "configs", + "hyperparameters", + filename, + ) + + +def instantiate_train_drl_agents( + num_robots: int = 1, + existing_robots: int = 0, + robot_model: str = "burger", + ns: str = None, + robot_name_prefix: str = "robot", + hyperparameter_path: str = os.path.join( + rospkg.RosPack().get_path("arena_local_planner_drl"), + "configs", + "hyperparameters", + "default.json", + ), +) -> List[TrainingDRLAgent]: + """Function which generates a list agents which handle the ROS connection. + + Args: + num_robots (int, optional): Number of robots in the environment. Defaults to 1. + robot_model (str, optional): Model of the robot. Defaults to "burger". + ns (str, optional): Name of the namespace (used for ROS topics). Defaults to None. + robot_name_prefix (str, optional): Name with which to prefix robots in the ROS environment. Defaults to "robot". + hyperparameter_path (str, optional): Path where to load hyperparameters from. Defaults to DEFAULT_HYPERPARAMETER. + action_space_path (str, optional): Path where to load action spaces from. Defaults to DEFAULT_ACTION_SPACE. + + Returns: + List[TrainingDRLAgent]: List containing _num\_robots_ agent classes. + """ + return [ + TrainingDRLAgent( + ns=ns, + robot_model=robot_model, + robot_ns=robot_name_prefix + str(i + 1), + hyperparameter_path=hyperparameter_path, + ) + for i in range(existing_robots, existing_robots + num_robots) + ] + + +def instantiate_deploy_drl_agents( + num_robots: int = 1, + existing_robots: int = 0, + robot_model: str = "burger", + ns: str = None, + robot_name_prefix: str = "robot", + hyperparameter_path: str = os.path.join( + rospkg.RosPack().get_path("arena_local_planner_drl"), + "configs", + "hyperparameters", + "default.json", + ), +) -> List[BaseDRLAgent]: + """Function which generates a list agents which handle the ROS connection. + + Args: + num_robots (int, optional): Number of robots in the environment. Defaults to 1. + robot_model (str, optional): Model of the robot. Defaults to "burger". + ns (str, optional): Name of the namespace (used for ROS topics). Defaults to None. + robot_name_prefix (str, optional): Name with which to prefix robots in the ROS environment. Defaults to "robot". + hyperparameter_path (str, optional): Path where to load hyperparameters from. Defaults to DEFAULT_HYPERPARAMETER. + action_space_path (str, optional): Path where to load action spaces from. Defaults to DEFAULT_ACTION_SPACE. + + Returns: + List[TrainingDRLAgent]: List containing _num\_robots_ agent classes. + """ + return [ + BaseDRLAgent( + ns=ns, + robot_model=robot_model, + robot_ns=robot_name_prefix + str(i + 1), + hyperparameter_path=hyperparameter_path, + ) + for i in range(existing_robots, existing_robots + num_robots) + ] diff --git a/arena_marl/marl_tools/__init__.py b/arena_marl/marl_tools/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/arena_marl/marl_tools/argsparser.py b/arena_marl/marl_tools/argsparser.py new file mode 100644 index 000000000..6d7b3bbf2 --- /dev/null +++ b/arena_marl/marl_tools/argsparser.py @@ -0,0 +1,211 @@ +import argparse +import os +import numpy as np + +from rl_agent.model.agent_factory import AgentFactory +from marl_tools.custom_mlp_utils import get_net_arch + + +def training_args(parser): + """program arguments training script""" + parser.add_argument( + "--n_envs", type=int, default=1, help="number of parallel environments" + ) + parser.add_argument( + "--no-gpu", action="store_true", help="disables gpu for training" + ) + parser.add_argument( + "--debug", + action="store_true", + help="disables multiprocessing in order to debug", + ) + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument( + "--agent", + type=str, + choices=AgentFactory.registry.keys(), + help="predefined agent to train", + ) + group.add_argument( + "--custom-mlp", + action="store_true", + help="enables training with custom multilayer perceptron", + ) + group.add_argument( + "--load", + type=str, + metavar="[agent name]", + help="agent to be loaded for training", + ) + parser.add_argument( + "--config", + type=str, + metavar="[config name]", + default="default", + help="name of the json file containing" "the hyperparameters", + ) + parser.add_argument( + "--n", type=int, help="timesteps in total to be generated for training" + ) + parser.add_argument( + "-log", + "--eval_log", + action="store_true", + help="enables storage of evaluation data", + ) + parser.add_argument("--tb", action="store_true", help="enables tensorboard logging") + + +def marl_training_args(parser): + parser.add_argument("--robots", type=int, default=1, help="number of robots") + + +def run_agent_args(parser): + parser.add_argument( + "--no-gpu", action="store_true", help="disables gpu for training" + ) + parser.add_argument( + "--load", + type=str, + metavar="[agent name]", + help="agent to be loaded for training", + ) + parser.add_argument( + "--log", + action="store_true", + help="store log file with episode information", + ) + parser.add_argument( + "-s", + "--scenario", + type=str, + metavar="[scenario name]", + default="scenario1", + help="name of scenario file for deployment", + ) + parser.add_argument( + "--num_eps", + type=int, + metavar="[num episodes]", + default=100, + help="number of episodes the agent/s get/s challenged", + ) + parser.add_argument( + "--max_steps", + type=int, + metavar="[max steps per episode]", + default=np.inf, + help="max amount of actions per episode before the simulation is resetted", + ) + parser.add_argument("-v", "--verbose", choices=["0", "1"], default="1") + + +def custom_mlp_args(parser): + """arguments for the custom mlp mode""" + custom_mlp_args = parser.add_argument_group( + "custom mlp args", "architecture arguments for the custom mlp" + ) + + custom_mlp_args.add_argument( + "--body", + type=str, + default="", + metavar="{num}-{num}-...", + help="architecture of the shared latent network, " + "each number representing the number of neurons per layer", + ) + custom_mlp_args.add_argument( + "--pi", + type=str, + default="", + metavar="{num}-{num}-...", + help="architecture of the latent policy network, " + "each number representing the number of neurons per layer", + ) + custom_mlp_args.add_argument( + "--vf", + type=str, + default="", + metavar="{num}-{num}-...", + help="architecture of the latent value network, " + "each number representing the number of neurons per layer", + ) + custom_mlp_args.add_argument( + "--act_fn", + type=str, + default="relu", + choices=["relu", "sigmoid", "tanh"], + help="activation function to be applied after each hidden layer", + ) + + +def process_training_args(parsed_args): + """argument check function""" + if parsed_args.no_gpu: + os.environ["CUDA_VISIBLE_DEVICES"] = "-1" + if parsed_args.custom_mlp: + setattr(parsed_args, "net_arch", get_net_arch(parsed_args)) + else: + if parsed_args.body != "" or parsed_args.pi != "" or parsed_args.vf != "": + print("[custom mlp] arguments will be ignored..") + delattr(parsed_args, "body") + delattr(parsed_args, "pi") + delattr(parsed_args, "vf") + delattr(parsed_args, "act_fn") + + +def process_run_agent_args(parsed_args): + if parsed_args.no_gpu: + os.environ["CUDA_VISIBLE_DEVICES"] = "-1" + + +def parse_training_args(args=None, ignore_unknown=False): + """parser for training script""" + arg_populate_funcs = [training_args, custom_mlp_args] + arg_check_funcs = [process_training_args] + + return parse_various_args(args, arg_populate_funcs, arg_check_funcs, ignore_unknown) + + +def parse_marl_training_args(args=None, ignore_unknown=False): + """parser for training script""" + arg_populate_funcs = [training_args, custom_mlp_args, marl_training_args] + arg_check_funcs = [process_training_args] + + return parse_various_args(args, arg_populate_funcs, arg_check_funcs, ignore_unknown) + + +def parse_run_agent_args(args=None, ignore_unknown=False): + """parser for training script""" + arg_populate_funcs = [run_agent_args] + arg_check_funcs = [process_run_agent_args] + + return parse_various_args(args, arg_populate_funcs, arg_check_funcs, ignore_unknown) + + +def parse_various_args(args, arg_populate_funcs, arg_check_funcs, ignore_unknown): + """generic arg parsing function""" + parser = argparse.ArgumentParser() + + for func in arg_populate_funcs: + func(parser) + + if ignore_unknown: + parsed_args, unknown_args = parser.parse_known_args(args=args) + else: + parsed_args = parser.parse_args(args=args) + unknown_args = [] + + for func in arg_check_funcs: + func(parsed_args) + + print_args(parsed_args) + return parsed_args, unknown_args + + +def print_args(args): + print("\n-------------------------------") + print(" ARGUMENTS ") + for k in args.__dict__: + print("- {} : {}".format(k, args.__dict__[k])) + print("--------------------------------\n") diff --git a/arena_marl/marl_tools/custom_mlp_utils.py b/arena_marl/marl_tools/custom_mlp_utils.py new file mode 100644 index 000000000..4ae5d200e --- /dev/null +++ b/arena_marl/marl_tools/custom_mlp_utils.py @@ -0,0 +1,53 @@ +import torch as th +import argparse + + +def get_net_arch(args: argparse.Namespace): + """function to convert input args into valid syntax for the PPO""" + body, policy, value = None, None, None + + if args.body != "": + body = parse_string(args.body) + if args.pi != "": + policy = parse_string(args.pi) + if args.vf != "": + value = parse_string(args.vf) + + if body is None: + body = [] + vf_pi = {} + if value is not None: + vf_pi["vf"] = value + if policy is not None: + vf_pi["pi"] = policy + + return body + [vf_pi] + + +def parse_string(string: str): + """function to convert a string into a int list + + Example: + + Input: parse_string("64-64") + Output: [64, 64] + + """ + string_arr = string.split("-") + int_list = [] + for string in string_arr: + try: + int_list.append(int(string)) + except: + raise Exception("Invalid argument format on: " + string) + return int_list + + +def get_act_fn(act_fn_string: str): + """function to convert str into pytorch activation function class""" + if act_fn_string == "relu": + return th.nn.ReLU + elif act_fn_string == "sigmoid": + return th.nn.Sigmoid + elif act_fn_string == "tanh": + return th.nn.Tanh diff --git a/arena_marl/marl_tools/staged_train_callback.py b/arena_marl/marl_tools/staged_train_callback.py new file mode 100644 index 000000000..b9c5c5147 --- /dev/null +++ b/arena_marl/marl_tools/staged_train_callback.py @@ -0,0 +1,140 @@ +import warnings +import rospy +import numpy as np +import time + +from typing import List +from std_msgs.msg import Bool +from stable_baselines3.common.callbacks import BaseCallback, EvalCallback, MarlEvalCallback +from task_generator.task_generator.tasks import StagedRandomTask + + +class InitiateNewTrainStage(BaseCallback): + """ + Introduces new training stage when threshhold reached. + It must be used with "EvalCallback". + + :param treshhold_type (str): checks threshhold for either percentage of successful episodes (succ) or mean reward (rew) + :param rew_threshold (int): mean reward threshold to trigger new stage + :param succ_rate_threshold (float): threshold percentage of succesful episodes to trigger new stage + :param task_mode (str): training task mode, if not 'staged' callback won't be called + :param verbose: + """ + + def __init__( + self, + n_envs: int = 1, + treshhold_type: str = "succ", + upper_threshold: float = 0, + lower_threshold: float = 0, + task_mode: str = "staged", + verbose=0, + ): + + super(InitiateNewTrainStage, self).__init__(verbose=verbose) + self.n_envs = n_envs + self.threshhold_type = treshhold_type + + assert self.threshhold_type in { + "rew", + "succ", + }, "given theshhold type neither 'rew' or 'succ'" + + # default values + if self.threshhold_type == "rew" and upper_threshold == 0: + self.upper_threshold = 13 + self.lower_threshold = 7 + elif self.threshhold_type == "succ" and upper_threshold == 0: + self.upper_threshold = 0.85 + self.lower_threshold = 0.6 + else: + self.upper_threshold = upper_threshold + self.lower_threshold = lower_threshold + + assert ( + self.upper_threshold > self.lower_threshold + ), "upper threshold has to be bigger than lower threshold" + assert ( + self.upper_threshold >= 0 and self.lower_threshold >= 0 + ), "upper/lower threshold have to be positive numbers" + if self.threshhold_type == "succ": + assert ( + self.upper_threshold <= 1 and self.lower_threshold >= 0 + ), "succ thresholds have to be between [1.0, 0.0]" + + self.verbose = verbose + self.activated = bool(task_mode == "staged") + + if self.activated: + rospy.set_param("/last_stage_reached", False) + self._instantiate_publishers() + + self._trigger = Bool() + self._trigger.data = True + + def _instantiate_publishers(self): + self._publishers_next = [] + self._publishers_previous = [] + + self._publishers_next.append( + rospy.Publisher(f"/eval_sim/next_stage", Bool, queue_size=1) + ) + self._publishers_previous.append( + rospy.Publisher(f"/eval_sim/previous_stage", Bool, queue_size=1) + ) + + for env_num in range(self.n_envs): + self._publishers_next.append( + rospy.Publisher(f"/sim_{env_num+1}/next_stage", Bool, queue_size=1) + ) + self._publishers_previous.append( + rospy.Publisher(f"/sim_{env_num+1}/previous_stage", Bool, queue_size=1) + ) + + def _on_step(self, EvalObject: EvalCallback) -> bool: + assert isinstance( + EvalObject, EvalCallback + ) or isinstance( + EvalObject, MarlEvalCallback + ), f"InitiateNewTrainStage must be called within EvalCallback" + + if self.activated: + if EvalObject.n_eval_episodes < 20: + warnings.warn( + "Only %d evaluation episodes considered for threshold monitoring," + "results might not represent agent performance well" + % EvalObject.n_eval_episodes + ) + + if ( + self.threshhold_type == "rew" + and EvalObject.best_mean_reward <= self.lower_threshold + ) or ( + self.threshhold_type == "succ" + and EvalObject.last_success_rate <= self.lower_threshold + ): + for i, pub in enumerate(self._publishers_previous): + pub.publish(self._trigger) + if i == 0: + self.log_curr_stage(EvalObject.logger) + + if ( + self.threshhold_type == "rew" + and EvalObject.best_mean_reward >= self.upper_threshold + ) or ( + self.threshhold_type == "succ" + and EvalObject.last_success_rate >= self.upper_threshold + ): + if not rospy.get_param("/last_stage_reached"): + EvalObject.best_mean_reward = -np.inf + EvalObject.last_success_rate = -np.inf + + for i, pub in enumerate(self._publishers_next): + pub.publish(self._trigger) + if i == 0: + self.log_curr_stage(EvalObject.logger) + + def log_curr_stage(self, logger): + time.sleep(1) + curr_stage = rospy.get_param("/curr_stage", -1) + logger.record("train_stage/stage_idx", curr_stage) diff --git a/arena_marl/marl_tools/train_agent_utils.py b/arena_marl/marl_tools/train_agent_utils.py new file mode 100644 index 000000000..a0462f77c --- /dev/null +++ b/arena_marl/marl_tools/train_agent_utils.py @@ -0,0 +1,565 @@ +from typing import Union, Type + +import argparse +from datetime import datetime as dt +import gym +import json +import os + +import yaml +import rosnode +import rospkg +import time +import warnings + +from stable_baselines3 import PPO +from stable_baselines3.common.monitor import Monitor +from stable_baselines3.common.policies import ActorCriticPolicy +from stable_baselines3.common.utils import set_random_seed + + +from rl_agent.envs.flatland_gym_env import ( + FlatlandEnv, +) +from rl_agent.model.agent_factory import AgentFactory +from rl_agent.model.base_agent import BaseAgent +from marl_tools.custom_mlp_utils import get_act_fn +import rospy + +""" +Dict containing agent specific hyperparameter keys (for documentation and typing validation purposes) + +:key agent_name: Precise agent name (as generated by get_agent_name()) +:key robot: Robot name to load robot specific .yaml file containing settings +:key batch_size: Batch size (n_envs * n_steps) +:key gamma: Discount factor +:key n_steps: The number of steps to run for each environment per update +:key ent_coef: Entropy coefficient for the loss calculation +:key learning_rate: The learning rate, it can be a function + of the current progress remaining (from 1 to 0) + (i.e. batch size is n_steps * n_env where n_env is number of environment copies running in parallel) +:key vf_coef: Value function coefficient for the loss calculation +:key max_grad_norm: The maximum value for the gradient clipping +:key gae_lambda: Factor for trade-off of bias vs variance for Generalized Advantage Estimator +:key m_batch_size: Minibatch size +:key n_epochs: Number of epoch when optimizing the surrogate loss +:key clip_range: Clipping parameter, it can be a function of the current progress + remaining (from 1 to 0). +:key train_max_steps_per_episode: Max timesteps per training episode +:key eval_max_steps_per_episode: Max timesteps per evaluation episode +:key goal_radius: Radius of the goal +:key reward_fnc: Number of the reward function (defined in ../rl_agent/utils/reward.py) +:key discrete_action_space: If robot uses discrete action space +:key normalize: If observations are normalized before fed to the network +:key task_mode: Mode tasks will be generated in (custom, random, staged). +:key curr_stage: In case of staged training which stage to start with. +:param n_timesteps: The number of timesteps trained on in total. +""" +hyperparams = { + key: None + for key in [ + "agent_name", + "robot", + "actions_in_observationspace", + "batch_size", + "gamma", + "n_steps", + "ent_coef", + "learning_rate", + "vf_coef", + "max_grad_norm", + "gae_lambda", + "m_batch_size", + "n_epochs", + "clip_range", + "reward_fnc", + "discrete_action_space", + "normalize", + "task_mode", + "curr_stage", + "train_max_steps_per_episode", + "eval_max_steps_per_episode", + "goal_radius", + ] +} + + +def load_config(config_name: str) -> dict: + """ + Load config parameters from config file + """ + config_location = os.path.join( + rospkg.RosPack().get_path("arena_local_planner_drl"), "configs", config_name + ) + with open(config_location, "r", encoding="utf-8") as target: + config = yaml.load(target, Loader=yaml.FullLoader) + + return config + + +def initialize_hyperparameters(PATHS: dict, config: dict, n_envs: int) -> dict: + """ + Write hyperparameters to json file in case agent is new otherwise load existing hyperparameters + + :param PATHS: dictionary containing model specific paths + :param load_target: unique agent name (when calling --load) + :param config_name: name of the hyperparameter file in /configs/hyperparameters + :param n_envs: number of envs + """ + # when building new agent + if config["resume"] is None: + hyperparams = load_hyperparameters_json(PATHS=PATHS, from_scratch=True) + hyperparams["agent_name"] = PATHS["model"].split("/")[-1] + else: + hyperparams = load_hyperparameters_json(PATHS=PATHS) + + # dynamically adapt n_steps according to batch size and n envs + # then update .json + check_batch_size(n_envs, hyperparams["batch_size"], hyperparams["m_batch_size"]) + hyperparams["n_steps"] = int(hyperparams["batch_size"] / n_envs) + if not rospy.get_param("debug_mode"): + write_hyperparameters_json(hyperparams, PATHS) + print_hyperparameters(hyperparams) + return hyperparams + + +def write_hyperparameters_json(hyperparams: dict, PATHS: dict) -> None: + """ + Write hyperparameters.json to agent directory + + :param hyperparams: dict containing model specific hyperparameters + :param PATHS: dictionary containing model specific paths + """ + doc_location = os.path.join(PATHS.get("model"), "hyperparameters.json") + + with open(doc_location, "w", encoding="utf-8") as target: + json.dump(hyperparams, target, ensure_ascii=False, indent=4) + + +def load_hyperparameters_json(PATHS: dict, from_scratch: bool = False) -> dict: + """ + Load hyperparameters from model directory when loading - when training from scratch + load from ../configs/hyperparameters + + :param PATHS: dictionary containing model specific paths + :param from_scatch: if training from scratch + :param config_name: file name of json file when training from scratch + """ + if from_scratch: + doc_location = os.path.join(PATHS.get("hyperparams")) + else: + doc_location = os.path.join(PATHS.get("model"), "hyperparameters.json") + + if os.path.isfile(doc_location): + with open(doc_location, "r") as file: + hyperparams = json.load(file) + check_hyperparam_format(loaded_hyperparams=hyperparams, PATHS=PATHS) + return hyperparams + else: + if from_scratch: + raise FileNotFoundError("Found no '%s'" % PATHS.get("hyperparams")) + else: + raise FileNotFoundError( + "Found no 'hyperparameters.json' in %s" % PATHS.get("model") + ) + + +def update_total_timesteps_json(timesteps: int, PATHS: dict) -> None: + """ + Update total number of timesteps in json file + + :param hyperparams_obj(object, agent_hyperparams): object containing containing model specific hyperparameters + :param PATHS: dictionary containing model specific paths + """ + doc_location = os.path.join(PATHS.get("model"), "hyperparameters.json") + hyperparams = load_hyperparameters_json(PATHS=PATHS) + + try: + curr_timesteps = int(hyperparams["n_timesteps"]) + timesteps + hyperparams["n_timesteps"] = curr_timesteps + except Exception: + raise Warning( + "Parameter 'total_timesteps' not found or not of type Integer in 'hyperparameter.json'!" + ) + else: + with open(doc_location, "w", encoding="utf-8") as target: + json.dump(hyperparams, target, ensure_ascii=False, indent=4) + + +def print_hyperparameters(hyperparams: dict) -> None: + print("\n--------------------------------") + print(" HYPERPARAMETERS \n") + for param, param_val in hyperparams.items(): + print("{:30s}{:<10s}".format((param + ":"), str(param_val))) + print("--------------------------------\n\n") + + +def check_hyperparam_format(loaded_hyperparams: dict, PATHS: dict) -> None: + if set(hyperparams.keys()) != set(loaded_hyperparams.keys()): + missing_keys = set(hyperparams.keys()).difference( + set(loaded_hyperparams.keys()) + ) + redundant_keys = set(loaded_hyperparams.keys()).difference( + set(hyperparams.keys()) + ) + raise AssertionError( + f"unmatching keys, following keys missing: {missing_keys} \n" + f"following keys unused: {redundant_keys}" + ) + if not isinstance(loaded_hyperparams["discrete_action_space"], bool): + raise TypeError("Parameter 'discrete_action_space' not of type bool") + if loaded_hyperparams["task_mode"] not in ["custom", "random", "staged"]: + raise TypeError("Parameter 'task_mode' has unknown value") + + +def update_hyperparam_model( + model: PPO, PATHS: dict, params: dict, n_envs: int = 1 +) -> None: + """ + Updates parameter of loaded PPO agent when it was manually changed in the configs yaml. + + :param model(object, PPO): loaded PPO agent + :param PATHS: program relevant paths + :param params: dictionary containing loaded hyperparams + :param n_envs: number of parallel environments + """ + if model.batch_size != params["batch_size"]: + model.batch_size = params["batch_size"] + if model.gamma != params["gamma"]: + model.gamma = params["gamma"] + if model.n_steps != params["n_steps"]: + model.n_steps = params["n_steps"] + if model.ent_coef != params["ent_coef"]: + model.ent_coef = params["ent_coef"] + if model.learning_rate != params["learning_rate"]: + model.learning_rate = params["learning_rate"] + if model.vf_coef != params["vf_coef"]: + model.vf_coef = params["vf_coef"] + if model.max_grad_norm != params["max_grad_norm"]: + model.max_grad_norm = params["max_grad_norm"] + if model.gae_lambda != params["gae_lambda"]: + model.gae_lambda = params["gae_lambda"] + if model.n_epochs != params["n_epochs"]: + model.n_epochs = params["n_epochs"] + """ + if model.clip_range != params['clip_range']: + model.clip_range = params['clip_range'] + """ + if model.n_envs != n_envs: + model.update_n_envs() + if model.rollout_buffer.buffer_size != params["n_steps"]: + model.rollout_buffer.buffer_size = params["n_steps"] + if model.tensorboard_log != PATHS["tb"]: + model.tensorboard_log = PATHS["tb"] + + +def check_batch_size(n_envs: int, batch_size: int, mn_batch_size: int) -> None: + assert ( + batch_size > mn_batch_size + ), f"Mini batch size {mn_batch_size} is bigger than batch size {batch_size}" + + assert ( + batch_size % mn_batch_size == 0 + ), f"Batch size {batch_size} isn't divisible by mini batch size {mn_batch_size}" + + assert ( + batch_size % n_envs == 0 + ), f"Batch size {batch_size} isn't divisible by n_envs {n_envs}" + + assert ( + batch_size % mn_batch_size == 0 + ), f"Batch size {batch_size} isn't divisible by mini batch size {mn_batch_size}" + + +def get_agent_name(args: argparse.Namespace) -> str: + """Function to get agent name to save to/load from file system + + Example names: + "MLP_B_64-64_P_32-32_V_32-32_relu_2021_01_07__10_32" + "DRL_LOCAL_PLANNER_2021_01_08__7_14" + + :param args (argparse.Namespace): Object containing the program arguments + """ + START_TIME = dt.now().strftime("%Y_%m_%d__%H_%M") + + if args.custom_mlp: + return ( + "MLP_B_" + + args.body + + "_P_" + + args.pi + + "_V_" + + args.vf + + "_" + + args.act_fn + + "_" + + START_TIME + ) + if args.load is None: + return args.agent + "_" + START_TIME + return args.load + + +def get_MARL_agent_name_and_start_time() -> str: + """Function to get MARL agent parent dir, where seperate agents for different robots are saved""" + START_TIME = dt.now().strftime("%Y_%m_%d__%H_%M") + + return "MARL_AGENTS_" + START_TIME, START_TIME + + +def get_paths( + marl_dir: str, + robot: str, + agent_name: str, + config_params: dict, + curriculum: str, + eval_log: bool, + tb: bool, +) -> dict: + """ + Function to generate agent specific paths + + :param agent_name: Precise agent name (as generated by get_agent_name()) + :param args (argparse.Namespace): Object containing the program arguments + """ + dir = rospkg.RosPack().get_path("arena_local_planner_drl") + PATHS = { + "model": os.path.join(dir, "agents", marl_dir, agent_name) + if config_params["resume"] is None + else config_params["resume"], + "tb": os.path.join(dir, "training_logs", "tensorboard", marl_dir, agent_name), + "eval": os.path.join( + dir, "training_logs", "train_eval_log", marl_dir, agent_name + ), + "robot_setting": os.path.join( + rospkg.RosPack().get_path("simulator_setup"), + "robot", + robot + ".model.yaml", + ), + "hyperparams": os.path.join( + dir, "configs", "hyperparameters", config_params["hyperparameter_file"] + ), + "robot_as": os.path.join( + dir, "configs", "action_spaces", "default_settings_" + robot + ".yaml" + ), + "curriculum": os.path.join(dir, "configs", "training_curriculums", curriculum), + } + rospy.get_param("/debug_mode") + + # check for mode + if not rospy.get_param("/debug_mode"): + if config_params["resume"] is None: + os.makedirs(PATHS["model"]) + elif not os.path.isfile( + os.path.join(PATHS["model"], agent_name + ".zip") + ) and not os.path.isfile(os.path.join(PATHS["model"], "best_model.zip")): + raise FileNotFoundError( + "Couldn't find model named %s.zip' or 'best_model.zip' in '%s'" + % (agent_name, PATHS["model"]) + ) + + # evaluation log enabled + if eval_log: + if not os.path.exists(PATHS["eval"]): + os.makedirs(PATHS["eval"]) + else: + PATHS["eval"] = None + # tensorboard log enabled + if tb: + if not os.path.exists(PATHS["tb"]): + os.makedirs(PATHS["tb"]) + else: + PATHS["tb"] = None + else: + PATHS["eval"] = None + PATHS["tb"] = None + + return PATHS + + +def make_envs( + args: argparse.Namespace, + with_ns: bool, + rank: int, + params: dict, + seed: int = 0, + PATHS: dict = None, + train: bool = True, +): + """ + Utility function for multiprocessed env + + :param with_ns: (bool) if the system was initialized with namespaces + :param rank: (int) index of the subprocess + :param params: (dict) hyperparameters of agent to be trained + :param seed: (int) the inital seed for RNG + :param PATHS: (dict) script relevant paths + :param train: (bool) to differentiate between train and eval env + :param args: (Namespace) program arguments + :return: (Callable) + """ + + def _init() -> Union[gym.Env, gym.Wrapper]: + train_ns = f"sim_{rank+1}" if with_ns else "" + eval_ns = f"eval_sim" if with_ns else "" + + if train: + # train env + env = FlatlandEnv( + train_ns, + params["reward_fnc"], + params["discrete_action_space"], + goal_radius=params["goal_radius"], + max_steps_per_episode=params["train_max_steps_per_episode"], + debug=args.debug, + task_mode=params["task_mode"], + curr_stage=params["curr_stage"], + PATHS=PATHS, + ) + else: + # eval env + env = Monitor( + FlatlandEnv( + eval_ns, + params["reward_fnc"], + params["discrete_action_space"], + goal_radius=params["goal_radius"], + max_steps_per_episode=params["eval_max_steps_per_episode"], + train_mode=False, + debug=args.debug, + task_mode=params["task_mode"], + curr_stage=params["curr_stage"], + PATHS=PATHS, + ), + PATHS.get("eval"), + info_keywords=("done_reason", "is_success"), + ) + env.seed(seed + rank) + return env + + set_random_seed(seed) + return _init + + +def wait_for_nodes( + with_ns: bool, n_envs: int, timeout: int = 30, nodes_per_ns: int = 3 +) -> None: + """ + Checks for timeout seconds if all nodes to corresponding namespace are online. + + :param with_ns: (bool) if the system was initialized with namespaces + :param n_envs: (int) number of virtual environments + :param timeout: (int) seconds to wait for each ns + :param nodes_per_ns: (int) usual number of nodes per ns + """ + if with_ns: + assert ( + with_ns and n_envs >= 1 + ), f"Illegal number of environments parsed: {n_envs}" + else: + assert ( + not with_ns and n_envs == 1 + ), f"Simulation setup isn't compatible with the given number of envs" + + for i in range(n_envs): + for k in range(timeout): + ns = "sim_" + str(i + 1) if with_ns else "" + namespaces = rosnode.get_node_names(namespace=ns) + + if len(namespaces) >= nodes_per_ns: + break + + warnings.warn( + f"Check if all simulation parts of namespace '{ns}' are running properly" + ) + warnings.warn(f"Trying to connect again..") + assert ( + k < timeout - 1 + ), f"Timeout while trying to connect to nodes of '{ns}'" + + time.sleep(1) + + +from stable_baselines3.common.vec_env import VecNormalize +from stable_baselines3.common.vec_env.base_vec_env import VecEnv + + +def load_vec_normalize(params: dict, PATHS: dict, env: VecEnv, eval_env: VecEnv): + if params["normalize"]: + load_path = os.path.join(PATHS["model"], "vec_normalize.pkl") + if os.path.isfile(load_path): + env = VecNormalize.load(load_path=load_path, venv=env) + eval_env = VecNormalize.load(load_path=load_path, venv=eval_env) + print("Succesfully loaded VecNormalize object from pickle file..") + else: + env = VecNormalize( + env, + training=True, + norm_obs=True, + norm_reward=False, + clip_reward=15, + ) + eval_env = VecNormalize( + eval_env, + training=True, + norm_obs=True, + norm_reward=False, + clip_reward=15, + ) + return env, eval_env + + +def choose_agent_model(AGENT_NAME, PATHS, config, env, params, n_envs): + if config["resume"] is None: + agent: Union[ + Type[BaseAgent], Type[ActorCriticPolicy] + ] = AgentFactory.instantiate(config["architecture_name"]) + if isinstance(agent, BaseAgent): + model = PPO( + agent.type.value, + env, + policy_kwargs=agent.get_kwargs(), + gamma=params["gamma"], + n_steps=params["n_steps"], + ent_coef=params["ent_coef"], + learning_rate=params["learning_rate"], + vf_coef=params["vf_coef"], + max_grad_norm=params["max_grad_norm"], + gae_lambda=params["gae_lambda"], + batch_size=params["m_batch_size"], + n_epochs=params["n_epochs"], + clip_range=params["clip_range"], + tensorboard_log=PATHS.get("tb"), + verbose=1, + ) + elif issubclass(agent, ActorCriticPolicy): + model = PPO( + agent, + env, + gamma=params["gamma"], + n_steps=params["n_steps"], + ent_coef=params["ent_coef"], + learning_rate=params["learning_rate"], + vf_coef=params["vf_coef"], + max_grad_norm=params["max_grad_norm"], + gae_lambda=params["gae_lambda"], + batch_size=params["m_batch_size"], + n_epochs=params["n_epochs"], + clip_range=params["clip_range"], + tensorboard_log=PATHS.get("tb"), + verbose=1, + ) + else: + architecture_name = config["architecture_name"] + raise TypeError( + f"Registered agent class {architecture_name} is neither of type" + "'BaseAgent' or 'ActorCriticPolicy'!" + ) + else: + # load flag + assert os.path.isfile( + os.path.join(config["resume"], "best_model.zip") + ), f"Couldn't find best model in {config['resume']}" + model = PPO.load(os.path.join(config["resume"], "best_model.zip"), env) + update_hyperparam_model(model, PATHS, params, n_envs) + return model diff --git a/arena_marl/package.xml b/arena_marl/package.xml new file mode 100755 index 000000000..8cf8131e7 --- /dev/null +++ b/arena_marl/package.xml @@ -0,0 +1,84 @@ + + + arena_marl + 0.0.0 + The arena_marl package + + + + + root + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + geometry_msgs + nav_msgs + roscpp + rospy + sensor_msgs + tf2 + tf2_geometry_msgs + tf2_ros + geometry_msgs + nav_msgs + roscpp + rospy + sensor_msgs + tf2 + tf2_geometry_msgs + tf2_ros + geometry_msgs + nav_msgs + roscpp + rospy + sensor_msgs + tf2 + tf2_geometry_msgs + tf2_ros + flatland_msgs + + + + + + + + diff --git a/arena_marl/scripts/__init__.py b/arena_marl/scripts/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/arena_marl/scripts/deployment/action_publisher.py b/arena_marl/scripts/deployment/action_publisher.py new file mode 100755 index 000000000..cb74fc3d8 --- /dev/null +++ b/arena_marl/scripts/deployment/action_publisher.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +import rospy +import time + +from geometry_msgs.msg import Twist +from rosgraph_msgs.msg import Clock +from std_msgs.msg import Bool + + +class ActionPublisher: + def __init__(self): + if rospy.get_param("train_mode"): + raise Exception("This node should be used solely in eval mode!") + + rospy.init_node("action_publisher", anonymous=True) + + self._step_size = rospy.get_param("step_size") + self._update_rate = rospy.get_param("update_rate") + # real time second in sim time + self._real_second_in_sim = self._step_size * self._update_rate + self._action_publish_rate = rospy.get_param("/robot_action_rate") + + # apply rate in sim time + rate = (1 / self._action_publish_rate) / self._real_second_in_sim + + ns_prefix = "" if "/single_env" in rospy.get_param_names() else "/eval_sim/" + self._pub_cmd_vel = rospy.Publisher(f"{ns_prefix}cmd_vel", Twist, queue_size=1) + self._pub_cycle_trigger = rospy.Publisher( + f"{ns_prefix}next_cycle", Bool, queue_size=1 + ) + self._sub = rospy.Subscriber( + f"{ns_prefix}cmd_vel_pub", + Twist, + self.callback_receive_cmd_vel, + queue_size=1, + ) + + # to measure sim time + # self._clock_sub = rospy.Subscriber( + # f"{ns_prefix}clock", Clock, self.callback_clock) + # last = 0 + + self._action = Twist() + self._signal = Bool() + self._clock = Clock().clock.to_sec() + + last_action = self._action + + while not rospy.is_shutdown(): + if self._sub.get_num_connections() < 1: + print(f"ActionPublisher: No publisher to {ns_prefix}cmd_vel_pub yet.. ") + time.sleep(1) + continue + + self._pub_cmd_vel.publish(self._action) + self._pub_cycle_trigger.publish(self._signal) + + print(f"Published same action: {last_action==self._action}") + last_action = self._action + + time.sleep(rate) + + # print(f"sim time between cmd_vel: {self._clock - last}") + # last = self._clock + + def callback_receive_cmd_vel(self, msg_cmd_vel: Twist): + self._action = msg_cmd_vel + + def callback_clock(self, msg_clock: Clock): + self._clock = msg_clock.clock.to_sec() + + +if __name__ == "__main__": + try: + ActionPublisher() + except rospy.ROSInterruptException: + pass diff --git a/arena_marl/scripts/deployment/drl_agent_node.py b/arena_marl/scripts/deployment/drl_agent_node.py new file mode 100755 index 000000000..f31c07efe --- /dev/null +++ b/arena_marl/scripts/deployment/drl_agent_node.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python +import os +import pickle +import rospy +import rospkg +import sys + +from stable_baselines3 import PPO + +from flatland_msgs.srv import StepWorld, StepWorldRequest +from rospy.exceptions import ROSException +from std_msgs.msg import Bool + +from rl_agent.base_agent_wrapper import BaseDRLAgent + + +""" TEMPORARY GLOBAL CONSTANTS """ +NS_PREFIX = "" +TRAINED_MODELS_DIR = os.path.join( + rospkg.RosPack().get_path("arena_local_planner_drl"), "agents" +) +DEFAULT_ACTION_SPACE = os.path.join( + rospkg.RosPack().get_path("arena_local_planner_drl"), + "configs", + "default_settings.yaml", +) + + +class DeploymentDRLAgent(BaseDRLAgent): + def __init__( + self, + agent_name: str, + ns: str = None, + robot_name: str = None, + action_space_path: str = DEFAULT_ACTION_SPACE, + *args, + **kwargs, + ) -> None: + """Initialization procedure for the DRL agent node. + + Args: + agent_name (str): + Agent name (directory has to be of the same name) + robot_name (str, optional): + Robot specific ROS namespace extension. Defaults to None. + ns (str, optional): + Simulation specific ROS namespace. Defaults to None. + action_space_path (str, optional): + Path to yaml file containing action space settings. + Defaults to DEFAULT_ACTION_SPACE. + """ + self.name = agent_name + self.setup_agent() + + hyperparameter_path = os.path.join( + TRAINED_MODELS_DIR, self.name, "hyperparameters.json" + ) + super().__init__( + ns, + robot_name, + hyperparameter_path, + action_space_path, + ) + + if not self._is_train_mode: + rospy.init_node(f"DRL_local_planner", anonymous=True) + + if self._is_train_mode: + # step world to fast forward simulation time + self._service_name_step = f"{self._ns}step_world" + self._sim_step_client = rospy.ServiceProxy( + self._service_name_step, StepWorld + ) + + def setup_agent(self) -> None: + """Loads the trained policy and when required the VecNormalize object.""" + model_file = os.path.join( + TRAINED_MODELS_DIR, self.name, "best_model.zip" + ) + vecnorm_file = os.path.join( + TRAINED_MODELS_DIR, self.name, "vec_normalize.pkl" + ) + + assert os.path.isfile( + model_file + ), f"Compressed model cannot be found at {model_file}!" + assert os.path.isfile( + vecnorm_file + ), f"VecNormalize file cannot be found at {vecnorm_file}!" + + with open(vecnorm_file, "rb") as file_handler: + vec_normalize = pickle.load(file_handler) + + custom_objects = { + "learning_rate": 0.0, + "lr_schedule": lambda _: 0.0, + "clip_range": lambda _: 0.0, + } + + self._agent = PPO.load(model_file, custom_objects=custom_objects).policy + self._obs_norm_func = vec_normalize.normalize_obs + + def run(self) -> None: + """Loop for running the agent until ROS is shutdown. + + Note: + Calls the 'step_world'-service for fast-forwarding the \ + simulation time in training mode. The simulation is forwarded \ + by action_frequency seconds. Otherwise, communicates with \ + the ActionPublisher node in order to comply with the specified \ + action publishing rate. + """ + while not rospy.is_shutdown(): + if self._is_train_mode: + self.call_service_takeSimStep(self._action_frequency) + else: + self._wait_for_next_action_cycle() + obs = self.get_observations()[0] + action = self.get_action(obs) + self.publish_action(action) + + def _wait_for_next_action_cycle(self) -> None: + """Stops the loop until a trigger message is sent by the ActionPublisher + + Note: + Only use this method in combination with the ActionPublisher node! + That node is only booted when training mode is off. + """ + try: + rospy.wait_for_message(f"{self._ns_robot}next_cycle", Bool) + except ROSException: + pass + + def call_service_takeSimStep(self, t: float = None) -> None: + """Fast-forwards the simulation time. + + Args: + t (float, optional): + Time in seconds. When t is None, time is forwarded by 'step_size' s. + Defaults to None. + """ + request = StepWorldRequest() if t is None else StepWorldRequest(t) + + try: + response = self._sim_step_client(request) + rospy.logdebug("step service=", response) + except rospy.ServiceException as e: + rospy.logdebug("step Service call failed: %s" % e) + + +def main(agent_name: str) -> None: + AGENT = DeploymentDRLAgent(agent_name=agent_name, ns=NS_PREFIX) + + try: + AGENT.run() + except rospy.ROSInterruptException: + pass + + +if __name__ == "__main__": + AGENT_NAME = sys.argv[1] + main(agent_name=AGENT_NAME) diff --git a/arena_marl/scripts/deployment/evaluation.py b/arena_marl/scripts/deployment/evaluation.py new file mode 100644 index 000000000..aabf27a90 --- /dev/null +++ b/arena_marl/scripts/deployment/evaluation.py @@ -0,0 +1,127 @@ +from typing import Any, Callable, Dict, List, Optional, Tuple, Union + +import numpy as np +from stable_baselines3.common import base_class +import supersuit.vector.sb3_vector_wrapper as sb3vw + + +def evaluate_policy( + model: "base_class.BaseAlgorithm", + # env: Union[sb3vw.SB3VecEnvWrapper, VecEnv], + num_robots: int, + env: sb3vw.SB3VecEnvWrapper, + n_eval_episodes: int = 10, + deterministic: bool = True, + render: bool = False, + callback: Optional[Callable[[Dict[str, Any], Dict[str, Any]], None]] = None, + reward_threshold: Optional[float] = None, + return_episode_rewards: bool = False, + warn: bool = True, +) -> Union[Tuple[float, float], Tuple[List[float], List[int]]]: + """ + Runs policy for ``n_eval_episodes`` episodes and returns average reward. + This is made to work only with one env. + + .. note:: + If environment has not been wrapped with ``Monitor`` wrapper, reward and + episode lengths are counted as it appears with ``env.step`` calls. If + the environment contains wrappers that modify rewards or episode lengths + (e.g. reward scaling, early episode reset), these will affect the evaluation + results as well. You can avoid this by wrapping environment with ``Monitor`` + wrapper before anything else. + + :param model: The RL agent you want to evaluate. + :param env: The gym environment. In the case of a ``VecEnv`` + this must contain only one environment. + :param n_eval_episodes: Number of episode to evaluate the agent + :param deterministic: Whether to use deterministic or stochastic actions + :param render: Whether to render the environment or not + :param callback: callback function to do additional checks, + called after each step. Gets locals() and globals() passed as parameters. + :param reward_threshold: Minimum expected reward per episode, + this will raise an error if the performance is not met + :param return_episode_rewards: If True, a list of rewards and episode lengths + per episode will be returned instead of the mean. + :param warn: If True (default), warns user about lack of a Monitor wrapper in the + evaluation environment. + :return: Mean reward per episode, std of reward per episode. + Returns ([float], [int]) when ``return_episode_rewards`` is True, first + list containing per-episode rewards and second containing per-episode lengths + (in number of steps). + """ + is_monitor_wrapped = False + # Avoid circular import + from stable_baselines3.common.env_util import is_wrapped + from stable_baselines3.common.monitor import Monitor + + not_reseted = True + # Avoid double reset, as VecEnv are reset automatically. + if not_reseted: + # Observations dictionary in {_agent name_: _respective observations_} + obs = env.reset() + not_reseted = False + + agents = [a for a, _ in obs.items()] + episode_rewards = {a: [None] for a in agents} + episode_lengths = [] + + default_dones = {a: False for a in agents} + default_states = {a: None for a in agents} + default_actions = {a: None for a in agents} + default_episode_reward = {a: None for a in agents} + while len(episode_rewards) < n_eval_episodes: + # Number of loops here might differ from true episodes + # played, if underlying wrappers modify episode lengths. + # Avoid double reset, as VecEnv are reset automatically. + if not_reseted: + # Observations dictionary in {_agent name_: _respective observations_} + obs = env.reset() + not_reseted = False + dones = default_dones.copy() + states = default_states.copy() + actions = default_actions.copy() + episode_reward = default_episode_reward.copy() + episode_length = 0 + while not dones: + # Get actions and states from each agent + for agent, state in states.items(): + actions[agent], states[agent] = model.predict( + obs[agent], state, deterministic=deterministic + ) + + obs, rewards, dones, infos = env.step(actions) + for agent, reward in zip(agents, rewards.values()): + episode_reward[agent] += reward + + if callback is not None: + callback(locals(), globals()) + + episode_length += 1 + if render: + env.render() + + # if is_monitor_wrapped: + # # Do not trust "done" with episode endings. + # # Remove vecenv stacking (if any) + # # if isinstance(env, VecEnv): + # # info = info[0] + # if "episode" in info.keys(): + # # Monitor wrapper includes "episode" key in info if environment + # # has been wrapped with it. Use those rewards instead. + # episode_rewards.append(info["episode"]["r"]) + # episode_lengths.append(info["episode"]["l"]) + # else: + for agent, reward in episode_reward.items(): + episode_rewards[agent].append(reward) + episode_lengths.append(episode_length) + + mean_rewards = {agent: np.mean(episode_rewards[agent]) for agent in agents} + std_rewards = {agent: np.std(episode_rewards[agent]) for agent in agents} + if reward_threshold is not None: + assert min(mean_rewards.values()) > reward_threshold, ( + "Atleast one mean reward below threshold: " + f"{min(mean_rewards.values()):.2f} < {reward_threshold:.2f}" + ) + if return_episode_rewards: + return episode_rewards, episode_lengths + return mean_rewards, std_rewards diff --git a/arena_marl/scripts/deployment/marl_deployment.py b/arena_marl/scripts/deployment/marl_deployment.py new file mode 100644 index 000000000..ef1712d2b --- /dev/null +++ b/arena_marl/scripts/deployment/marl_deployment.py @@ -0,0 +1,108 @@ +from multiprocessing import cpu_count +import os + + +from arena_marl.marl_agent.utils.utils import ( + instantiate_deploy_drl_agents, + get_hyperparameter_file, + instantiate_train_drl_agents, +) + +from arena_marl.scripts.deployment.evaluation import evaluate_policy + +from marl_tools.train_agent_utils import ( + load_config, +) +from marl_tools import train_agent_utils + +import rospy + +from stable_baselines3.common.vec_env import DummyVecEnv +from stable_baselines3 import PPO +from arena_marl.marl_agent.utils.supersuit_utils import ( + vec_env_create, +) +from arena_marl.marl_agent.envs.pettingzoo_env import env_fn + + +from tools.argsparser import parse_training_args + + +def main(args): + # load configuration + config = load_config(args.config) + + # set debug_mode + rospy.set_param("debug_mode", config["debug_mode"]) + + # load agents + assert len(config["robots"]) == 1, "Only one robot type is supported" + + robots, existing_robots = {}, 0 + + # loop over all robots in config + for robot_name, robot_train_params in config["robots"].items(): + # Get the Base Agent instance(s) + robots[robot_name] = { + "agents": instantiate_train_drl_agents( + num_robots=robot_train_params["num_robots"], + robot_model=robot_name, + hyperparameter_path=get_hyperparameter_file( + robot_train_params["hyperparameter_file"] + ), + ) + } + existing_robots += robot_train_params["num_robots"] + + # Define paths. If the agent is a SARL agent, MARL_DIR is None. + MARL_DIR = "" + paths = train_agent_utils.get_paths( + MARL_DIR, + robot_name, + robot_train_params["resume"].split("/")[-1], + robot_train_params, + config["training_curriculum"]["training_curriculum_file"], + config["eval_log"], + config["tb"], + ) + + # Create env and store in dict + env = vec_env_create( + env_fn, + instantiate_train_drl_agents, + num_robots=robot_train_params["num_robots"], + num_cpus=cpu_count() - 1, + num_vec_envs=config["n_envs"], + task_mode=config["task_mode"], + PATHS=paths, + agent_list_kwargs={ + "existing_robots": existing_robots, + "robot_model": robot_name, + }, + max_num_moves_per_eps=config["max_num_moves_per_eps"], + ) + robots[robot_name] = {"env": env} + + # Load PPO model and store in dict + model = PPO.load( + os.path.join(robot_train_params["resume"], "best_model.zip"), env + ) + robots[robot_name]["model"] = model + + # Evaluate the policy for one robot type! + # Integration of multiple robot types is not yet implemented + mean_rewards, std_rewards = evaluate_policy( + model=robots[robot_name]["model"], + num_robots=robot_train_params["num_robots"], + env=robots[robot_name]["env"], + n_eval_episodes=config["periodic_eval"]["n_eval_episodes"], + return_episode_rewards=False, + ) + + print("Mean rewards: {}".format(mean_rewards)) + print("Std rewards: {}".format(std_rewards)) + + +if __name__ == "__main__": + args, _ = parse_training_args() + main(args) diff --git a/arena_marl/scripts/deployment/run_agent.py b/arena_marl/scripts/deployment/run_agent.py new file mode 100644 index 000000000..6c758fc1a --- /dev/null +++ b/arena_marl/scripts/deployment/run_agent.py @@ -0,0 +1,217 @@ +import os +import sys +import rospy +import rospkg +import json +import numpy as np +import time +import warnings + +from stable_baselines3 import PPO +from stable_baselines3.common.vec_env import SubprocVecEnv, DummyVecEnv, VecNormalize +from stable_baselines3.common.monitor import Monitor +from stable_baselines3.common.evaluation import evaluate_policy + +from rl_agent.envs.flatland_gym_env import FlatlandEnv +from task_generator.task_generator.tasks import StopReset +from marl_tools.argsparser import parse_run_agent_args +from marl_tools.train_agent_utils import ( + load_hyperparameters_json, + print_hyperparameters, +) + +### AGENT LIST ### +AGENTS = [ + "AGENT_1_2021_04_02__22_03", + "AGENT_2_2021_03_30__23_10", + "AGENT_3_2021_04_01__08_06", + "AGENT_4_2021_04_02__01_07", + "AGENT_5_2021_03_31__18_52", + "AGENT_6_2021_04_04__02_12", + "AGENT_7_2021_04_06__07_00", + "AGENT_8_2021_04_05__22_11", + "AGENT_9_2021_04_04__11_09", + "AGENT_10_2021_04_03__16_57", + "AGENT_11_2021_04_14__20_13", + "AGENT_12_2021_04_05__12_08", + "AGENT_13_2021_04_04__18_04", + "AGENT_14_2021_04_07__01_17", + "AGENT_15_2021_04_08__01_27", + "AGENT_16_2021_04_09__22_24", + "AGENT_17_2021_04_10__15_36", + "AGENT_18_2021_04_11__13_54", + "AGENT_19_2021_04_12__13_17", +] + + +def get_paths(args: dict, AGENT: str): + dir = rospkg.RosPack().get_path("arena_local_planner_drl") + PATHS = { + "model": os.path.join(dir, "agents", AGENT), + "vecnorm": os.path.join(dir, "agents", AGENT, "vec_normalize.pkl"), + "robot_setting": os.path.join( + rospkg.RosPack().get_path("simulator_setup"), "robot", "myrobot.model.yaml" + ), + "robot_as": os.path.join(dir, "configs", "default_settings.yaml"), + "scenario": os.path.join( + rospkg.RosPack().get_path("simulator_setup"), + "scenarios", + args.scenario + ".json", + ), + "curriculum": os.path.join( + dir, "configs", "training_curriculum_map1small.yaml" + ), + "log": os.path.join(dir, "evaluation_logs", AGENT), + } + if args.log and not os.path.exists(PATHS["log"]): + os.makedirs(PATHS["log"]) + return PATHS + + +def make_env( + with_ns: bool, PATHS: dict, PARAMS: dict, log: bool = False, max_steps: int = 1000 +): + """ + Utility function for the evaluation environment. + + :param params: (dict) hyperparameters of agent to be trained + :param PATHS: (dict) script relevant paths + :param log: (bool) to differentiate between train and eval env + :param max_steps: (int) number of steps before the episode is stopped + :return: (Callable) + """ + + def _init(): + ns = f"eval_sim" if with_ns else "" + + env = FlatlandEnv( + ns, + PARAMS["reward_fnc"], + PARAMS["discrete_action_space"], + goal_radius=0.05, + max_steps_per_episode=max_steps, + train_mode=False, + task_mode="scenario", + PATHS=PATHS, + curr_stage=4, + extended_eval=True, + ) + if log: + # eval env + env = Monitor( + env, + PATHS["log"], + False, + info_keywords=( + "collisions", + "distance_travelled", + "time_safe_dist", + "time", + "done_reason", + "is_success", + ), + ) + return env + + return _init + + +if __name__ == "__main__": + args, _ = parse_run_agent_args() + + if args.load: + AGENTS = [args.load] + assert len(AGENTS) > 0, "No agent name was given for evaluation" + + ros_params = rospy.get_param_names() + ns_for_nodes = "/single_env" not in ros_params + + start = time.time() + while len(AGENTS) != 0: + AGENT = AGENTS.pop(0) + print(f"START RUNNING AGENT: {AGENT}") + PATHS = get_paths(args, AGENT) + + assert os.path.isfile(os.path.join(PATHS["model"], "best_model.zip")), ( + "No model file found in %s" % PATHS["model"] + ) + assert os.path.isfile(PATHS["scenario"]), ( + "No scenario file named %s" % PATHS["scenario"] + ) + + PARAMS = load_hyperparameters_json(PATHS) + print_hyperparameters(PARAMS) + + env = DummyVecEnv( + [make_env(ns_for_nodes, PATHS, PARAMS, args.log, args.max_steps)] + ) + if PARAMS["normalize"]: + if not os.path.isfile(PATHS["vecnorm"]): + # without it agent performance will be strongly altered + warnings.warn( + f"Couldn't find VecNormalize pickle for {PATHS['model'].split('/')[-1]}, going to skip this model" + ) + continue + + env = VecNormalize.load(PATHS["vecnorm"], env) + + # load agent + agent = PPO.load(os.path.join(PATHS["model"], "best_model.zip"), env) + + try: + evaluate_policy( + model=agent, env=env, n_eval_episodes=args.num_eps, deterministic=True + ) + except StopReset: + pass + + time = round(time.time() - start) + print(f"Time passed: {time}s") + print("EVALUATION DONE!") + sys.exit() + + # env.reset() + # first_obs = True + + # # iterate through each scenario max_repeat times + # while True: + # if first_obs: + # # send action 'stand still' in order to get first obs + # if params['discrete_action_space']: + # obs, rewards, dones, info = env.step([6]) + # else: + # obs, rewards, dones, info = env.step([[0.0, 0.0]]) + # first_obs = False + # cum_reward = 0.0 + + # # timer = time.time() + # action, _ = agent.predict(obs, deterministic=True) + # # print(f"Action predict time: {(time.time()-timer)*2.5} (sim time)") + + # # clip action + # if not params['discrete_action_space']: + # action = np.maximum( + # np.minimum(agent.action_space.high, action), agent.action_space.low) + + # # apply action + # obs, rewards, done, info = env.step(action) + + # cum_reward += rewards + + # if done: + # if args.verbose == '1': + # if info[0]['done_reason'] == 0: + # done_reason = "exceeded max steps" + # elif info[0]['done_reason'] == 1: + # done_reason = "collision" + # else: + # done_reason = "goal reached" + + # print("Episode finished with reward of %f (finish reason: %s)"% (cum_reward, done_reason)) + # env.reset() + # first_obs = True + + # time.sleep(0.001) + # if rospy.is_shutdown(): + # print('shutdown') + # break diff --git a/arena_marl/scripts/training/marl_test_script.py b/arena_marl/scripts/training/marl_test_script.py new file mode 100644 index 000000000..b9b79e37a --- /dev/null +++ b/arena_marl/scripts/training/marl_test_script.py @@ -0,0 +1,125 @@ +import numpy as np +import rospy +import rospkg +import os + +from stable_baselines3 import PPO +from stable_baselines3.common.callbacks import MarlEvalCallback +from supersuit import pettingzoo_env_to_vec_env_v0, black_death_v2 +from supersuit.vector.sb3_vector_wrapper import SB3VecEnvWrapper + +rospy.set_param("/MARL", True) +rospy.set_param("/num_robots", 8) + +from rl_agent.training_agent_wrapper import TrainingDRLAgent +from scripts.deployment.drl_agent_node import DeploymentDRLAgent +from marl_agent.envs.pettingzoo_env import FlatlandPettingZooEnv + +from nav_msgs.srv import GetMap + +DEFAULT_HYPERPARAMETER = os.path.join( + rospkg.RosPack().get_path("arena_local_planner_drl"), + "configs", + "hyperparameters", + "default.json", +) +DEFAULT_ACTION_SPACE = os.path.join( + rospkg.RosPack().get_path("arena_local_planner_drl"), + "configs", + "default_settings.yaml", +) + + +def instantiate_drl_agents( + num_robots: int = 1, + ns: str = None, + robot_name_prefix: str = "robot", + hyperparameter_path: str = DEFAULT_HYPERPARAMETER, + action_space_path: str = DEFAULT_ACTION_SPACE, +) -> list: + return [ + TrainingDRLAgent( + ns=ns, + robot_name=robot_name_prefix + str(i + 1), + hyperparameter_path=hyperparameter_path, + action_space_path=action_space_path, + ) + for i in range(num_robots) + ] + + +def main(): + # rospy.init_node(f"USER_NODE", anonymous=True) + + # agent_list = instantiate_drl_agents( + # num_robots=8, + # ns="sim_1", + # robot_name_prefix=rospy.get_param("base_robot_name", default="robot"), + # ) + NUM_ROBOTS = 8 + + env = SB3VecEnvWrapper( + pettingzoo_env_to_vec_env_v0( + black_death_v2( + FlatlandPettingZooEnv( + num_agents=NUM_ROBOTS, + ns="sim_1", + agent_list_fn=instantiate_drl_agents, + max_num_moves_per_eps=2000, + ) + ) + ) + ) + obs = env.reset() + + # AGENT = DeploymentDRLAgent( + # agent_name="rule_04", ns="sim_1", robot_name="test1" + # ) + + model = PPO("MlpPolicy", env) + model.learn( + total_timesteps=200000, + callbacks=get_evalcallback( + num_robots=NUM_ROBOTS, + ), + reset_num_timesteps=True, + ) + exit() + agent_names = env.agents + for _ in range(100000000): + if not agent_names: + agent_names = env.possible_agents[:] + obs = env.reset() + + actions = {agent: AGENT.get_action(obs[agent]) for agent in agent_names} + obs, rewards, dones, infos = env.step(actions) + + done_agents = [k for k, v in dones.items() if v] + for agent in done_agents: + agent_names.remove(agent) + + if done_agents: + for agent in done_agents: + if infos[agent]["is_success"]: + print(f"{agent}: finito") + + +def get_evalcallback(num_robots: int) -> MarlEvalCallback: + eval_env = FlatlandPettingZooEnv( + num_agents=num_robots, + ns="eval_sim", + agent_list_fn=instantiate_drl_agents, + max_num_moves_per_eps=2000, + ) + + return MarlEvalCallback( + eval_env, + num_robots, + n_eval_episodes=40, + eval_freq=1, + deterministic=True, + ) + + +if __name__ == "__main__": + main() diff --git a/arena_marl/scripts/training/train_marl_agent.py b/arena_marl/scripts/training/train_marl_agent.py new file mode 100644 index 000000000..689bd45d1 --- /dev/null +++ b/arena_marl/scripts/training/train_marl_agent.py @@ -0,0 +1,226 @@ +import sys +import os, sys, rospy, time + +from datetime import time +from multiprocessing import cpu_count + +import rospy +from multiprocessing import cpu_count, set_start_method + +# from stable_baselines3 import PPO +# from supersuit.vector import MakeCPUAsyncConstructor, ConcatVecEnv +# from supersuit.vector.sb3_vector_wrapper import SB3VecEnvWrapper + +# from marl_tools.custom_mlp_utils import * +from arena_navigation.arena_local_planner.learning_based.arena_local_planner_drl.rl_agent.model.custom_policy import * +from arena_navigation.arena_local_planner.learning_based.arena_local_planner_drl.rl_agent.model.custom_sb3_policy import * + +# from tools.argsparser import parse_training_args +from marl_tools.staged_train_callback import InitiateNewTrainStage + +from tools.argsparser import parse_training_args + +from arena_marl.marl_agent.envs.pettingzoo_env import env_fn +from arena_marl.marl_agent.utils.supersuit_utils import ( + vec_env_create, +) + +# from tools.argsparser import parse_marl_training_args +from marl_tools.train_agent_utils import ( + get_MARL_agent_name_and_start_time, + get_paths, + choose_agent_model, + load_config, + initialize_hyperparameters, +) +from marl_tools import train_agent_utils + +from stable_baselines3.common.callbacks import ( + StopTrainingOnRewardThreshold, + MarlEvalCallback, +) + +from arena_navigation.arena_local_planner.learning_based.arena_local_planner_drl.tools.train_agent_utils import * + +from marl_agent.utils.utils import instantiate_train_drl_agents + + +def main(args): + # load configuration + config = load_config(args.config) + + # set debug_mode + rospy.set_param("debug_mode", config["debug_mode"]) + + robots, existing_robots = {}, 0 + MARL_NAME, START_TIME = get_MARL_agent_name_and_start_time() + + # create seperate model instances for each robot + for robot_name, robot_train_params in config["robots"].items(): + # generate agent name and model specific paths + agent_name = ( + robot_train_params["resume"].split("/")[-1] + if robot_train_params["resume"] + else f"{robot_name}_{START_TIME}" + ) + + paths = train_agent_utils.get_paths( + MARL_NAME, + robot_name, + agent_name, + robot_train_params, + config["training_curriculum"]["training_curriculum_file"], + config["eval_log"], + config["tb"], + ) + + # initialize hyperparameters (save to/ load from json) + hyper_params = train_agent_utils.initialize_hyperparameters( + PATHS=paths, + config=robot_train_params, + n_envs=config["n_envs"], + ) + + env = vec_env_create( + env_fn, + instantiate_train_drl_agents, + num_robots=robot_train_params["num_robots"], + num_cpus=cpu_count() - 1, + num_vec_envs=config["n_envs"], + task_mode=config["task_mode"], + PATHS=paths, + agent_list_kwargs={ + "existing_robots": existing_robots, + "robot_model": robot_name, + }, + max_num_moves_per_eps=config["max_num_moves_per_eps"], + ) + + existing_robots += robot_train_params["num_robots"] + + # env = VecNormalize( + # env, + # training=True, + # norm_obs=True, + # norm_reward=True, + # clip_reward=15, + # clip_obs=15, + # ) + + model = choose_agent_model( + agent_name, paths, robot_train_params, env, hyper_params, config["n_envs"] + ) + + # add configuration for one robot to robots dictionary + robots[robot_name] = { + "model": model, + "env": env, + "n_envs": config["n_envs"], + "robot_train_params": robot_train_params, + "hyper_params": hyper_params, + "paths": paths, + } + + # set num of timesteps to be generated + n_timesteps = 40000000 if config["n_timesteps"] is None else config["n_timesteps"] + + start = time.time() + try: + model = robots[robot_name]["model"] + model.learn( + total_timesteps=n_timesteps, + reset_num_timesteps=True, + # Übergib einfach das dict für den aktuellen roboter + callback=get_evalcallback( + eval_config=config["periodic_eval"], + curriculum_config=config["training_curriculum"], + stop_training_config=config["stop_training"], + train_env=robots[robot_name]["env"], + num_robots=robots[robot_name]["robot_train_params"]["num_robots"], + num_envs=config["n_envs"], + task_mode=config["task_mode"], + PATHS=robots[robot_name]["paths"], + ), + ) + except KeyboardInterrupt: + print("KeyboardInterrupt..") + # finally: + # update the timesteps the model has trained in total + # update_total_timesteps_json(n_timesteps, PATHS) + + robots[robot_name][model].env.close() + print(f"Time passed: {time.time() - start}s") + print("Training script will be terminated") + sys.exit() + + +def get_evalcallback( + eval_config: dict, + curriculum_config: dict, + stop_training_config: dict, + train_env: VecEnv, + num_robots: int, + num_envs: int, + task_mode: str, + PATHS: dict, +) -> MarlEvalCallback: + """Function which generates an evaluation callback with an evaluation environment. + + Args: + train_env (VecEnv): Vectorized training environment + num_robots (int): Number of robots in the environment + num_envs (int): Number of parallel spawned environments + task_mode (str): Task mode for the current experiment + PATHS (dict): Dictionary which holds hyperparameters for the experiment + + Returns: + MarlEvalCallback: [description] + """ + eval_env = env_fn( + num_agents=num_robots, + ns="eval_sim", + agent_list_fn=instantiate_train_drl_agents, + max_num_moves_per_eps=eval_config["max_num_moves_per_eps"], + PATHS=PATHS, + ) + + # eval_env = VecNormalize( + # eval_env, + # training=False, + # norm_obs=True, + # norm_reward=False, + # clip_reward=15, + # clip_obs=3.5, + # ) + + return MarlEvalCallback( + train_env=train_env, + eval_env=eval_env, + num_robots=num_robots, + n_eval_episodes=eval_config["n_eval_episodes"], + eval_freq=eval_config["eval_freq"], + deterministic=True, + log_path=PATHS["eval"], + best_model_save_path=PATHS["model"], + callback_on_eval_end=InitiateNewTrainStage( + n_envs=num_envs, + treshhold_type=curriculum_config["threshold_type"], + upper_threshold=curriculum_config["upper_threshold"], + lower_threshold=curriculum_config["lower_threshold"], + task_mode=task_mode, + verbose=1, + ), + callback_on_new_best=StopTrainingOnRewardThreshold( + treshhold_type=stop_training_config["threshold_type"], + threshold=stop_training_config["threshold"], + verbose=1, + ), + ) + + +if __name__ == "__main__": + set_start_method("fork") + # args, _ = parse_marl_training_args() + args, _ = parse_training_args() + # rospy.init_node("train_env", disable_signals=False, anonymous=True) + main(args) diff --git a/arena_marl/setup.py b/arena_marl/setup.py new file mode 100755 index 000000000..2dd27cb99 --- /dev/null +++ b/arena_marl/setup.py @@ -0,0 +1,16 @@ +## ! DO NOT MANUALLY INVOKE THIS setup.py, USE CATKIN INSTEAD + +from distutils.core import setup +from catkin_pkg.python_setup import generate_distutils_setup + +# fetch values from package.xml +setup_args = generate_distutils_setup( + packages=[ + "rl_agent", + "rl_agent.envs", + "rl_agent.utils", + "scripts", + "tools", + ], +) +setup(**setup_args) diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings.yaml b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings.yaml similarity index 96% rename from arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings.yaml rename to arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings.yaml index cc4c53e98..bcf07f4f1 100755 --- a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings.yaml +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings.yaml @@ -1,4 +1,5 @@ robot: + holonomic: False discrete_actions: - name: move_forward linear: 0.30 diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_agvota.yaml b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_agvota.yaml similarity index 97% rename from arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_agvota.yaml rename to arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_agvota.yaml index de7680846..d9c3a3482 100755 --- a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_agvota.yaml +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_agvota.yaml @@ -1,4 +1,5 @@ robot: + radius: 0.629 holonomic: False discrete_actions: - name: move_forward diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_burger.yaml b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_burger.yaml similarity index 97% rename from arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_burger.yaml rename to arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_burger.yaml index 749d30395..dc0782237 100755 --- a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_burger.yaml +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_burger.yaml @@ -1,4 +1,5 @@ robot: + radius: 0.113 holonomic: False discrete_actions: - name: move_forward diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_cob4.yaml b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_cob4.yaml similarity index 98% rename from arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_cob4.yaml rename to arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_cob4.yaml index 2fb2c227b..41ed40c74 100644 --- a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_cob4.yaml +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_cob4.yaml @@ -1,5 +1,6 @@ # TODO: The discrete actions have not been changed (from ridgeback here) robot: + radius: 0.36 holonomic: True discrete_actions: - name: move_forward diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_jackal.yaml b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_jackal.yaml similarity index 97% rename from arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_jackal.yaml rename to arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_jackal.yaml index 7d43b0e1d..2e6ddbed4 100755 --- a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_jackal.yaml +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_jackal.yaml @@ -1,4 +1,5 @@ robot: + radius: 0.267 holonomic: False discrete_actions: - name: move_forward diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_ridgeback.yaml b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_ridgeback.yaml similarity index 97% rename from arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_ridgeback.yaml rename to arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_ridgeback.yaml index 10cbb2319..eeae900c3 100755 --- a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_ridgeback.yaml +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_ridgeback.yaml @@ -1,4 +1,5 @@ robot: + radius: 0.625 holonomic: True discrete_actions: - name: move_forward diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_rto.yaml b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_rto.yaml similarity index 97% rename from arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_rto.yaml rename to arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_rto.yaml index 1157ed13c..0ccfef053 100755 --- a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_rto.yaml +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_rto.yaml @@ -1,5 +1,6 @@ # TODO: The discrete actions have not been changed (from ridgeback here) robot: + radius: 0.225 holonomic: True discrete_actions: - name: move_forward diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_rto_real.yaml b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_rto_real.yaml similarity index 97% rename from arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_rto_real.yaml rename to arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_rto_real.yaml index 8e9005ef2..b9fee66ea 100755 --- a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_rto_real.yaml +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_rto_real.yaml @@ -1,5 +1,6 @@ # TODO: The discrete actions have not been changed (from ridgeback here) robot: + radius: 0.225 holonomic: True discrete_actions: - name: move_forward diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_tiago.yaml b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_tiago.yaml similarity index 97% rename from arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_tiago.yaml rename to arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_tiago.yaml index 78232be97..c7a2d634c 100755 --- a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_tiago.yaml +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_tiago.yaml @@ -1,5 +1,6 @@ # TODO: @Tuan adjust the discrete actions robot: + radius: 0.27 holonomic: False discrete_actions: - name: move_forward diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_waffle_pi.yaml b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_waffle_pi.yaml similarity index 97% rename from arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_waffle_pi.yaml rename to arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_waffle_pi.yaml index 3fd4756f6..1cdd02a0c 100755 --- a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_waffle_pi.yaml +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_waffle_pi.yaml @@ -1,5 +1,6 @@ # TODO: The discrete actions have not been changed (from burger here) robot: + radius: 0.208 holonomic: False discrete_actions: - name: move_forward diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_youbot.yaml b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_youbot.yaml similarity index 98% rename from arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_youbot.yaml rename to arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_youbot.yaml index 40ef0e741..bfe85d23f 100755 --- a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/default_settings_youbot.yaml +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/action_spaces/default_settings_youbot.yaml @@ -2,6 +2,7 @@ # values from: https://github.com/youbot/youbot_navigation/blob/hydro-devel/youbot_navigation_common/config/base_local_planner_params.yaml # and values from here: http://www.youbot-store.com/wiki/index.php/YouBot_Detailed_Specifications robot: + radius: 0.347 holonomic: True discrete_actions: - name: move_forward diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/deployment_config.yaml b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/deployment_config.yaml new file mode 100644 index 000000000..f5503fb10 --- /dev/null +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/deployment_config.yaml @@ -0,0 +1,68 @@ +# in debug_mode no agent directories will be created and no models will be saved +debug_mode: true + +# Hardware specifc configurations +# number of parallel environments +n_envs: 1 +# gpu yes or no +no_gpu: false + + +### Global configuration that applies to all robots +# navigation task mode, chose from "random" or "staged" +task_mode: "staged" +# number of simulation timesteps +n_timesteps: 40000000 +max_num_moves_per_eps: 1000 + +periodic_eval: + # max number of steps per episode + max_num_moves_per_eps: 1000 + # number of evaluation episodes + n_eval_episodes: 100 + # evaluation frequency, evaluation after every n_envs * 20000 timesteps + eval_freq: 20000 + +### training_curriculum +# threshold metric to be considered during evaluation +# can be either "succ" (success rate) or "rew" (reward) +training_curriculum: + # file for the robot's learning curriculum + training_curriculum_file: "training_curriculum.yaml" + threshold_type: "succ" + upper_threshold: 0.8 + lower_threshold: 0.6 + +### stop training on threshold +# stops training when last stage reached and threshold satisfied +stop_training: + threshold_type: "succ" + threshold: 0.9 + + +# save evaluation stats during training in log file +eval_log: false +# use tensorboard +tb: false + +robots: + jackal: + # number of robots of this type + num_robots: 2 + # name of hyperparameter file located in the configs/hyperparameters directory + hyperparameter_file: "default.json" + # name of architecture defined in the Policy factory + architecture_name: "AGENT_24" + # path to latest checkpoint; if provided the training will be resumed from that checkpoint + resume: "/home/ignc/catkin_ws/src/arena-rosnav/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/agents/jackal" + # burger: + # # number of robots of this type + # num_robots: 4 + # # name of hyperparameter file located in the configs/hyperparameters directory + # hyperparameter_file: "default.json" + # # name of architecture defined in the Policy factory + # architecture_name: "AGENT_24" + # # path to latest checkpoint; if provided the training will be resumed from that checkpoint + # resume: null + # add more robots as you wish + \ No newline at end of file diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/hyperparameters/default.json b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/hyperparameters/default.json index aab39666c..c7a84645a 100644 --- a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/hyperparameters/default.json +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/hyperparameters/default.json @@ -2,7 +2,7 @@ "agent_name": "", "robot": "myrobot", "actions_in_observationspace": true, - "reward_fnc": "rule_05", + "reward_fnc": "rule_04", "discrete_action_space": false, "normalize": false, "task_mode": "staged", diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/training_config.yaml b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/training_config.yaml new file mode 100644 index 000000000..99ef999c7 --- /dev/null +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/training_config.yaml @@ -0,0 +1,68 @@ +# in debug_mode no agent directories will be created and no models will be saved +debug_mode: true + +# Hardware specifc configurations +# number of parallel environments +n_envs: 1 +# gpu yes or no +no_gpu: false + + +### Global configuration that applies to all robots +# navigation task mode, chose from "random" or "staged" +task_mode: "staged" +# number of simulation timesteps +n_timesteps: 40000000 +max_num_moves_per_eps: 1000 + +periodic_eval: + # max number of steps per episode + max_num_moves_per_eps: 1000 + # number of evaluation episodes + n_eval_episodes: 100 + # evaluation frequency, evaluation after every n_envs * 20000 timesteps + eval_freq: 20000 + +### training_curriculum +# threshold metric to be considered during evaluation +# can be either "succ" (success rate) or "rew" (reward) +training_curriculum: + # file for the robot's learning curriculum + training_curriculum_file: "training_curriculum.yaml" + threshold_type: "succ" + upper_threshold: 0.8 + lower_threshold: 0.6 + +### stop training on threshold +# stops training when last stage reached and threshold satisfied +stop_training: + threshold_type: "succ" + threshold: 0.9 + + +# save evaluation stats during training in log file +eval_log: false +# use tensorboard +tb: false + +robots: + jackal: + # number of robots of this type + num_robots: 2 + # name of hyperparameter file located in the configs/hyperparameters directory + hyperparameter_file: "default.json" + # name of architecture defined in the Policy factory + architecture_name: "AGENT_24" + # path to latest checkpoint; if provided the training will be resumed from that checkpoint + resume: null + # burger: + # # number of robots of this type + # num_robots: 4 + # # name of hyperparameter file located in the configs/hyperparameters directory + # hyperparameter_file: "default.json" + # # name of architecture defined in the Policy factory + # architecture_name: "AGENT_24" + # # path to latest checkpoint; if provided the training will be resumed from that checkpoint + # resume: null + # add more robots as you wish + \ No newline at end of file diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/training_curriculum.yaml b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/training_curriculums/training_curriculum.yaml similarity index 100% rename from arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/training_curriculum.yaml rename to arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/training_curriculums/training_curriculum.yaml diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/training_curriculum_map1small.yaml b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/training_curriculums/training_curriculum_map1small.yaml similarity index 100% rename from arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/training_curriculum_map1small.yaml rename to arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/configs/training_curriculums/training_curriculum_map1small.yaml diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/__pycache__/__init__.cpython-38.pyc b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/__pycache__/__init__.cpython-38.pyc index cde1f812d..071e0c50a 100644 Binary files a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/__pycache__/__init__.cpython-38.pyc and b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/__pycache__/__init__.cpython-38.pyc differ diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/base_agent_wrapper.py b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/base_agent_wrapper.py index ff3e18a6f..f8e3e5f70 100644 --- a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/base_agent_wrapper.py +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/base_agent_wrapper.py @@ -16,14 +16,7 @@ from rl_agent.utils.reward import RewardCalculator robot_model = rospy.get_param("model") -ROOT_ROBOT_PATH = os.path.join( - rospkg.RosPack().get_path("simulator_setup"), "robot" -) -DEFAULT_ACTION_SPACE = os.path.join( - rospkg.RosPack().get_path("arena_local_planner_drl"), - "configs", - f"default_settings_{robot_model}.yaml", -) +ROOT_ROBOT_PATH = os.path.join(rospkg.RosPack().get_path("simulator_setup"), "robot") DEFAULT_HYPERPARAMETER = os.path.join( rospkg.RosPack().get_path("arena_local_planner_drl"), "configs", @@ -38,39 +31,46 @@ class BaseDRLAgent(ABC): def __init__( self, ns: str = None, - robot_name: str = None, + robot_model: str = "burger", + robot_ns: str = None, hyperparameter_path: str = DEFAULT_HYPERPARAMETER, - action_space_path: str = DEFAULT_ACTION_SPACE, - *args, - **kwargs, ) -> None: """[summary] Args: ns (str, optional): Agent name (directory has to be of the same name). Defaults to None. - robot_name (str, optional): + robot_model (str, optional): + Robot model name. Defaults to "burger". + robot_ns (str, optional): Robot specific ROS namespace extension. Defaults to None. hyperparameter_path (str, optional): Path to json file containing defined hyperparameters. Defaults to DEFAULT_HYPERPARAMETER. - action_space_path (str, optional): - Path to yaml file containing action space settings. - Defaults to DEFAULT_ACTION_SPACE. """ self._is_train_mode = rospy.get_param("/train_mode") - self._ns = "" if ns is None or ns == "" else ns + "/" - self._ns_robot = ( - self._ns if robot_name is None else self._ns + robot_name + "/" - ) - self._robot_sim_ns = robot_name + self._ns = "" if ns is None or not ns else f"{ns}/" + self._ns_robot = self._ns if robot_ns is None else self._ns + robot_ns + self._robot_sim_ns = robot_ns + + self.robot_model = robot_model - self.load_hyperparameters(path=hyperparameter_path) robot_setting_path = os.path.join( - ROOT_ROBOT_PATH, self.robot_config_name + ".model.yaml" + ROOT_ROBOT_PATH, f"{self.robot_model}.model.yaml" ) + + action_space_path = os.path.join( + rospkg.RosPack().get_path("arena_local_planner_drl"), + "configs", + "action_spaces", + f"default_settings_{self.robot_model}.yaml", + ) + + self.load_hyperparameters(path=hyperparameter_path) self.read_setting_files(robot_setting_path, action_space_path) + # self._check_robot_type_from_params() + self.setup_action_space() self.setup_reward_calculator() @@ -84,13 +84,13 @@ def __init__( if self._is_train_mode: # w/o action publisher node self._action_pub = rospy.Publisher( - f"{self._ns_robot}cmd_vel", Twist, queue_size=1 + f"{self._ns_robot}/cmd_vel", Twist, queue_size=1 ) else: # w/ action publisher node # (controls action rate being published on '../cmd_vel') self._action_pub = rospy.Publisher( - f"{self._ns_robot}cmd_vel_pub", Twist, queue_size=1 + f"{self._ns_robot}/cmd_vel_pub", Twist, queue_size=1 ) @abstractmethod @@ -108,15 +108,13 @@ def load_hyperparameters(self, path: str) -> None: Args: path (str): Path to the json file. """ - assert os.path.isfile( - path - ), f"Hyperparameters file cannot be found at {path}!" + assert os.path.isfile(path), f"Hyperparameters file cannot be found at {path}!" with open(path, "r") as file: hyperparams = json.load(file) self._agent_params = hyperparams - self._get_robot_name_from_params() + self.robot_config_name = robot_model rospy.set_param( "actions_in_obs", self._agent_params.get("actions_in_observationspace", False), @@ -139,7 +137,12 @@ def read_setting_files( """ self._num_laser_beams = None self._laser_range = None - self._robot_radius = rospy.get_param("radius") * 1.05 + + with open(action_space_yaml, "r", encoding="utf-8") as target: + config = yaml.load(target, Loader=yaml.FullLoader) + + self._robot_radius = config["robot"]["radius"] * 1.05 + with open(robot_setting_yaml, "r") as fd: robot_data = yaml.safe_load(fd) @@ -151,10 +154,8 @@ def read_setting_files( laser_angle_increment = plugin["angle"]["increment"] self._num_laser_beams = int( round( - (laser_angle_max - laser_angle_min) - / laser_angle_increment + (laser_angle_max - laser_angle_min) / laser_angle_increment ) - + 1 ) self._laser_range = plugin["range"] @@ -187,19 +188,21 @@ def read_setting_files( ], } - def _get_robot_name_from_params(self): + def _check_robot_type_from_params(self): """Retrives the agent-specific robot name from the dictionary loaded\ - from respective 'hyperparameter.json'. + from respective 'hyperparameter.json' and compares it to the provided + robot model from initialization. """ assert self._agent_params and self._agent_params["robot"] - self.robot_config_name = self._agent_params["robot"] + assert self.robot_model == self._agent_params["robot"], ( + "Robot model in hyperparameter.json is not the same as the parsed model!" + f"({self.robot_model} != {self._agent_params['robot']})" + ) def setup_action_space(self) -> None: """Sets up the action space. (spaces.Box)""" assert self._discrete_actions or self._cont_actions - assert ( - self._agent_params and "discrete_action_space" in self._agent_params - ) + assert self._agent_params and "discrete_action_space" in self._agent_params if self._agent_params["discrete_action_space"]: # self._discrete_actions is a list, each element is a dict with the keys ["name", 'linear','angular'] @@ -298,9 +301,7 @@ def normalize_observations(self, merged_obs: np.ndarray) -> np.ndarray: Returns: np.ndarray: Normalized observations array. """ - assert self._agent_params["normalize"] and hasattr( - self, "_obs_norm_func" - ) + assert self._agent_params["normalize"] and hasattr(self, "_obs_norm_func") return self._obs_norm_func(merged_obs) def get_action(self, obs: np.ndarray) -> np.ndarray: diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/envs/__pycache__/__init__.cpython-38.pyc b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/envs/__pycache__/__init__.cpython-38.pyc index 51c998e79..4cf9b4cbe 100644 Binary files a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/envs/__pycache__/__init__.cpython-38.pyc and b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/envs/__pycache__/__init__.cpython-38.pyc differ diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/envs/__pycache__/flatland_gym_env.cpython-38.pyc b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/envs/__pycache__/flatland_gym_env.cpython-38.pyc index 17b7b6ca3..a4ba6ebb8 100644 Binary files a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/envs/__pycache__/flatland_gym_env.cpython-38.pyc and b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/envs/__pycache__/flatland_gym_env.cpython-38.pyc differ diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/envs/flatland_gym_env.py b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/envs/flatland_gym_env.py index f3fc28340..fb33047ad 100755 --- a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/envs/flatland_gym_env.py +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/envs/flatland_gym_env.py @@ -1,10 +1,12 @@ #! /usr/bin/env python3 from operator import is_ +import os from random import randint import gym from gym import spaces from gym.spaces import space from typing import Union +import rospkg from stable_baselines3.common.env_checker import check_env import yaml from rl_agent.utils.observation_collector import ObservationCollector @@ -68,7 +70,9 @@ def __init__( ns_int = int(ns.split("_")[1]) time.sleep(ns_int * 2) except Exception: - rospy.logwarn(f"Can't not determinate the number of the environment, training script may crash!") + rospy.logwarn( + f"Can't not determinate the number of the environment, training script may crash!" + ) # process specific namespace in ros system self.ns_prefix = "" if (ns == "" or ns is None) else "/" + ns + "/" @@ -115,17 +119,25 @@ def __init__( # action agent publisher if self._is_train_mode: - self.agent_action_pub = rospy.Publisher(f"{self.ns_prefix}cmd_vel", Twist, queue_size=1) + self.agent_action_pub = rospy.Publisher( + f"{self.ns_prefix}cmd_vel", Twist, queue_size=1 + ) else: - self.agent_action_pub = rospy.Publisher(f"{self.ns_prefix}cmd_vel_pub", Twist, queue_size=1) + self.agent_action_pub = rospy.Publisher( + f"{self.ns_prefix}cmd_vel_pub", Twist, queue_size=1 + ) # service clients if self._is_train_mode: self._service_name_step = f"{self.ns_prefix}step_world" - self._sim_step_client = rospy.ServiceProxy(self._service_name_step, StepWorld) + self._sim_step_client = rospy.ServiceProxy( + self._service_name_step, StepWorld + ) # instantiate task manager - self.task = get_predefined_task(ns, mode=task_mode, start_stage=kwargs["curr_stage"], PATHS=PATHS) + self.task = get_predefined_task( + ns, mode=task_mode, start_stage=kwargs["curr_stage"], PATHS=PATHS + ) self._steps_curr_episode = 0 self._episode = 0 @@ -153,7 +165,8 @@ def setup_by_configuration(self, robot_yaml_path: str, settings_yaml_path: str): Args: robot_yaml_path (str): [description] """ - self._robot_radius = rospy.get_param("radius") + 0.25 + self._robot_radius = yaml.load(settings_yaml_path)["robot"]["radius"] + 0.25 + with open(robot_yaml_path, "r") as fd: robot_data = yaml.safe_load(fd) @@ -163,7 +176,11 @@ def setup_by_configuration(self, robot_yaml_path: str, settings_yaml_path: str): laser_angle_min = plugin["angle"]["min"] laser_angle_max = plugin["angle"]["max"] laser_angle_increment = plugin["angle"]["increment"] - self._laser_num_beams = int(round((laser_angle_max - laser_angle_min) / laser_angle_increment)) + self._laser_num_beams = int( + round( + (laser_angle_max - laser_angle_min) / laser_angle_increment + ) + ) self._laser_max_range = plugin["range"] with open(settings_yaml_path, "r") as fd: @@ -173,12 +190,18 @@ def setup_by_configuration(self, robot_yaml_path: str, settings_yaml_path: str): if self._is_action_space_discrete: # self._discrete_actions is a list, each element is a dict with the keys ["name", 'linear','angular'] - assert not self._holonomic, "Discrete action space currently not supported for holonomic robots" + assert ( + not self._holonomic + ), "Discrete action space currently not supported for holonomic robots" self._discrete_acitons = setting_data["robot"]["discrete_actions"] self.action_space = spaces.Discrete(len(self._discrete_acitons)) else: - linear_range = setting_data["robot"]["continuous_actions"]["linear_range"] - angular_range = setting_data["robot"]["continuous_actions"]["angular_range"] + linear_range = setting_data["robot"]["continuous_actions"][ + "linear_range" + ] + angular_range = setting_data["robot"]["continuous_actions"][ + "angular_range" + ] if not self._holonomic: self.action_space = spaces.Box( @@ -218,7 +241,9 @@ def _pub_action(self, action: np.ndarray) -> Twist: self.agent_action_pub.publish(action_msg) def _translate_disc_action(self, action): - assert not self._holonomic, "Discrete action space currently not supported for holonomic robots" + assert ( + not self._holonomic + ), "Discrete action space currently not supported for holonomic robots" new_action = np.array([]) new_action = np.append(new_action, self._discrete_acitons[action]["linear"]) new_action = np.append(new_action, self._discrete_acitons[action]["angular"]) @@ -252,7 +277,9 @@ def step(self, action: np.ndarray): self._steps_curr_episode += 1 # wait for new observations - merged_obs, obs_dict = self.observation_collector.get_observations(last_action=self._last_action) + merged_obs, obs_dict = self.observation_collector.get_observations( + last_action=self._last_action + ) self._last_action = action # calculate reward @@ -337,7 +364,9 @@ def _update_eval_statistics(self, obs_dict: dict, reward_info: dict): """ # distance travelled if self._last_robot_pose is not None: - self._distance_travelled += FlatlandEnv.get_distance(self._last_robot_pose, obs_dict["robot_pose"]) + self._distance_travelled += FlatlandEnv.get_distance( + self._last_robot_pose, obs_dict["robot_pose"] + ) # collision detector if "crash" in reward_info: diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/__init__.cpython-38.pyc b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/__init__.cpython-38.pyc index c3d1d140b..69c58f917 100644 Binary files a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/__init__.cpython-38.pyc and b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/__init__.cpython-38.pyc differ diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/agent_factory.cpython-38.pyc b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/agent_factory.cpython-38.pyc index 88b5715b0..c5651744e 100644 Binary files a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/agent_factory.cpython-38.pyc and b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/agent_factory.cpython-38.pyc differ diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/base_agent.cpython-38.pyc b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/base_agent.cpython-38.pyc index 6702e4224..32cd09bb5 100644 Binary files a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/base_agent.cpython-38.pyc and b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/base_agent.cpython-38.pyc differ diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/custom_policy.cpython-38.pyc b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/custom_policy.cpython-38.pyc index 3789ff424..cc886151e 100644 Binary files a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/custom_policy.cpython-38.pyc and b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/custom_policy.cpython-38.pyc differ diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/custom_sb3_policy.cpython-38.pyc b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/custom_sb3_policy.cpython-38.pyc index 5ae530396..80b162dc6 100644 Binary files a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/custom_sb3_policy.cpython-38.pyc and b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/custom_sb3_policy.cpython-38.pyc differ diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/feature_extractors.cpython-38.pyc b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/feature_extractors.cpython-38.pyc index 3e0d55ca5..f4226141a 100644 Binary files a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/feature_extractors.cpython-38.pyc and b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/__pycache__/feature_extractors.cpython-38.pyc differ diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/agent_factory.py b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/agent_factory.py index 945f9627d..cd381e86d 100644 --- a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/agent_factory.py +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/model/agent_factory.py @@ -1,3 +1,4 @@ +from warnings import warn from typing import Callable, Type, Union from stable_baselines3.common.policies import BasePolicy @@ -24,7 +25,11 @@ def register(cls, name: str) -> Callable: """ def inner_wrapper(wrapped_class) -> Callable: - assert name not in cls.registry, f"Agent '{name}' already exists!" + if name in cls.registry: + warn( + f"Try to register agent: '{name}' although an entry already exists. " + "Register entry will be overwritten if there exists another architecture with the same id." + ) assert issubclass(wrapped_class, BaseAgent) or issubclass( wrapped_class, BasePolicy ), f"Wrapped class {wrapped_class.__name__} is neither of type 'BaseAgent' nor 'BasePolicy!'" @@ -54,7 +59,7 @@ def instantiate(cls, name: str, **kwargs) -> Union[Type[BaseAgent], Type[BasePol """ assert name in cls.registry, f"Agent '{name}' is not registered!" agent_class = cls.registry[name] - + if issubclass(agent_class, BaseAgent): return agent_class(**kwargs) else: diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/training_agent_wrapper.py b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/training_agent_wrapper.py index cbb49bea1..edbf5746d 100644 --- a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/training_agent_wrapper.py +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/training_agent_wrapper.py @@ -8,23 +8,16 @@ from geometry_msgs.msg import Twist -robot_model = rospy.get_param("model") -DEFAULT_ACTION_SPACE = os.path.join( - rospkg.RosPack().get_path("arena_local_planner_drl"), - "configs", - f"default_settings_{robot_model}.yaml", -) - class TrainingDRLAgent(BaseDRLAgent): def __init__( self, ns: str, - robot_name: str, + robot_model: str, + robot_ns: str, hyperparameter_path: str, - action_space_path: str = DEFAULT_ACTION_SPACE, *args, - **kwargs + **kwargs, ) -> None: """DRL Agent Wrapper Class for training. @@ -51,7 +44,7 @@ def __init__( Args: ns (str, optional): Agent name (directory has to be of the same name). Defaults to None. - robot_name (str, optional): + robot_ns (str, optional): Robot specific ROS namespace extension. Defaults to None. hyperparameter_path (str, optional): Path to json file containing defined hyperparameters. @@ -62,11 +55,11 @@ def __init__( """ super().__init__( ns=ns, - robot_name=robot_name, + robot_model=robot_model, + robot_ns=robot_ns, hyperparameter_path=hyperparameter_path, - action_space_path=action_space_path, *args, - **kwargs + **kwargs, ) def setup_agent(self) -> None: diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/utils/observation_collector.py b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/utils/observation_collector.py index 089b0d908..9a48a07f2 100755 --- a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/utils/observation_collector.py +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/utils/observation_collector.py @@ -69,9 +69,7 @@ def __init__( dtype=np.float32, ), spaces.Box(low=0, high=15, shape=(1,), dtype=np.float32), - spaces.Box( - low=-np.pi, high=np.pi, shape=(1,), dtype=np.float32 - ), + spaces.Box(low=-np.pi, high=np.pi, shape=(1,), dtype=np.float32), ) ) else: @@ -83,9 +81,7 @@ def __init__( shape=(num_lidar_beams,), dtype=np.float32, ), - spaces.Box( - low=0, high=15, shape=(1,), dtype=np.float32 - ), # rho + spaces.Box(low=0, high=15, shape=(1,), dtype=np.float32), # rho spaces.Box( low=-np.pi, high=np.pi, @@ -123,9 +119,7 @@ def __init__( # synchronization parameters self._ext_time_sync = external_time_sync - self._first_sync_obs = ( - True # whether to return first sync'd obs or most recent - ) + self._first_sync_obs = True # whether to return first sync'd obs or most recent self.max_deque_size = 10 self._sync_slop = 0.05 @@ -167,18 +161,22 @@ def __init__( # self._clock_sub = rospy.Subscriber( # f'{self.ns_prefix}clock', Clock, self.callback_clock, tcp_nodelay=True) - + goal_topic = ( + f"{self.ns_prefix}subgoal" + if rospy.get_param("num_robots", default=1) == 1 + else f"{self.ns_prefix}goal" + ) self._subgoal_sub = rospy.Subscriber( - f"{self.ns_prefix}subgoal", PoseStamped, self.callback_subgoal + goal_topic, PoseStamped, self.callback_subgoal ) - self._globalplan_sub = rospy.Subscriber( f"{self.ns_prefix}globalPlan", Path, self.callback_global_plan ) # service clients if self._is_train_mode: - self._service_name_step = f"{self.ns_prefix}step_world" + _sim_namespace = self.ns_prefix.split("/")[1] + self._service_name_step = f"/{_sim_namespace}/step_world" self._sim_step_client = rospy.ServiceProxy( self._service_name_step, StepWorld ) @@ -244,9 +242,9 @@ def _get_goal_pose_in_robot_frame(goal_pos: Pose2D, robot_pos: Pose2D): y_relative = goal_pos.y - robot_pos.y x_relative = goal_pos.x - robot_pos.x rho = (x_relative ** 2 + y_relative ** 2) ** 0.5 - theta = ( - np.arctan2(y_relative, x_relative) - robot_pos.theta + 4 * np.pi - ) % (2 * np.pi) - np.pi + theta = (np.arctan2(y_relative, x_relative) - robot_pos.theta + 4 * np.pi) % ( + 2 * np.pi + ) - np.pi return rho, theta def get_sync_obs(self): @@ -315,9 +313,7 @@ def callback_subgoal(self, msg_Subgoal): return def callback_global_plan(self, msg_global_plan): - self._globalplan = ObservationCollector.process_global_plan_msg( - msg_global_plan - ) + self._globalplan = ObservationCollector.process_global_plan_msg(msg_global_plan) return def callback_scan(self, msg_laserscan): @@ -330,9 +326,7 @@ def callback_robot_state(self, msg_robotstate): self._rs_deque.popleft() self._rs_deque.append(msg_robotstate) - def callback_observation_received( - self, msg_LaserScan, msg_RobotStateStamped - ): + def callback_observation_received(self, msg_LaserScan, msg_RobotStateStamped): # process sensor msg self._scan = self.process_scan_msg(msg_LaserScan) self._robot_pose, self._robot_vel = self.process_robot_state_msg( diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/utils/reward.py b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/utils/reward.py index f3c212f9c..89e667d0f 100755 --- a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/utils/reward.py +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/rl_agent/utils/reward.py @@ -9,7 +9,7 @@ class RewardCalculator: def __init__( self, - holonomic: float, + holonomic: bool, robot_radius: float, safe_dist: float, goal_radius: float, diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/scripts/training/train_agent.py b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/scripts/training/train_agent.py index af281c3f3..2a8702901 100755 --- a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/scripts/training/train_agent.py +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/scripts/training/train_agent.py @@ -20,6 +20,7 @@ def main(): + # parse name of training config file args, _ = parse_training_args() # in debug mode, we emulate multiprocessing on only one process @@ -51,11 +52,19 @@ def main(): # when debug run on one process only if not args.debug and ns_for_nodes: env = SubprocVecEnv( - [make_envs(args, ns_for_nodes, i, params=params, PATHS=PATHS) for i in range(args.n_envs)], + [ + make_envs(args, ns_for_nodes, i, params=params, PATHS=PATHS) + for i in range(args.n_envs) + ], start_method="fork", ) else: - env = DummyVecEnv([make_envs(args, ns_for_nodes, i, params=params, PATHS=PATHS) for i in range(args.n_envs)]) + env = DummyVecEnv( + [ + make_envs(args, ns_for_nodes, i, params=params, PATHS=PATHS) + for i in range(args.n_envs) + ] + ) # threshold settings for training curriculum # type can be either 'succ' or 'rew' @@ -69,7 +78,9 @@ def main(): ) # stop training on reward threshold callback - stoptraining_cb = StopTrainingOnRewardThreshold(treshhold_type="succ", threshold=0.95, verbose=1) + stoptraining_cb = StopTrainingOnRewardThreshold( + treshhold_type="succ", threshold=0.95, verbose=1 + ) # instantiate eval environment # take task_manager from first sim (currently evaluation only provided for single process) @@ -113,7 +124,9 @@ def main(): model = PPO( "MlpPolicy", env, - policy_kwargs=dict(net_arch=args.net_arch, activation_fn=get_act_fn(args.act_fn)), + policy_kwargs=dict( + net_arch=args.net_arch, activation_fn=get_act_fn(args.act_fn) + ), gamma=params["gamma"], n_steps=params["n_steps"], ent_coef=params["ent_coef"], @@ -128,7 +141,9 @@ def main(): verbose=1, ) elif args.agent is not None: - agent: Union[Type[BaseAgent], Type[ActorCriticPolicy]] = AgentFactory.instantiate(args.agent) + agent: Union[ + Type[BaseAgent], Type[ActorCriticPolicy] + ] = AgentFactory.instantiate(args.agent) if isinstance(agent, BaseAgent): model = PPO( agent.type.value, @@ -166,7 +181,8 @@ def main(): ) else: raise TypeError( - f"Registered agent class {args.agent} is neither of type" "'BaseAgent' or 'ActorCriticPolicy'!" + f"Registered agent class {args.agent} is neither of type" + "'BaseAgent' or 'ActorCriticPolicy'!" ) else: # load flag diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/tools/__pycache__/__init__.cpython-38.pyc b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/tools/__pycache__/__init__.cpython-38.pyc index 3da04eff7..56b64218c 100644 Binary files a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/tools/__pycache__/__init__.cpython-38.pyc and b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/tools/__pycache__/__init__.cpython-38.pyc differ diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/tools/__pycache__/argsparser.cpython-38.pyc b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/tools/__pycache__/argsparser.cpython-38.pyc index 047799d7d..fcd858fe1 100644 Binary files a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/tools/__pycache__/argsparser.cpython-38.pyc and b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/tools/__pycache__/argsparser.cpython-38.pyc differ diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/tools/__pycache__/staged_train_callback.cpython-38.pyc b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/tools/__pycache__/staged_train_callback.cpython-38.pyc index 3151cf5ed..69e95e7db 100644 Binary files a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/tools/__pycache__/staged_train_callback.cpython-38.pyc and b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/tools/__pycache__/staged_train_callback.cpython-38.pyc differ diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/tools/argsparser.py b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/tools/argsparser.py index 2d1860112..1abe17a76 100644 --- a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/tools/argsparser.py +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/tools/argsparser.py @@ -7,59 +7,79 @@ def training_args(parser): """program arguments training script""" - parser.add_argument( - "--n_envs", type=int, default=1, help="number of parallel environments" - ) - parser.add_argument( - "--no-gpu", action="store_true", help="disables gpu for training" - ) - parser.add_argument( - "--debug", - action="store_true", - help="disables multiprocessing in order to debug", - ) - group = parser.add_mutually_exclusive_group(required=True) - - import rl_agent.model.custom_policy - import rl_agent.model.custom_sb3_policy - from rl_agent.model.agent_factory import AgentFactory - - group.add_argument( - "--agent", - type=str, - choices=AgentFactory.registry.keys(), - help="predefined agent to train", - ) - group.add_argument( - "--custom-mlp", - action="store_true", - help="enables training with custom multilayer perceptron", - ) - group.add_argument( - "--load", - type=str, - metavar="[agent name]", - help="agent to be loaded for training", - ) parser.add_argument( "--config", type=str, metavar="[config name]", - default="default", - help="name of the json file containing" "the hyperparameters", - ) - parser.add_argument( - "--n", type=int, help="timesteps in total to be generated for training" - ) - parser.add_argument( - "-log", - "--eval_log", - action="store_true", - help="enables storage of evaluation data", - ) - parser.add_argument( - "--tb", action="store_true", help="enables tensorboard logging" - ) + default="training_config.yaml", + help="name of the config file", + ) + + ########################################################################### + + # parser.add_argument( + # "--n_envs", type=int, default=1, help="number of parallel environments" + # ) + # parser.add_argument( + # "--no-gpu", action="store_true", help="disables gpu for training" + # ) + # parser.add_argument( + # "--debug", + # action="store_true", + # help="disables multiprocessing in order to debug", + # ) + # group = parser.add_mutually_exclusive_group(required=True) + + # import rl_agent.model.custom_policy + # import rl_agent.model.custom_sb3_policy + # from rl_agent.model.agent_factory import AgentFactory + + # group.add_argument( + # "--agent", + # type=str, + # choices=AgentFactory.registry.keys(), + # help="predefined agent to train", + # ) + # group.add_argument( + # "--custom-mlp", + # action="store_true", + # help="enables training with custom multilayer perceptron", + # ) + # group.add_argument( + # "--load", + # type=str, + # metavar="[agent name]", + # help="agent to be loaded for training", + # ) + # parser.add_argument( + # "--config", + # type=str, + # metavar="[config name]", + # default="default", + # help="name of the json file containing" "the hyperparameters", + # ) + # parser.add_argument( + # "--n", type=int, help="timesteps in total to be generated for training" + # ) + # parser.add_argument( + # "-log", + # "--eval_log", + # action="store_true", + # help="enables storage of evaluation data", + # ) + # parser.add_argument("--tb", action="store_true", help="enables tensorboard logging") + + +# def marl_training_args(parser): +# parser.add_argument("--robots", type=int, default=1, help="number of robots") + + +# def parse_marl_training_args(args=None, ignore_unknown=False): +# """parser for training script""" +# arg_populate_funcs = [training_args, custom_mlp_args, marl_training_args] +# arg_check_funcs = [process_training_args] + +# return parse_various_args(args, arg_populate_funcs, arg_check_funcs, ignore_unknown) def run_agent_args(parser): @@ -143,21 +163,17 @@ def custom_mlp_args(parser): def process_training_args(parsed_args): """argument check function""" - if parsed_args.no_gpu: - os.environ["CUDA_VISIBLE_DEVICES"] = "-1" - if parsed_args.custom_mlp: - setattr(parsed_args, "net_arch", get_net_arch(parsed_args)) - else: - if ( - parsed_args.body != "" - or parsed_args.pi != "" - or parsed_args.vf != "" - ): - print("[custom mlp] arguments will be ignored..") - delattr(parsed_args, "body") - delattr(parsed_args, "pi") - delattr(parsed_args, "vf") - delattr(parsed_args, "act_fn") + # if parsed_args.no_gpu: + # os.environ["CUDA_VISIBLE_DEVICES"] = "-1" + # if parsed_args.custom_mlp: + # setattr(parsed_args, "net_arch", get_net_arch(parsed_args)) + # else: + # if parsed_args.body != "" or parsed_args.pi != "" or parsed_args.vf != "": + # print("[custom mlp] arguments will be ignored..") + # delattr(parsed_args, "body") + # delattr(parsed_args, "pi") + # delattr(parsed_args, "vf") + # delattr(parsed_args, "act_fn") def process_run_agent_args(parsed_args): @@ -170,9 +186,7 @@ def parse_training_args(args=None, ignore_unknown=False): arg_populate_funcs = [training_args, custom_mlp_args] arg_check_funcs = [process_training_args] - return parse_various_args( - args, arg_populate_funcs, arg_check_funcs, ignore_unknown - ) + return parse_various_args(args, arg_populate_funcs, arg_check_funcs, ignore_unknown) def parse_run_agent_args(args=None, ignore_unknown=False): @@ -180,14 +194,10 @@ def parse_run_agent_args(args=None, ignore_unknown=False): arg_populate_funcs = [run_agent_args] arg_check_funcs = [process_run_agent_args] - return parse_various_args( - args, arg_populate_funcs, arg_check_funcs, ignore_unknown - ) + return parse_various_args(args, arg_populate_funcs, arg_check_funcs, ignore_unknown) -def parse_various_args( - args, arg_populate_funcs, arg_check_funcs, ignore_unknown -): +def parse_various_args(args, arg_populate_funcs, arg_check_funcs, ignore_unknown): """generic arg parsing function""" parser = argparse.ArgumentParser() diff --git a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/tools/train_agent_utils.py b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/tools/train_agent_utils.py index 74c2af519..c7ae5a533 100644 --- a/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/tools/train_agent_utils.py +++ b/arena_navigation/arena_local_planner/learning_based/arena_local_planner_drl/tools/train_agent_utils.py @@ -5,6 +5,8 @@ import gym import json import os, rospy + +import yaml import rosnode import rospkg import time @@ -83,6 +85,21 @@ } +def load_config(config_name: str) -> dict: + """ + Load config parameters from config file + """ + config_location = os.path.join( + rospkg.RosPack().get_path("arena_local_planner_drl"), + "configs", + config_name + ".yaml", + ) + with open(config_location, "r", encoding="utf-8") as target: + config = yaml.load(target, Loader=yaml.FullLoader) + + return config + + def initialize_hyperparameters( PATHS: dict, load_target: str, config_name: str = "default", n_envs: int = 1 ) -> dict: @@ -117,9 +134,7 @@ def initialize_hyperparameters( # dynamically adapt n_steps according to batch size and n envs # then update .json - check_batch_size( - n_envs, hyperparams["batch_size"], hyperparams["m_batch_size"] - ) + check_batch_size(n_envs, hyperparams["batch_size"], hyperparams["m_batch_size"]) hyperparams["n_steps"] = int(hyperparams["batch_size"] / n_envs) write_hyperparameters_json(hyperparams, PATHS) print_hyperparameters(hyperparams) @@ -151,9 +166,7 @@ def load_hyperparameters_json( :param config_name: file name of json file when training from scratch """ if from_scratch: - doc_location = os.path.join( - PATHS.get("hyperparams"), config_name + ".json" - ) + doc_location = os.path.join(PATHS.get("hyperparams"), config_name + ".json") else: doc_location = os.path.join(PATHS.get("model"), "hyperparameters.json") @@ -165,8 +178,7 @@ def load_hyperparameters_json( else: if from_scratch: raise FileNotFoundError( - "Found no '%s.json' in %s" - % (config_name, PATHS.get("hyperparams")) + "Found no '%s.json' in %s" % (config_name, PATHS.get("hyperparams")) ) else: raise FileNotFoundError( @@ -230,9 +242,7 @@ def check_hyperparam_format(loaded_hyperparams: dict, PATHS: dict) -> None: "actions_in_observationspace" in loaded_hyperparams and type(loaded_hyperparams["actions_in_observationspace"]) is not bool ): - raise TypeError( - "Parameter 'actions_in_observationspace' has to be a boolean!" - ) + raise TypeError("Parameter 'actions_in_observationspace' has to be a boolean!") def update_hyperparam_model( @@ -336,9 +346,7 @@ def get_paths(agent_name: str, args: argparse.Namespace) -> dict: PATHS = { "model": os.path.join(dir, "agents", agent_name), "tb": os.path.join(dir, "training_logs", "tensorboard", agent_name), - "eval": os.path.join( - dir, "training_logs", "train_eval_log", agent_name - ), + "eval": os.path.join(dir, "training_logs", "train_eval_log", agent_name), "robot_setting": os.path.join( rospkg.RosPack().get_path("simulator_setup"), "robot", @@ -346,10 +354,10 @@ def get_paths(agent_name: str, args: argparse.Namespace) -> dict: ), "hyperparams": os.path.join(dir, "configs", "hyperparameters"), "robot_as": os.path.join( - dir, "configs", f"default_settings_{robot_model}.yaml" + dir, "configs", "action_spaces", f"default_settings_{robot_model}.yaml" ), "curriculum": os.path.join( - dir, "configs", "training_curriculum_map1small.yaml" + dir, "configs", "training_curriculums", "training_curriculum_map1small.yaml" ), } # check for mode @@ -485,9 +493,7 @@ def wait_for_nodes( from stable_baselines3.common.vec_env.base_vec_env import VecEnv -def load_vec_normalize( - params: dict, PATHS: dict, env: VecEnv, eval_env: VecEnv -): +def load_vec_normalize(params: dict, PATHS: dict, env: VecEnv, eval_env: VecEnv): if params["normalize"]: load_path = os.path.join(PATHS["model"], "vec_normalize.pkl") if os.path.isfile(load_path): diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 000000000..3ebb20867 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,3024 @@ +[[package]] +name = "absl-py" +version = "1.0.0" +description = "Abseil Python Common Libraries, see https://github.com/abseil/abseil-py." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +six = "*" + +[[package]] +name = "actionlib" +version = "1.12.0" +description = "The actionlib stack provides a standardized interface for interfacing with preemptable tasks. Examples of this include moving the base to a target location, performing a laser scan and retu..." +category = "main" +optional = false +python-versions = "*" + +[package.source] +type = "legacy" +url = "https://rospypi.github.io/simple" +reference = "ros" + +[[package]] +name = "actionlib-msgs" +version = "1.13.0.post3" +description = "" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +genpy = ">=0.6.14,<2000" + +[package.source] +type = "legacy" +url = "https://rospypi.github.io/simple" +reference = "ros" + +[[package]] +name = "appnope" +version = "0.1.2" +description = "Disable App Nap on macOS >= 10.9" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "argon2-cffi" +version = "21.1.0" +description = "The secure Argon2 password hashing algorithm." +category = "main" +optional = false +python-versions = ">=3.5" + +[package.dependencies] +cffi = ">=1.0.0" + +[package.extras] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pytest", "sphinx", "furo", "wheel", "pre-commit"] +docs = ["sphinx", "furo"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pytest"] + +[[package]] +name = "attrs" +version = "21.2.0" +description = "Classes Without Boilerplate" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.extras] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] +docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] + +[[package]] +name = "backcall" +version = "0.2.0" +description = "Specifications for callback functions passed in to an API" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "black" +version = "22.3.0" +description = "The uncompromising code formatter." +category = "dev" +optional = false +python-versions = ">=3.6.2" + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "bleach" +version = "4.1.0" +description = "An easy safelist-based HTML-sanitizing tool." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +packaging = "*" +six = ">=1.9.0" +webencodings = "*" + +[[package]] +name = "cachetools" +version = "4.2.4" +description = "Extensible memoizing collections and decorators" +category = "main" +optional = false +python-versions = "~=3.5" + +[[package]] +name = "catkin" +version = "0.7.18" +description = "Low-level build system macros and infrastructure for ROS." +category = "main" +optional = false +python-versions = "*" + +[package.source] +type = "legacy" +url = "https://rospypi.github.io/simple" +reference = "ros" + +[[package]] +name = "catkin-pkg" +version = "0.4.24" +description = "catkin package library" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +docutils = "*" +pyparsing = "*" +python-dateutil = "*" + +[[package]] +name = "certifi" +version = "2021.10.8" +description = "Python package for providing Mozilla's CA Bundle." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "cffi" +version = "1.15.0" +description = "Foreign Function Interface for Python calling C code." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "charset-normalizer" +version = "2.0.7" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" +optional = false +python-versions = ">=3.5.0" + +[package.extras] +unicode_backport = ["unicodedata2"] + +[[package]] +name = "click" +version = "8.1.3" +description = "Composable command line interface toolkit" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "cloudpickle" +version = "2.0.0" +description = "Extended pickling support for Python objects" +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "colorama" +version = "0.4.4" +description = "Cross-platform colored terminal text." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "cycler" +version = "0.11.0" +description = "Composable style cycles" +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "debugpy" +version = "1.5.1" +description = "An implementation of the Debug Adapter Protocol for Python" +category = "main" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" + +[[package]] +name = "decorator" +version = "5.1.0" +description = "Decorators for Humans" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "defusedxml" +version = "0.7.1" +description = "XML bomb protection for Python stdlib modules" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "distro" +version = "1.6.0" +description = "Distro - an OS platform information API" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "docutils" +version = "0.18" +description = "Docutils -- Python Documentation Utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "empy" +version = "3.3.4" +description = "A templating system for Python." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "entrypoints" +version = "0.3" +description = "Discover and load entry points from installed packages." +category = "main" +optional = false +python-versions = ">=2.7" + +[[package]] +name = "filelock" +version = "3.3.2" +description = "A platform independent file lock." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"] +testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-cov", "pytest-timeout (>=1.4.2)"] + +[[package]] +name = "genmsg" +version = "0.5.12" +description = "Standalone Python library for generating ROS message and service data structures for various languages." +category = "main" +optional = false +python-versions = "*" + +[package.source] +type = "legacy" +url = "https://rospypi.github.io/simple" +reference = "ros" + +[[package]] +name = "genpy" +version = "0.6.14" +description = "Python ROS message and service generators." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +genmsg = "*" + +[package.source] +type = "legacy" +url = "https://rospypi.github.io/simple" +reference = "ros" + +[[package]] +name = "geometry-msgs" +version = "1.13.0.post2" +description = "" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +genpy = ">=0.6.14,<2000" + +[package.source] +type = "legacy" +url = "https://rospypi.github.io/simple" +reference = "ros" + +[[package]] +name = "gnupg" +version = "2.3.1" +description = "A Python wrapper for GnuPG" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +psutil = ">=1.2.1" + +[package.extras] +docs = ["Sphinx (>=1.1)", "sphinxcontrib-fulltoc (==1.0)"] + +[[package]] +name = "google-auth" +version = "2.3.3" +description = "Google Authentication Library" +category = "main" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*" + +[package.dependencies] +cachetools = ">=2.0.0,<5.0" +pyasn1-modules = ">=0.2.1" +rsa = {version = ">=3.1.4,<5", markers = "python_version >= \"3.6\""} +six = ">=1.9.0" + +[package.extras] +aiohttp = ["requests (>=2.20.0,<3.0.0dev)", "aiohttp (>=3.6.2,<4.0.0dev)"] +pyopenssl = ["pyopenssl (>=20.0.0)"] +reauth = ["pyu2f (>=0.1.5)"] + +[[package]] +name = "google-auth-oauthlib" +version = "0.4.6" +description = "Google Authentication Library" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +google-auth = ">=1.0.0" +requests-oauthlib = ">=0.7.0" + +[package.extras] +tool = ["click (>=6.0.0)"] + +[[package]] +name = "grpcio" +version = "1.41.1" +description = "HTTP/2-based RPC framework" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +six = ">=1.5.2" + +[package.extras] +protobuf = ["grpcio-tools (>=1.41.1)"] + +[[package]] +name = "gym" +version = "0.21.0" +description = "Gym: A universal API for reinforcement learning environments." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +cloudpickle = ">=1.2.0" +numpy = ">=1.18.0" + +[package.extras] +accept-rom-license = ["autorom[accept-rom-license] (>=0.4.2,<0.5.0)"] +all = ["mujoco_py (>=1.50,<2.0)", "lz4 (>=3.1.0)", "opencv-python (>=3)", "ale-py (>=0.7.1,<0.8.0)", "pyglet (>=1.4.0)", "scipy (>=1.4.1)", "box2d-py (==2.3.5)", "pyglet (>=1.4.0)", "ale-py (>=0.7.1,<0.8.0)", "lz4 (>=3.1.0)", "opencv-python (>=3)", "pyglet (>=1.4.0)", "box2d-py (==2.3.5)", "pyglet (>=1.4.0)", "scipy (>=1.4.1)", "mujoco_py (>=1.50,<2.0)"] +atari = ["ale-py (>=0.7.1,<0.8.0)"] +box2d = ["box2d-py (==2.3.5)", "pyglet (>=1.4.0)"] +classic_control = ["pyglet (>=1.4.0)"] +mujoco = ["mujoco_py (>=1.50,<2.0)"] +nomujoco = ["lz4 (>=3.1.0)", "opencv-python (>=3)", "ale-py (>=0.7.1,<0.8.0)", "pyglet (>=1.4.0)", "scipy (>=1.4.1)", "box2d-py (==2.3.5)", "pyglet (>=1.4.0)"] +other = ["lz4 (>=3.1.0)", "opencv-python (>=3)"] +robotics = ["mujoco_py (>=1.50,<2.0)"] +toy_text = ["scipy (>=1.4.1)"] + +[[package]] +name = "idna" +version = "3.3" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "importlib-resources" +version = "5.4.0" +description = "Read resources from Python packages" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-black (>=0.3.7)", "pytest-mypy"] + +[[package]] +name = "ipykernel" +version = "6.5.0" +description = "IPython Kernel for Jupyter" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +appnope = {version = "*", markers = "platform_system == \"Darwin\""} +debugpy = ">=1.0.0,<2.0" +ipython = ">=7.23.1,<8.0" +jupyter-client = "<8.0" +matplotlib-inline = ">=0.1.0,<0.2.0" +tornado = ">=4.2,<7.0" +traitlets = ">=5.1.0,<6.0" + +[package.extras] +test = ["pytest (!=5.3.4)", "pytest-cov", "flaky", "nose", "ipyparallel"] + +[[package]] +name = "ipython" +version = "7.29.0" +description = "IPython: Productive Interactive Computing" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +appnope = {version = "*", markers = "sys_platform == \"darwin\""} +backcall = "*" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +decorator = "*" +jedi = ">=0.16" +matplotlib-inline = "*" +pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} +pickleshare = "*" +prompt-toolkit = ">=2.0.0,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.1.0" +pygments = "*" +traitlets = ">=4.2" + +[package.extras] +all = ["Sphinx (>=1.3)", "ipykernel", "ipyparallel", "ipywidgets", "nbconvert", "nbformat", "nose (>=0.10.1)", "notebook", "numpy (>=1.17)", "pygments", "qtconsole", "requests", "testpath"] +doc = ["Sphinx (>=1.3)"] +kernel = ["ipykernel"] +nbconvert = ["nbconvert"] +nbformat = ["nbformat"] +notebook = ["notebook", "ipywidgets"] +parallel = ["ipyparallel"] +qtconsole = ["qtconsole"] +test = ["nose (>=0.10.1)", "requests", "testpath", "pygments", "nbformat", "ipykernel", "numpy (>=1.17)"] + +[[package]] +name = "ipython-genutils" +version = "0.2.0" +description = "Vestigial utilities from IPython" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "ipywidgets" +version = "7.6.5" +description = "IPython HTML widgets for Jupyter" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +ipykernel = ">=4.5.1" +ipython = {version = ">=4.0.0", markers = "python_version >= \"3.3\""} +ipython-genutils = ">=0.2.0,<0.3.0" +jupyterlab-widgets = {version = ">=1.0.0", markers = "python_version >= \"3.6\""} +nbformat = ">=4.2.0" +traitlets = ">=4.3.1" +widgetsnbextension = ">=3.5.0,<3.6.0" + +[package.extras] +test = ["pytest (>=3.6.0)", "pytest-cov", "mock"] + +[[package]] +name = "jedi" +version = "0.18.0" +description = "An autocompletion tool for Python that can be used for text editors." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +parso = ">=0.8.0,<0.9.0" + +[package.extras] +qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] +testing = ["Django (<3.1)", "colorama", "docopt", "pytest (<6.0.0)"] + +[[package]] +name = "jinja2" +version = "3.0.3" +description = "A very fast and expressive template engine." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "jsonschema" +version = "4.2.1" +description = "An implementation of JSON Schema validation for Python" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +attrs = ">=17.4.0" +importlib-resources = {version = ">=1.4.0", markers = "python_version < \"3.9\""} +pyrsistent = ">=0.14.0,<0.17.0 || >0.17.0,<0.17.1 || >0.17.1,<0.17.2 || >0.17.2" + +[package.extras] +format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] +format_nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] + +[[package]] +name = "jupyter" +version = "1.0.0" +description = "Jupyter metapackage. Install all the Jupyter components in one go." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +ipykernel = "*" +ipywidgets = "*" +jupyter-console = "*" +nbconvert = "*" +notebook = "*" +qtconsole = "*" + +[[package]] +name = "jupyter-client" +version = "7.0.6" +description = "Jupyter protocol implementation and client libraries" +category = "main" +optional = false +python-versions = ">=3.6.1" + +[package.dependencies] +entrypoints = "*" +jupyter-core = ">=4.6.0" +nest-asyncio = ">=1.5" +python-dateutil = ">=2.1" +pyzmq = ">=13" +tornado = ">=4.1" +traitlets = "*" + +[package.extras] +doc = ["myst-parser", "sphinx (>=1.3.6)", "sphinx-rtd-theme", "sphinxcontrib-github-alt"] +test = ["codecov", "coverage", "ipykernel", "ipython", "mock", "mypy", "pre-commit", "pytest", "pytest-asyncio", "pytest-cov", "pytest-timeout", "jedi (<0.18)"] + +[[package]] +name = "jupyter-console" +version = "6.4.0" +description = "Jupyter terminal console" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +ipykernel = "*" +ipython = "*" +jupyter-client = "*" +prompt-toolkit = ">=2.0.0,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.1.0" +pygments = "*" + +[package.extras] +test = ["pexpect"] + +[[package]] +name = "jupyter-core" +version = "4.9.1" +description = "Jupyter core package. A base package on which Jupyter projects rely." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pywin32 = {version = ">=1.0", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""} +traitlets = "*" + +[[package]] +name = "jupyterlab-pygments" +version = "0.1.2" +description = "Pygments theme using JupyterLab CSS variables" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +pygments = ">=2.4.1,<3" + +[[package]] +name = "jupyterlab-widgets" +version = "1.0.2" +description = "A JupyterLab extension." +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "kiwisolver" +version = "1.3.2" +description = "A fast implementation of the Cassowary constraint solver" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "mako" +version = "1.1.5" +description = "A super-fast templating language that borrows the best ideas from the existing templating languages." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.dependencies] +MarkupSafe = ">=0.9.2" + +[package.extras] +babel = ["babel"] +lingua = ["lingua"] + +[[package]] +name = "markdown" +version = "3.3.4" +description = "Python implementation of Markdown." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +testing = ["coverage", "pyyaml"] + +[[package]] +name = "markupsafe" +version = "2.0.1" +description = "Safely add untrusted strings to HTML/XML markup." +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "matplotlib" +version = "3.4.3" +description = "Python plotting package" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +cycler = ">=0.10" +kiwisolver = ">=1.0.1" +numpy = ">=1.16" +pillow = ">=6.2.0" +pyparsing = ">=2.2.1" +python-dateutil = ">=2.7" + +[[package]] +name = "matplotlib-inline" +version = "0.1.3" +description = "Inline Matplotlib backend for Jupyter" +category = "main" +optional = false +python-versions = ">=3.5" + +[package.dependencies] +traitlets = "*" + +[[package]] +name = "mistune" +version = "0.8.4" +description = "The fastest markdown parser in pure Python" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "mypy-extensions" +version = "0.4.3" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "nbclient" +version = "0.5.8" +description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." +category = "main" +optional = false +python-versions = ">=3.6.1" + +[package.dependencies] +jupyter-client = ">=6.1.5" +nbformat = ">=5.0" +nest-asyncio = "*" +traitlets = ">=4.2" + +[package.extras] +dev = ["codecov", "coverage", "ipython", "ipykernel", "ipywidgets", "pytest (>=4.1)", "pytest-cov (>=2.6.1)", "check-manifest", "flake8", "mypy", "tox", "xmltodict", "pip (>=18.1)", "wheel (>=0.31.0)", "setuptools (>=38.6.0)", "twine (>=1.11.0)", "black"] +sphinx = ["Sphinx (>=1.7)", "sphinx-book-theme", "mock", "moto", "myst-parser"] +test = ["codecov", "coverage", "ipython", "ipykernel", "ipywidgets", "pytest (>=4.1)", "pytest-cov (>=2.6.1)", "check-manifest", "flake8", "mypy", "tox", "xmltodict", "pip (>=18.1)", "wheel (>=0.31.0)", "setuptools (>=38.6.0)", "twine (>=1.11.0)", "black"] + +[[package]] +name = "nbconvert" +version = "6.3.0" +description = "Converting Jupyter Notebooks" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +bleach = "*" +defusedxml = "*" +entrypoints = ">=0.2.2" +jinja2 = ">=2.4" +jupyter-core = "*" +jupyterlab-pygments = "*" +mistune = ">=0.8.1,<2" +nbclient = ">=0.5.0,<0.6.0" +nbformat = ">=4.4" +pandocfilters = ">=1.4.1" +pygments = ">=2.4.1" +testpath = "*" +traitlets = ">=5.0" + +[package.extras] +all = ["pytest", "pytest-cov", "pytest-dependency", "ipykernel", "ipywidgets (>=7)", "pyppeteer (==0.2.6)", "tornado (>=4.0)", "sphinx (>=1.5.1)", "sphinx-rtd-theme", "nbsphinx (>=0.2.12)", "ipython"] +docs = ["sphinx (>=1.5.1)", "sphinx-rtd-theme", "nbsphinx (>=0.2.12)", "ipython"] +serve = ["tornado (>=4.0)"] +test = ["pytest", "pytest-cov", "pytest-dependency", "ipykernel", "ipywidgets (>=7)", "pyppeteer (==0.2.6)"] +webpdf = ["pyppeteer (==0.2.6)"] + +[[package]] +name = "nbformat" +version = "5.1.3" +description = "The Jupyter Notebook format" +category = "main" +optional = false +python-versions = ">=3.5" + +[package.dependencies] +ipython-genutils = "*" +jsonschema = ">=2.4,<2.5.0 || >2.5.0" +jupyter-core = "*" +traitlets = ">=4.1" + +[package.extras] +fast = ["fastjsonschema"] +test = ["check-manifest", "fastjsonschema", "testpath", "pytest", "pytest-cov"] + +[[package]] +name = "nest-asyncio" +version = "1.5.1" +description = "Patch asyncio to allow nested event loops" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "netifaces" +version = "0.10.9" +description = "Portable network interface information." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "notebook" +version = "6.4.5" +description = "A web-based notebook environment for interactive computing" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +argon2-cffi = "*" +ipykernel = "*" +ipython-genutils = "*" +jinja2 = "*" +jupyter-client = ">=5.3.4" +jupyter-core = ">=4.6.1" +nbconvert = "*" +nbformat = "*" +prometheus-client = "*" +pyzmq = ">=17" +Send2Trash = ">=1.5.0" +terminado = ">=0.8.3" +tornado = ">=6.1" +traitlets = ">=4.2.1" + +[package.extras] +docs = ["sphinx", "nbsphinx", "sphinxcontrib-github-alt", "sphinx-rtd-theme", "myst-parser"] +json-logging = ["json-logging"] +test = ["pytest", "coverage", "requests", "nbval", "selenium", "pytest-cov", "requests-unixsocket"] + +[[package]] +name = "numpy" +version = "1.21.4" +description = "NumPy is the fundamental package for array computing with Python." +category = "main" +optional = false +python-versions = ">=3.7,<3.11" + +[[package]] +name = "oauthlib" +version = "3.1.1" +description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +rsa = ["cryptography (>=3.0.0,<4)"] +signals = ["blinker (>=1.4.0)"] +signedtoken = ["cryptography (>=3.0.0,<4)", "pyjwt (>=2.0.0,<3)"] + +[[package]] +name = "opencv-python" +version = "3.4.16.57" +description = "Wrapper package for OpenCV python bindings." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +numpy = ">=1.21.2" + +[[package]] +name = "packaging" +version = "21.0" +description = "Core utilities for Python packages" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pyparsing = ">=2.0.2" + +[[package]] +name = "pandas" +version = "1.3.4" +description = "Powerful data structures for data analysis, time series, and statistics" +category = "main" +optional = false +python-versions = ">=3.7.1" + +[package.dependencies] +numpy = [ + {version = ">=1.17.3", markers = "platform_machine != \"aarch64\" and platform_machine != \"arm64\" and python_version < \"3.10\""}, + {version = ">=1.19.2", markers = "platform_machine == \"aarch64\" and python_version < \"3.10\""}, + {version = ">=1.20.0", markers = "platform_machine == \"arm64\" and python_version < \"3.10\""}, +] +python-dateutil = ">=2.7.3" +pytz = ">=2017.3" + +[package.extras] +test = ["hypothesis (>=3.58)", "pytest (>=6.0)", "pytest-xdist"] + +[[package]] +name = "pandocfilters" +version = "1.5.0" +description = "Utilities for writing pandoc filters in python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "parso" +version = "0.8.2" +description = "A Python Parser" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] +testing = ["docopt", "pytest (<6.0.0)"] + +[[package]] +name = "pathlib" +version = "1.0.1" +description = "Object-oriented filesystem paths" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pathspec" +version = "0.9.0" +description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + +[[package]] +name = "pdoc3" +version = "0.10.0" +description = "Auto-generate API documentation for Python projects." +category = "dev" +optional = false +python-versions = ">= 3.6" + +[package.dependencies] +mako = "*" +markdown = ">=3.0" + +[[package]] +name = "pettingzoo" +version = "1.13.1" +description = "Gym for multi-agent reinforcement learning" +category = "main" +optional = false +python-versions = ">=3.7, <3.10" + +[package.dependencies] +gym = ">=0.21.0" +numpy = ">=1.18.0" + +[package.extras] +all = ["multi_agent_ale_py (==0.1.11)", "pygame (==2.0.0)", "chess (==1.7.0)", "rlcard (==1.0.4)", "pygame (==2.0.0)", "hanabi_learning_environment (==0.0.1)", "pygame (==2.0.0)", "pymunk (==6.2.0)", "magent (==0.1.14)", "pyglet (>=1.4.0)", "pygame (==2.0.0)", "box2d-py (==2.3.5)", "pyglet (>=1.4.0)", "scipy (>=1.4.1)", "pillow (>=8.0.1)"] +atari = ["multi_agent_ale_py (==0.1.11)", "pygame (==2.0.0)"] +butterfly = ["pygame (==2.0.0)", "pymunk (==6.2.0)"] +classic = ["chess (==1.7.0)", "rlcard (==1.0.4)", "pygame (==2.0.0)", "hanabi_learning_environment (==0.0.1)"] +magent = ["magent (==0.1.14)"] +mpe = ["pyglet (>=1.4.0)"] +other = ["pillow (>=8.0.1)"] +sisl = ["pygame (==2.0.0)", "box2d-py (==2.3.5)", "pyglet (>=1.4.0)", "scipy (>=1.4.1)"] +tests = ["pynput"] + +[[package]] +name = "pexpect" +version = "4.8.0" +description = "Pexpect allows easy control of interactive console applications." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +ptyprocess = ">=0.5" + +[[package]] +name = "pickleshare" +version = "0.7.5" +description = "Tiny 'shelve'-like database with concurrency support" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pillow" +version = "8.4.0" +description = "Python Imaging Library (Fork)" +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "platformdirs" +version = "2.5.2" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.extras] +docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"] +test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"] + +[[package]] +name = "prometheus-client" +version = "0.12.0" +description = "Python client for the Prometheus monitoring system." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.extras] +twisted = ["twisted"] + +[[package]] +name = "prompt-toolkit" +version = "3.0.22" +description = "Library for building powerful interactive command lines in Python" +category = "main" +optional = false +python-versions = ">=3.6.2" + +[package.dependencies] +wcwidth = "*" + +[[package]] +name = "protobuf" +version = "3.19.1" +description = "Protocol Buffers" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "psutil" +version = "5.8.0" +description = "Cross-platform lib for process and system monitoring in Python." +category = "main" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.extras] +test = ["ipaddress", "mock", "unittest2", "enum34", "pywin32", "wmi"] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +description = "Run a subprocess in a pseudo terminal" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "py" +version = "1.11.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "pyasn1" +version = "0.4.8" +description = "ASN.1 types and codecs" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pyasn1-modules" +version = "0.2.8" +description = "A collection of ASN.1-based protocols modules." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +pyasn1 = ">=0.4.6,<0.5.0" + +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pycryptodome" +version = "3.11.0" +description = "Cryptographic library for Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "pycryptodomex" +version = "3.11.0" +description = "Cryptographic library for Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "pygments" +version = "2.10.0" +description = "Pygments is a syntax highlighting package written in Python." +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "pyparsing" +version = "3.0.5" +description = "Python parsing module" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + +[[package]] +name = "pyqt5" +version = "5.15.6" +description = "Python bindings for the Qt cross platform application toolkit" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +PyQt5-Qt5 = ">=5.15.2" +PyQt5-sip = ">=12.8,<13" + +[[package]] +name = "pyqt5-qt5" +version = "5.15.2" +description = "The subset of a Qt installation needed by PyQt5." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pyqt5-sip" +version = "12.9.0" +description = "The sip module support for PyQt5" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "pyrsistent" +version = "0.18.0" +description = "Persistent/Functional/Immutable data structures" +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pytz" +version = "2021.3" +description = "World timezone definitions, modern and historical" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pywin32" +version = "302" +description = "Python for Window Extensions" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pywinpty" +version = "1.1.5" +description = "Pseudo terminal support for Windows from Python." +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "pyyaml" +version = "5.4.1" +description = "YAML parser and emitter for Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[[package]] +name = "pyzmq" +version = "22.3.0" +description = "Python bindings for 0MQ" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +cffi = {version = "*", markers = "implementation_name == \"pypy\""} +py = {version = "*", markers = "implementation_name == \"pypy\""} + +[[package]] +name = "qtconsole" +version = "5.2.0" +description = "Jupyter Qt console" +category = "main" +optional = false +python-versions = ">= 3.6" + +[package.dependencies] +ipykernel = ">=4.1" +ipython-genutils = "*" +jupyter-client = ">=4.1" +jupyter-core = "*" +pygments = "*" +pyzmq = ">=17.1" +qtpy = "*" +traitlets = "*" + +[package.extras] +doc = ["Sphinx (>=1.3)"] +test = ["flaky", "pytest", "pytest-qt"] + +[[package]] +name = "qtpy" +version = "1.11.2" +description = "Provides an abstraction layer on top of the various Qt bindings (PyQt5, PyQt4 and PySide) and additional custom QWidgets." +category = "main" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*" + +[[package]] +name = "requests" +version = "2.26.0" +description = "Python HTTP for Humans." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} +idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} +urllib3 = ">=1.21.1,<1.27" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] + +[[package]] +name = "requests-oauthlib" +version = "1.3.0" +description = "OAuthlib authentication support for Requests." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.dependencies] +oauthlib = ">=3.0.0" +requests = ">=2.0.0" + +[package.extras] +rsa = ["oauthlib[signedtoken] (>=3.0.0)"] + +[[package]] +name = "rosbag" +version = "1.15.11" +description = "This is a set of tools for recording from and playing back to ROS topics. It is intended to be high performance and avoids deserialization and reserialization of the messages." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +genmsg = "*" +genpy = "<2000" +gnupg = "*" +pycryptodome = "*" +pycryptodomex = "*" +roslib = "*" +rospkg = "*" +rospy = "*" + +[package.source] +type = "legacy" +url = "https://rospypi.github.io/simple" +reference = "ros" + +[[package]] +name = "roscpp" +version = "1.15.11" +description = "" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +genpy = ">=0.6.14,<2000" + +[package.source] +type = "legacy" +url = "https://rospypi.github.io/simple" +reference = "ros" + +[[package]] +name = "rosgraph" +version = "1.15.11" +description = "rosgraph contains the rosgraph command-line tool, which prints information about the ROS Computation Graph. It also provides an internal library that can be used by graphical tools." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +rospkg = "*" + +[package.source] +type = "legacy" +url = "https://rospypi.github.io/simple" +reference = "ros" + +[[package]] +name = "rosgraph-msgs" +version = "1.11.3.post2" +description = "" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +genpy = ">=0.6.14,<2000" + +[package.source] +type = "legacy" +url = "https://rospypi.github.io/simple" +reference = "ros" + +[[package]] +name = "roslib" +version = "1.14.7.post0" +description = "Base dependencies and support libraries for ROS. roslib contains many of the common data structures and tools that are shared across ROS client library implementations." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +catkin = "*" +rospkg = "*" + +[package.source] +type = "legacy" +url = "https://rospypi.github.io/simple" +reference = "ros" + +[[package]] +name = "rospkg" +version = "1.3.0" +description = "ROS package library" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +catkin-pkg = "*" +distro = "*" +PyYAML = "*" + +[[package]] +name = "rospy" +version = "1.15.11" +description = "rospy is a pure Python client library for ROS. The rospy client API enables Python programmers to quickly interface with ROS Topics, =0.2.0,<0.3.0)", "pillow", "tensorboard (>=2.2.0)", "psutil"] +tests = ["pytest", "pytest-cov", "pytest-env", "pytest-xdist", "pytype", "flake8 (>=3.8)", "flake8-bugbear", "isort (>=5.0)", "black"] + +[package.source] +type = "git" +url = "https://github.com/ignc-research/stable-baselines3" +reference = "marl" +resolved_reference = "323a3730f2cc6674332f47f8ae7bb5094a1909ed" + +[[package]] +name = "std-msgs" +version = "0.5.13.post0" +description = "" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +genpy = ">=0.6.14,<2000" + +[package.source] +type = "legacy" +url = "https://rospypi.github.io/simple" +reference = "ros" + +[[package]] +name = "supersuit" +version = "3.3.1" +description = "Wrappers for Gym and PettingZoo" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +opencv-python = ">=3.4.0,<3.5.0" +pettingzoo = ">=1.13.1" + +[[package]] +name = "tensorboard" +version = "2.7.0" +description = "TensorBoard lets you watch Tensors Flow" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +absl-py = ">=0.4" +google-auth = ">=1.6.3,<3" +google-auth-oauthlib = ">=0.4.1,<0.5" +grpcio = ">=1.24.3" +markdown = ">=2.6.8" +numpy = ">=1.12.0" +protobuf = ">=3.6.0" +requests = ">=2.21.0,<3" +tensorboard-data-server = ">=0.6.0,<0.7.0" +tensorboard-plugin-wit = ">=1.6.0" +werkzeug = ">=0.11.15" + +[[package]] +name = "tensorboard-data-server" +version = "0.6.1" +description = "Fast data loading for TensorBoard" +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "tensorboard-plugin-wit" +version = "1.8.0" +description = "What-If Tool TensorBoard plugin." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "terminado" +version = "0.12.1" +description = "Tornado websocket backend for the Xterm.js Javascript terminal emulator library." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +ptyprocess = {version = "*", markers = "os_name != \"nt\""} +pywinpty = {version = ">=1.1.0", markers = "os_name == \"nt\""} +tornado = ">=4" + +[package.extras] +test = ["pytest"] + +[[package]] +name = "testpath" +version = "0.5.0" +description = "Test utilities for code working with files and commands" +category = "main" +optional = false +python-versions = ">= 3.5" + +[package.extras] +test = ["pytest", "pathlib2"] + +[[package]] +name = "tf" +version = "1.12.1.post3" +description = "tf is a package that lets the user keep track of multiple coordinate" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +genmsg = "*" +genpy = "<2000" +geometry-msgs = "*" +roslib = "*" +rospkg = "*" +sensor-msgs = "*" +std-msgs = "*" + +[package.source] +type = "legacy" +url = "https://rospypi.github.io/simple" +reference = "ros" + +[[package]] +name = "tf2-msgs" +version = "0.7.2.post3" +description = "" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +genpy = ">=0.6.14,<2000" + +[package.source] +type = "legacy" +url = "https://rospypi.github.io/simple" +reference = "ros" + +[[package]] +name = "tf2-py" +version = "0.6.5.post1" +description = "" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +geometry_msgs = "*" +rospy = "*" +tf2_msgs = "*" + +[package.source] +type = "legacy" +url = "https://rospypi.github.io/simple" +reference = "ros" + +[[package]] +name = "tf2-ros" +version = "0.6.5" +description = "This package contains the ROS bindings for the tf2 library, for both Python and C++." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +actionlib = "*" +actionlib-msgs = "*" +geometry-msgs = "*" +rospy = "*" +tf2-msgs = "*" +tf2-py = "*" + +[package.source] +type = "legacy" +url = "https://rospypi.github.io/simple" +reference = "ros" + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +category = "dev" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "torch" +version = "1.10.0" +description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" +category = "main" +optional = false +python-versions = ">=3.6.2" + +[package.dependencies] +typing-extensions = "*" + +[[package]] +name = "tornado" +version = "6.1" +description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." +category = "main" +optional = false +python-versions = ">= 3.5" + +[[package]] +name = "traitlets" +version = "5.1.1" +description = "Traitlets Python configuration system" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +test = ["pytest"] + +[[package]] +name = "typing-extensions" +version = "3.10.0.2" +description = "Backported and Experimental Type Hints for Python 3.5+" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "urllib3" +version = "1.26.7" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" + +[package.extras] +brotli = ["brotlipy (>=0.6.0)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[[package]] +name = "wcwidth" +version = "0.2.5" +description = "Measures the displayed width of unicode strings in a terminal" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "webencodings" +version = "0.5.1" +description = "Character encoding aliases for legacy web content" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "werkzeug" +version = "2.0.2" +description = "The comprehensive WSGI web application library." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +watchdog = ["watchdog"] + +[[package]] +name = "widgetsnbextension" +version = "3.5.2" +description = "IPython HTML widgets for Jupyter" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +notebook = ">=4.4.1" + +[[package]] +name = "zipp" +version = "3.6.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] + +[metadata] +lock-version = "1.1" +python-versions = ">=3.8,<3.10" +content-hash = "41e16c86ccb17760d49ec243797e45b9bca7c7f7bfe3fc4077726c07a6a8547c" + +[metadata.files] +absl-py = [ + {file = "absl-py-1.0.0.tar.gz", hash = "sha256:ac511215c01ee9ae47b19716599e8ccfa746f2e18de72bdf641b79b22afa27ea"}, + {file = "absl_py-1.0.0-py3-none-any.whl", hash = "sha256:84e6dcdc69c947d0c13e5457d056bd43cade4c2393dce00d684aedea77ddc2a3"}, +] +actionlib = [] +actionlib-msgs = [] +appnope = [ + {file = "appnope-0.1.2-py2.py3-none-any.whl", hash = "sha256:93aa393e9d6c54c5cd570ccadd8edad61ea0c4b9ea7a01409020c9aa019eb442"}, + {file = "appnope-0.1.2.tar.gz", hash = "sha256:dd83cd4b5b460958838f6eb3000c660b1f9caf2a5b1de4264e941512f603258a"}, +] +argon2-cffi = [ + {file = "argon2-cffi-21.1.0.tar.gz", hash = "sha256:f710b61103d1a1f692ca3ecbd1373e28aa5e545ac625ba067ff2feca1b2bb870"}, + {file = "argon2_cffi-21.1.0-cp35-abi3-macosx_10_14_x86_64.whl", hash = "sha256:217b4f0f853ccbbb5045242946ad2e162e396064575860141b71a85eb47e475a"}, + {file = "argon2_cffi-21.1.0-cp35-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:fa7e7d1fc22514a32b1761fdfa1882b6baa5c36bb3ef557bdd69e6fc9ba14a41"}, + {file = "argon2_cffi-21.1.0-cp35-abi3-win32.whl", hash = "sha256:e4d8f0ae1524b7b0372a3e574a2561cbdddb3fdb6c28b70a72868189bda19659"}, + {file = "argon2_cffi-21.1.0-cp35-abi3-win_amd64.whl", hash = "sha256:65213a9174320a1aee03fe826596e0620783966b49eb636955958b3074e87ff9"}, + {file = "argon2_cffi-21.1.0-pp36-pypy36_pp73-macosx_10_7_x86_64.whl", hash = "sha256:245f64a203012b144b7b8c8ea6d468cb02b37caa5afee5ba4a10c80599334f6a"}, + {file = "argon2_cffi-21.1.0-pp36-pypy36_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4ad152c418f7eb640eac41ac815534e6aa61d1624530b8e7779114ecfbf327f8"}, + {file = "argon2_cffi-21.1.0-pp36-pypy36_pp73-win32.whl", hash = "sha256:bc513db2283c385ea4da31a2cd039c33380701f376f4edd12fe56db118a3b21a"}, + {file = "argon2_cffi-21.1.0-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:c7a7c8cc98ac418002090e4add5bebfff1b915ea1cb459c578cd8206fef10378"}, + {file = "argon2_cffi-21.1.0-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:165cadae5ac1e26644f5ade3bd9c18d89963be51d9ea8817bd671006d7909057"}, + {file = "argon2_cffi-21.1.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:566ffb581bbd9db5562327aee71b2eda24a1c15b23a356740abe3c011bbe0dcb"}, +] +attrs = [ + {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, + {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, +] +backcall = [ + {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, + {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, +] +black = [ + {file = "black-22.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09"}, + {file = "black-22.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5795a0375eb87bfe902e80e0c8cfaedf8af4d49694d69161e5bd3206c18618bb"}, + {file = "black-22.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e3556168e2e5c49629f7b0f377070240bd5511e45e25a4497bb0073d9dda776a"}, + {file = "black-22.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67c8301ec94e3bcc8906740fe071391bce40a862b7be0b86fb5382beefecd968"}, + {file = "black-22.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:fd57160949179ec517d32ac2ac898b5f20d68ed1a9c977346efbac9c2f1e779d"}, + {file = "black-22.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cc1e1de68c8e5444e8f94c3670bb48a2beef0e91dddfd4fcc29595ebd90bb9ce"}, + {file = "black-22.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2fc92002d44746d3e7db7cf9313cf4452f43e9ea77a2c939defce3b10b5c82"}, + {file = "black-22.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:a6342964b43a99dbc72f72812bf88cad8f0217ae9acb47c0d4f141a6416d2d7b"}, + {file = "black-22.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:328efc0cc70ccb23429d6be184a15ce613f676bdfc85e5fe8ea2a9354b4e9015"}, + {file = "black-22.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06f9d8846f2340dfac80ceb20200ea5d1b3f181dd0556b47af4e8e0b24fa0a6b"}, + {file = "black-22.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4efa5fad66b903b4a5f96d91461d90b9507a812b3c5de657d544215bb7877a"}, + {file = "black-22.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8477ec6bbfe0312c128e74644ac8a02ca06bcdb8982d4ee06f209be28cdf163"}, + {file = "black-22.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:637a4014c63fbf42a692d22b55d8ad6968a946b4a6ebc385c5505d9625b6a464"}, + {file = "black-22.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:863714200ada56cbc366dc9ae5291ceb936573155f8bf8e9de92aef51f3ad0f0"}, + {file = "black-22.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10dbe6e6d2988049b4655b2b739f98785a884d4d6b85bc35133a8fb9a2233176"}, + {file = "black-22.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:cee3e11161dde1b2a33a904b850b0899e0424cc331b7295f2a9698e79f9a69a0"}, + {file = "black-22.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5891ef8abc06576985de8fa88e95ab70641de6c1fca97e2a15820a9b69e51b20"}, + {file = "black-22.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:30d78ba6bf080eeaf0b7b875d924b15cd46fec5fd044ddfbad38c8ea9171043a"}, + {file = "black-22.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ee8f1f7228cce7dffc2b464f07ce769f478968bfb3dd1254a4c2eeed84928aad"}, + {file = "black-22.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ee227b696ca60dd1c507be80a6bc849a5a6ab57ac7352aad1ffec9e8b805f21"}, + {file = "black-22.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:9b542ced1ec0ceeff5b37d69838106a6348e60db7b8fdd245294dc1d26136265"}, + {file = "black-22.3.0-py3-none-any.whl", hash = "sha256:bc58025940a896d7e5356952228b68f793cf5fcb342be703c3a2669a1488cb72"}, + {file = "black-22.3.0.tar.gz", hash = "sha256:35020b8886c022ced9282b51b5a875b6d1ab0c387b31a065b84db7c33085ca79"}, +] +bleach = [ + {file = "bleach-4.1.0-py2.py3-none-any.whl", hash = "sha256:4d2651ab93271d1129ac9cbc679f524565cc8a1b791909c4a51eac4446a15994"}, + {file = "bleach-4.1.0.tar.gz", hash = "sha256:0900d8b37eba61a802ee40ac0061f8c2b5dee29c1927dd1d233e075ebf5a71da"}, +] +cachetools = [ + {file = "cachetools-4.2.4-py3-none-any.whl", hash = "sha256:92971d3cb7d2a97efff7c7bb1657f21a8f5fb309a37530537c71b1774189f2d1"}, + {file = "cachetools-4.2.4.tar.gz", hash = "sha256:89ea6f1b638d5a73a4f9226be57ac5e4f399d22770b92355f92dcb0f7f001693"}, +] +catkin = [] +catkin-pkg = [ + {file = "catkin_pkg-0.4.24-py3-none-any.whl", hash = "sha256:6ae0dddcde95689266e91dac13e1d8e9cdec4739bc7e2037b14cbcc1d7af96b2"}, + {file = "catkin_pkg-0.4.24.tar.gz", hash = "sha256:f26d22cc5d8cb54f681f13fec4d06637b4983d493aa054f8e69ba888d632c6b4"}, +] +certifi = [ + {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, + {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, +] +cffi = [ + {file = "cffi-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962"}, + {file = "cffi-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0"}, + {file = "cffi-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14"}, + {file = "cffi-1.15.0-cp27-cp27m-win32.whl", hash = "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474"}, + {file = "cffi-1.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6"}, + {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27"}, + {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023"}, + {file = "cffi-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2"}, + {file = "cffi-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382"}, + {file = "cffi-1.15.0-cp310-cp310-win32.whl", hash = "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55"}, + {file = "cffi-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0"}, + {file = "cffi-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605"}, + {file = "cffi-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e"}, + {file = "cffi-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc"}, + {file = "cffi-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7"}, + {file = "cffi-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66"}, + {file = "cffi-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029"}, + {file = "cffi-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6"}, + {file = "cffi-1.15.0-cp38-cp38-win32.whl", hash = "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c"}, + {file = "cffi-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443"}, + {file = "cffi-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a"}, + {file = "cffi-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8"}, + {file = "cffi-1.15.0-cp39-cp39-win32.whl", hash = "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a"}, + {file = "cffi-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139"}, + {file = "cffi-1.15.0.tar.gz", hash = "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954"}, +] +charset-normalizer = [ + {file = "charset-normalizer-2.0.7.tar.gz", hash = "sha256:e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0"}, + {file = "charset_normalizer-2.0.7-py3-none-any.whl", hash = "sha256:f7af805c321bfa1ce6714c51f254e0d5bb5e5834039bc17db7ebe3a4cec9492b"}, +] +click = [ + {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, + {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, +] +cloudpickle = [ + {file = "cloudpickle-2.0.0-py3-none-any.whl", hash = "sha256:6b2df9741d06f43839a3275c4e6632f7df6487a1f181f5f46a052d3c917c3d11"}, + {file = "cloudpickle-2.0.0.tar.gz", hash = "sha256:5cd02f3b417a783ba84a4ec3e290ff7929009fe51f6405423cfccfadd43ba4a4"}, +] +colorama = [ + {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, +] +cycler = [ + {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, + {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, +] +debugpy = [ + {file = "debugpy-1.5.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:70b422c63a833630c33e3f9cdbd9b6971f8c5afd452697e464339a21bbe862ba"}, + {file = "debugpy-1.5.1-cp310-cp310-win32.whl", hash = "sha256:3a457ad9c0059a21a6c7d563c1f18e924f5cf90278c722bd50ede6f56b77c7fe"}, + {file = "debugpy-1.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:5d76a4fd028d8009c3faf1185b4b78ceb2273dd2499447664b03939e0368bb90"}, + {file = "debugpy-1.5.1-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:16db27b4b91991442f91d73604d32080b30de655aca9ba821b1972ea8171021b"}, + {file = "debugpy-1.5.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2b073ad5e8d8c488fbb6a116986858bab0c9c4558f28deb8832c7a5a27405bd6"}, + {file = "debugpy-1.5.1-cp36-cp36m-win32.whl", hash = "sha256:318f81f37341e4e054b4267d39896b73cddb3612ca13b39d7eea45af65165e1d"}, + {file = "debugpy-1.5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b5b3157372e0e0a1297a8b6b5280bcf1d35a40f436c7973771c972726d1e32d5"}, + {file = "debugpy-1.5.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:1ec3a086e14bba6c472632025b8fe5bdfbaef2afa1ebd5c6615ce6ed8d89bc67"}, + {file = "debugpy-1.5.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:26fbe53cca45a608679094791ce587b6e2798acd1d4777a8b303b07622e85182"}, + {file = "debugpy-1.5.1-cp37-cp37m-win32.whl", hash = "sha256:d876db8c312eeb02d85611e0f696abe66a2c1515e6405943609e725d5ff36f2a"}, + {file = "debugpy-1.5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4404a62fb5332ea5c8c9132290eef50b3a0ba38cecacad5529e969a783bcbdd7"}, + {file = "debugpy-1.5.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:f3a3dca9104aa14fd4210edcce6d9ce2b65bd9618c0b222135a40b9d6e2a9eeb"}, + {file = "debugpy-1.5.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b2df2c373e85871086bd55271c929670cd4e1dba63e94a08d442db830646203b"}, + {file = "debugpy-1.5.1-cp38-cp38-win32.whl", hash = "sha256:82f5f9ce93af6861a0713f804e62ab390bb12a17f113153e47fea8bbb1dfbe36"}, + {file = "debugpy-1.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:17a25ce9d7714f92fc97ef00cc06269d7c2b163094990ada30156ed31d9a5030"}, + {file = "debugpy-1.5.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:01e98c594b3e66d529e40edf314f849cd1a21f7a013298df58cd8e263bf8e184"}, + {file = "debugpy-1.5.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f73988422b17f071ad3c4383551ace1ba5ed810cbab5f9c362783d22d40a08dc"}, + {file = "debugpy-1.5.1-cp39-cp39-win32.whl", hash = "sha256:23df67fc56d59e386c342428a7953c2c06cc226d8525b11319153e96afb65b0c"}, + {file = "debugpy-1.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:a2aa64f6d2ca7ded8a7e8a4e7cae3bc71866b09876b7b05cecad231779cb9156"}, + {file = "debugpy-1.5.1-py2.py3-none-any.whl", hash = "sha256:194f95dd3e84568b5489aab5689a3a2c044e8fdc06f1890b8b4f70b6b89f2778"}, + {file = "debugpy-1.5.1.zip", hash = "sha256:d2b09e91fbd1efa4f4fda121d49af89501beda50c18ed7499712c71a4bf3452e"}, +] +decorator = [ + {file = "decorator-5.1.0-py3-none-any.whl", hash = "sha256:7b12e7c3c6ab203a29e157335e9122cb03de9ab7264b137594103fd4a683b374"}, + {file = "decorator-5.1.0.tar.gz", hash = "sha256:e59913af105b9860aa2c8d3272d9de5a56a4e608db9a2f167a8480b323d529a7"}, +] +defusedxml = [ + {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, + {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, +] +distro = [ + {file = "distro-1.6.0-py2.py3-none-any.whl", hash = "sha256:c8713330ab31a034623a9515663ed87696700b55f04556b97c39cd261aa70dc7"}, + {file = "distro-1.6.0.tar.gz", hash = "sha256:83f5e5a09f9c5f68f60173de572930effbcc0287bb84fdc4426cb4168c088424"}, +] +docutils = [ + {file = "docutils-0.18-py2.py3-none-any.whl", hash = "sha256:a31688b2ea858517fa54293e5d5df06fbb875fb1f7e4c64529271b77781ca8fc"}, + {file = "docutils-0.18.tar.gz", hash = "sha256:c1d5dab2b11d16397406a282e53953fe495a46d69ae329f55aa98a5c4e3c5fbb"}, +] +empy = [ + {file = "empy-3.3.4.tar.gz", hash = "sha256:73ac49785b601479df4ea18a7c79bc1304a8a7c34c02b9472cf1206ae88f01b3"}, +] +entrypoints = [ + {file = "entrypoints-0.3-py2.py3-none-any.whl", hash = "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19"}, + {file = "entrypoints-0.3.tar.gz", hash = "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"}, +] +filelock = [ + {file = "filelock-3.3.2-py3-none-any.whl", hash = "sha256:bb2a1c717df74c48a2d00ed625e5a66f8572a3a30baacb7657add1d7bac4097b"}, + {file = "filelock-3.3.2.tar.gz", hash = "sha256:7afc856f74fa7006a289fd10fa840e1eebd8bbff6bffb69c26c54a0512ea8cf8"}, +] +genmsg = [] +genpy = [] +geometry-msgs = [] +gnupg = [ + {file = "gnupg-2.3.1-py2.7.egg", hash = "sha256:d2e16c486aaeecbb65633f8493ccab025e2487c0e1dc59a83c520b6f81dff9b8"}, + {file = "gnupg-2.3.1-py3.4.egg", hash = "sha256:be656a2f693dbac4362537c1b6cfd03131ac5ce7a4b2bb21bff7e3145f94f7ea"}, + {file = "gnupg-2.3.1.tar.gz", hash = "sha256:8db5a05c369dbc231dab4c98515ce828f2dffdc14f1534441a6c59b71c6d2031"}, +] +google-auth = [ + {file = "google-auth-2.3.3.tar.gz", hash = "sha256:d83570a664c10b97a1dc6f8df87e5fdfff012f48f62be131e449c20dfc32630e"}, + {file = "google_auth-2.3.3-py2.py3-none-any.whl", hash = "sha256:a348a50b027679cb7dae98043ac8dbcc1d7951f06d8387496071a1e05a2465c0"}, +] +google-auth-oauthlib = [ + {file = "google-auth-oauthlib-0.4.6.tar.gz", hash = "sha256:a90a072f6993f2c327067bf65270046384cda5a8ecb20b94ea9a687f1f233a7a"}, + {file = "google_auth_oauthlib-0.4.6-py2.py3-none-any.whl", hash = "sha256:3f2a6e802eebbb6fb736a370fbf3b055edcb6b52878bf2f26330b5e041316c73"}, +] +grpcio = [ + {file = "grpcio-1.41.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:ead9885b53777bed4b0694ff0baea9d2c519ff774b17b177bde43d73e2b4aa38"}, + {file = "grpcio-1.41.1-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:3b4b7c1ab18283eb64af5648d20eabef9237a2aec09e30a805f18adc9497258d"}, + {file = "grpcio-1.41.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:f68aa98f5970eccb6c94456f3447a99916c42fbddae1971256bc4e7c40a6593b"}, + {file = "grpcio-1.41.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:71d9ed5a732a54b9c87764609f2fd2bc4ae72fa85e271038eb132ea723222209"}, + {file = "grpcio-1.41.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0aa1af3e1480b6dd3092ee67c4b67b1ea88d638fcdc4d1a611ae11e311800b34"}, + {file = "grpcio-1.41.1-cp310-cp310-win32.whl", hash = "sha256:766f1b943abc3e27842b72fba6e28fb9f57c9b84029fd7e91146e4c37034d937"}, + {file = "grpcio-1.41.1-cp310-cp310-win_amd64.whl", hash = "sha256:3713e3918da6ae10812a64e75620a172f01af2ff0a1c99d6481c910e1d4a9053"}, + {file = "grpcio-1.41.1-cp36-cp36m-linux_armv7l.whl", hash = "sha256:3f0b70cf8632028714a8341b841b011a47900b1c163bf5fababb4ab3888c9b6c"}, + {file = "grpcio-1.41.1-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:8824b36e6b0e45fefe0b4eac5ad460830e0cbc856a0c794f711289b4b8933d53"}, + {file = "grpcio-1.41.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:788154b32bf712e9711d001df024af5f7b2522117876c129bb27b9ad6e5461fb"}, + {file = "grpcio-1.41.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:c32c470e077b34a52e87e7de26644ad0f9e9ff89a785ff7e6466870869659e05"}, + {file = "grpcio-1.41.1-cp36-cp36m-manylinux_2_17_aarch64.whl", hash = "sha256:a3bb4302389b23f2006ecaaea5eb4a39cc80ea98d1964159e59c1c20ef39a483"}, + {file = "grpcio-1.41.1-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e156ea12adb7a7ca8d8280c9df850c15510b790c785fc26c9a3fb928cd221fd4"}, + {file = "grpcio-1.41.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eb8180a6d9e47fc865a4e92a2678f3202145021ef2c1bccf165fa5744f6ec95"}, + {file = "grpcio-1.41.1-cp36-cp36m-win32.whl", hash = "sha256:888d8519709652dd39415de5f79abd50257201b345dd4f40151feffc3dad3232"}, + {file = "grpcio-1.41.1-cp36-cp36m-win_amd64.whl", hash = "sha256:734690b3f35468f8ed4003ec7622d2d47567f1881f5fcdca34f1e52551c2ef55"}, + {file = "grpcio-1.41.1-cp37-cp37m-linux_armv7l.whl", hash = "sha256:133fb9a3cf4519543e4e41eb18b5dac0da26941aeabca8122dbcf3decbad2d21"}, + {file = "grpcio-1.41.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:a5ac91db3c588296366554b2d91116fc3a9f05bae516cafae07220e1f05bfef7"}, + {file = "grpcio-1.41.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:b8dd1b6456c6fb3681affe0f81dff4b3bc46f825fc05e086d64216545da9ad92"}, + {file = "grpcio-1.41.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:9e403d07d77ed4495ad3c18994191525b11274693e72e464241c9139e2f9cd7c"}, + {file = "grpcio-1.41.1-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:9d1be99f216b18f8a9dbdfbdbcc9a6caee504d0d27295fdbb5c8da35f5254a69"}, + {file = "grpcio-1.41.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ebbe9582ef06559a2358827a588ab4b92a2639517de8fe428288772820ab03b5"}, + {file = "grpcio-1.41.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd570720871dc84d2adc8430ce287319c9238d1e2f70c140f9bc54c690fabd1b"}, + {file = "grpcio-1.41.1-cp37-cp37m-win32.whl", hash = "sha256:0c075616d5e86fb65fd4784d5a87d6e5a1882d277dce5c33d9b67cfc71d79899"}, + {file = "grpcio-1.41.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9170b5d2082fc00c057c6ccd6b893033c1ade05717fcec1d63557c3bc7afdb1b"}, + {file = "grpcio-1.41.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:61aa02f4505c5bbbaeba80fef1bd6871d1aef05a8778a707ab91303ee0865ad0"}, + {file = "grpcio-1.41.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:d1461672b2eaef9affb60a71014ebd2f789deea7c9acb1d4bd163de92dd8e044"}, + {file = "grpcio-1.41.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:c35b847bc6bd3c3a118a13277d91a772e7dd163ce7dd2791239f9941b6eaafe3"}, + {file = "grpcio-1.41.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:8487fb0649ebebc9c5dca1a6dc4eb7fddf701183426b3eefeb3584639d223d43"}, + {file = "grpcio-1.41.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:6ca497ccecaa8727f14c4ccc9ffb70a19c6413fe1d4650500c90a7febd662860"}, + {file = "grpcio-1.41.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b1232c5efc8a9e4b7a13db235c51135412beb9e62e618a2a89dd0463edb3d929"}, + {file = "grpcio-1.41.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31a47af7356fb5ed3120636dd75c5efb571ecf15737484119e31286687f0e52a"}, + {file = "grpcio-1.41.1-cp38-cp38-win32.whl", hash = "sha256:7a22a7378ea59ad1e6f2e79f9da6862eb9e1f6586253aee784d419a49e3f4bd9"}, + {file = "grpcio-1.41.1-cp38-cp38-win_amd64.whl", hash = "sha256:32b7ca83f1a6929217098aaaac89fc49879ae714c95501d40df41a0e7506164c"}, + {file = "grpcio-1.41.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:3213dfe3abfc3fda7f30e86aa5967dce0c2eb4cc90a0504f95434091bf6b219a"}, + {file = "grpcio-1.41.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:fd11995e3402af0f838844194707da8b3235f1719bcac961493f0138f1325893"}, + {file = "grpcio-1.41.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:23a3f03e1d9ac429ff78d23d2ab07756d3728ee1a68b5f244d8435006608b6aa"}, + {file = "grpcio-1.41.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:fc2eadfb5ec956c556c138fab0dfc1d2395c57ae0bfea047edae1976a26b250c"}, + {file = "grpcio-1.41.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:2a34c8979de10b04a44d2cad07d41d83643e65e49f84a05b1adf150aeb41c95f"}, + {file = "grpcio-1.41.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72d0bdc3605dc8f4187b302e1180643963896e3f2917a52becb51afb54448e3e"}, + {file = "grpcio-1.41.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:740f5b21a7108a8c08bf522434752dc1d306274d47ca8b4d51af5588a16b6113"}, + {file = "grpcio-1.41.1-cp39-cp39-win32.whl", hash = "sha256:2f2ee78a6ae88d668ceda56fa4a18d8a38b34c2f2e1332083dd1da1a92870703"}, + {file = "grpcio-1.41.1-cp39-cp39-win_amd64.whl", hash = "sha256:c3a446b6a1f8077cc03d0d496fc1cecdd3d0b66860c0c5b65cc92d0549117840"}, + {file = "grpcio-1.41.1.tar.gz", hash = "sha256:9b751271b029432a526a4970dc9b70d93eb6f0963b6a841b574f780b72651969"}, +] +gym = [ + {file = "gym-0.21.0.tar.gz", hash = "sha256:0fd1ce165c754b4017e37a617b097c032b8c3feb8a0394ccc8777c7c50dddff3"}, +] +idna = [ + {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, + {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, +] +importlib-resources = [ + {file = "importlib_resources-5.4.0-py3-none-any.whl", hash = "sha256:33a95faed5fc19b4bc16b29a6eeae248a3fe69dd55d4d229d2b480e23eeaad45"}, + {file = "importlib_resources-5.4.0.tar.gz", hash = "sha256:d756e2f85dd4de2ba89be0b21dba2a3bbec2e871a42a3a16719258a11f87506b"}, +] +ipykernel = [ + {file = "ipykernel-6.5.0-py3-none-any.whl", hash = "sha256:f43de132feea90f86d68c51013afe9694f9415f440053ec9909dd656c75b04b5"}, + {file = "ipykernel-6.5.0.tar.gz", hash = "sha256:299795cca2c4aed7e233e3ad5360e1c73627fd0dcec11a9e75d5b2df43629353"}, +] +ipython = [ + {file = "ipython-7.29.0-py3-none-any.whl", hash = "sha256:a658beaf856ce46bc453366d5dc6b2ddc6c481efd3540cb28aa3943819caac9f"}, + {file = "ipython-7.29.0.tar.gz", hash = "sha256:4f69d7423a5a1972f6347ff233e38bbf4df6a150ef20fbb00c635442ac3060aa"}, +] +ipython-genutils = [ + {file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"}, + {file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"}, +] +ipywidgets = [ + {file = "ipywidgets-7.6.5-py2.py3-none-any.whl", hash = "sha256:d258f582f915c62ea91023299603be095de19afb5ee271698f88327b9fe9bf43"}, + {file = "ipywidgets-7.6.5.tar.gz", hash = "sha256:00974f7cb4d5f8d494c19810fedb9fa9b64bffd3cda7c2be23c133a1ad3c99c5"}, +] +jedi = [ + {file = "jedi-0.18.0-py2.py3-none-any.whl", hash = "sha256:18456d83f65f400ab0c2d3319e48520420ef43b23a086fdc05dff34132f0fb93"}, + {file = "jedi-0.18.0.tar.gz", hash = "sha256:92550a404bad8afed881a137ec9a461fed49eca661414be45059329614ed0707"}, +] +jinja2 = [ + {file = "Jinja2-3.0.3-py3-none-any.whl", hash = "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8"}, + {file = "Jinja2-3.0.3.tar.gz", hash = "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"}, +] +jsonschema = [ + {file = "jsonschema-4.2.1-py3-none-any.whl", hash = "sha256:2a0f162822a64d95287990481b45d82f096e99721c86534f48201b64ebca6e8c"}, + {file = "jsonschema-4.2.1.tar.gz", hash = "sha256:390713469ae64b8a58698bb3cbc3859abe6925b565a973f87323ef21b09a27a8"}, +] +jupyter = [ + {file = "jupyter-1.0.0-py2.py3-none-any.whl", hash = "sha256:5b290f93b98ffbc21c0c7e749f054b3267782166d72fa5e3ed1ed4eaf34a2b78"}, + {file = "jupyter-1.0.0.tar.gz", hash = "sha256:d9dc4b3318f310e34c82951ea5d6683f67bed7def4b259fafbfe4f1beb1d8e5f"}, + {file = "jupyter-1.0.0.zip", hash = "sha256:3e1f86076bbb7c8c207829390305a2b1fe836d471ed54be66a3b8c41e7f46cc7"}, +] +jupyter-client = [ + {file = "jupyter_client-7.0.6-py3-none-any.whl", hash = "sha256:074bdeb1ffaef4a3095468ee16313938cfdc48fc65ca95cc18980b956c2e5d79"}, + {file = "jupyter_client-7.0.6.tar.gz", hash = "sha256:8b6e06000eb9399775e0a55c52df6c1be4766666209c22f90c2691ded0e338dc"}, +] +jupyter-console = [ + {file = "jupyter_console-6.4.0-py3-none-any.whl", hash = "sha256:7799c4ea951e0e96ba8260575423cb323ea5a03fcf5503560fa3e15748869e27"}, + {file = "jupyter_console-6.4.0.tar.gz", hash = "sha256:242248e1685039cd8bff2c2ecb7ce6c1546eb50ee3b08519729e6e881aec19c7"}, +] +jupyter-core = [ + {file = "jupyter_core-4.9.1-py3-none-any.whl", hash = "sha256:1c091f3bbefd6f2a8782f2c1db662ca8478ac240e962ae2c66f0b87c818154ea"}, + {file = "jupyter_core-4.9.1.tar.gz", hash = "sha256:dce8a7499da5a53ae3afd5a9f4b02e5df1d57250cf48f3ad79da23b4778cd6fa"}, +] +jupyterlab-pygments = [ + {file = "jupyterlab_pygments-0.1.2-py2.py3-none-any.whl", hash = "sha256:abfb880fd1561987efaefcb2d2ac75145d2a5d0139b1876d5be806e32f630008"}, + {file = "jupyterlab_pygments-0.1.2.tar.gz", hash = "sha256:cfcda0873626150932f438eccf0f8bf22bfa92345b814890ab360d666b254146"}, +] +jupyterlab-widgets = [ + {file = "jupyterlab_widgets-1.0.2-py3-none-any.whl", hash = "sha256:f5d9efface8ec62941173ba1cffb2edd0ecddc801c11ae2931e30b50492eb8f7"}, + {file = "jupyterlab_widgets-1.0.2.tar.gz", hash = "sha256:7885092b2b96bf189c3a705cc3c412a4472ec5e8382d0b47219a66cccae73cfa"}, +] +kiwisolver = [ + {file = "kiwisolver-1.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1d819553730d3c2724582124aee8a03c846ec4362ded1034c16fb3ef309264e6"}, + {file = "kiwisolver-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8d93a1095f83e908fc253f2fb569c2711414c0bfd451cab580466465b235b470"}, + {file = "kiwisolver-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c4550a359c5157aaf8507e6820d98682872b9100ce7607f8aa070b4b8af6c298"}, + {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2210f28778c7d2ee13f3c2a20a3a22db889e75f4ec13a21072eabb5693801e84"}, + {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:82f49c5a79d3839bc8f38cb5f4bfc87e15f04cbafa5fbd12fb32c941cb529cfb"}, + {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9661a04ca3c950a8ac8c47f53cbc0b530bce1b52f516a1e87b7736fec24bfff0"}, + {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ddb500a2808c100e72c075cbb00bf32e62763c82b6a882d403f01a119e3f402"}, + {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72be6ebb4e92520b9726d7146bc9c9b277513a57a38efcf66db0620aec0097e0"}, + {file = "kiwisolver-1.3.2-cp310-cp310-win32.whl", hash = "sha256:83d2c9db5dfc537d0171e32de160461230eb14663299b7e6d18ca6dca21e4977"}, + {file = "kiwisolver-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:cba430db673c29376135e695c6e2501c44c256a81495da849e85d1793ee975ad"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4116ba9a58109ed5e4cb315bdcbff9838f3159d099ba5259c7c7fb77f8537492"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19554bd8d54cf41139f376753af1a644b63c9ca93f8f72009d50a2080f870f77"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7a4cf5bbdc861987a7745aed7a536c6405256853c94abc9f3287c3fa401b174"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0007840186bacfaa0aba4466d5890334ea5938e0bb7e28078a0eb0e63b5b59d5"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec2eba188c1906b05b9b49ae55aae4efd8150c61ba450e6721f64620c50b59eb"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3dbb3cea20b4af4f49f84cffaf45dd5f88e8594d18568e0225e6ad9dec0e7967"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-win32.whl", hash = "sha256:5326ddfacbe51abf9469fe668944bc2e399181a2158cb5d45e1d40856b2a0589"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:c6572c2dab23c86a14e82c245473d45b4c515314f1f859e92608dcafbd2f19b8"}, + {file = "kiwisolver-1.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b5074fb09429f2b7bc82b6fb4be8645dcbac14e592128beeff5461dcde0af09f"}, + {file = "kiwisolver-1.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:22521219ca739654a296eea6d4367703558fba16f98688bd8ce65abff36eaa84"}, + {file = "kiwisolver-1.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c358721aebd40c243894298f685a19eb0491a5c3e0b923b9f887ef1193ddf829"}, + {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ba5a1041480c6e0a8b11a9544d53562abc2d19220bfa14133e0cdd9967e97af"}, + {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44e6adf67577dbdfa2d9f06db9fbc5639afefdb5bf2b4dfec25c3a7fbc619536"}, + {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1d45d1c74f88b9f41062716c727f78f2a59a5476ecbe74956fafb423c5c87a76"}, + {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:70adc3658138bc77a36ce769f5f183169bc0a2906a4f61f09673f7181255ac9b"}, + {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b6a5431940f28b6de123de42f0eb47b84a073ee3c3345dc109ad550a3307dd28"}, + {file = "kiwisolver-1.3.2-cp38-cp38-win32.whl", hash = "sha256:ee040a7de8d295dbd261ef2d6d3192f13e2b08ec4a954de34a6fb8ff6422e24c"}, + {file = "kiwisolver-1.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:8dc3d842fa41a33fe83d9f5c66c0cc1f28756530cd89944b63b072281e852031"}, + {file = "kiwisolver-1.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a498bcd005e8a3fedd0022bb30ee0ad92728154a8798b703f394484452550507"}, + {file = "kiwisolver-1.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:80efd202108c3a4150e042b269f7c78643420cc232a0a771743bb96b742f838f"}, + {file = "kiwisolver-1.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f8eb7b6716f5b50e9c06207a14172cf2de201e41912ebe732846c02c830455b9"}, + {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f441422bb313ab25de7b3dbfd388e790eceb76ce01a18199ec4944b369017009"}, + {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:30fa008c172355c7768159983a7270cb23838c4d7db73d6c0f6b60dde0d432c6"}, + {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f8f6c8f4f1cff93ca5058d6ec5f0efda922ecb3f4c5fb76181f327decff98b8"}, + {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba677bcaff9429fd1bf01648ad0901cea56c0d068df383d5f5856d88221fe75b"}, + {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7843b1624d6ccca403a610d1277f7c28ad184c5aa88a1750c1a999754e65b439"}, + {file = "kiwisolver-1.3.2-cp39-cp39-win32.whl", hash = "sha256:e6f5eb2f53fac7d408a45fbcdeda7224b1cfff64919d0f95473420a931347ae9"}, + {file = "kiwisolver-1.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:eedd3b59190885d1ebdf6c5e0ca56828beb1949b4dfe6e5d0256a461429ac386"}, + {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:dedc71c8eb9c5096037766390172c34fb86ef048b8e8958b4e484b9e505d66bc"}, + {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:bf7eb45d14fc036514c09554bf983f2a72323254912ed0c3c8e697b62c4c158f"}, + {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2b65bd35f3e06a47b5c30ea99e0c2b88f72c6476eedaf8cfbc8e66adb5479dcf"}, + {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25405f88a37c5f5bcba01c6e350086d65e7465fd1caaf986333d2a045045a223"}, + {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:bcadb05c3d4794eb9eee1dddf1c24215c92fb7b55a80beae7a60530a91060560"}, + {file = "kiwisolver-1.3.2.tar.gz", hash = "sha256:fc4453705b81d03568d5b808ad8f09c77c47534f6ac2e72e733f9ca4714aa75c"}, +] +mako = [ + {file = "Mako-1.1.5-py2.py3-none-any.whl", hash = "sha256:6804ee66a7f6a6416910463b00d76a7b25194cd27f1918500c5bd7be2a088a23"}, + {file = "Mako-1.1.5.tar.gz", hash = "sha256:169fa52af22a91900d852e937400e79f535496191c63712e3b9fda5a9bed6fc3"}, +] +markdown = [ + {file = "Markdown-3.3.4-py3-none-any.whl", hash = "sha256:96c3ba1261de2f7547b46a00ea8463832c921d3f9d6aba3f255a6f71386db20c"}, + {file = "Markdown-3.3.4.tar.gz", hash = "sha256:31b5b491868dcc87d6c24b7e3d19a0d730d59d3e46f4eea6430a321bed387a49"}, +] +markupsafe = [ + {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, + {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, +] +matplotlib = [ + {file = "matplotlib-3.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5c988bb43414c7c2b0a31bd5187b4d27fd625c080371b463a6d422047df78913"}, + {file = "matplotlib-3.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f1c5efc278d996af8a251b2ce0b07bbeccb821f25c8c9846bdcb00ffc7f158aa"}, + {file = "matplotlib-3.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:eeb1859efe7754b1460e1d4991bbd4a60a56f366bc422ef3a9c5ae05f0bc70b5"}, + {file = "matplotlib-3.4.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:844a7b0233e4ff7fba57e90b8799edaa40b9e31e300b8d5efc350937fa8b1bea"}, + {file = "matplotlib-3.4.3-cp37-cp37m-win32.whl", hash = "sha256:85f0c9cf724715e75243a7b3087cf4a3de056b55e05d4d76cc58d610d62894f3"}, + {file = "matplotlib-3.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:c70b6311dda3e27672f1bf48851a0de816d1ca6aaf3d49365fbdd8e959b33d2b"}, + {file = "matplotlib-3.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b884715a59fec9ad3b6048ecf3860f3b2ce965e676ef52593d6fa29abcf7d330"}, + {file = "matplotlib-3.4.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:a78a3b51f29448c7f4d4575e561f6b0dbb8d01c13c2046ab6c5220eb25c06506"}, + {file = "matplotlib-3.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6a724e3a48a54b8b6e7c4ae38cd3d07084508fa47c410c8757e9db9791421838"}, + {file = "matplotlib-3.4.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:48e1e0859b54d5f2e29bb78ca179fd59b971c6ceb29977fb52735bfd280eb0f5"}, + {file = "matplotlib-3.4.3-cp38-cp38-win32.whl", hash = "sha256:01c9de93a2ca0d128c9064f23709362e7fefb34910c7c9e0b8ab0de8258d5eda"}, + {file = "matplotlib-3.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:ebfb01a65c3f5d53a8c2a8133fec2b5221281c053d944ae81ff5822a68266617"}, + {file = "matplotlib-3.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b8b53f336a4688cfce615887505d7e41fd79b3594bf21dd300531a4f5b4f746a"}, + {file = "matplotlib-3.4.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:fcd6f1954943c0c192bfbebbac263f839d7055409f1173f80d8b11a224d236da"}, + {file = "matplotlib-3.4.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6be8df61b1626e1a142c57e065405e869e9429b4a6dab4a324757d0dc4d42235"}, + {file = "matplotlib-3.4.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:41b6e307458988891fcdea2d8ecf84a8c92d53f84190aa32da65f9505546e684"}, + {file = "matplotlib-3.4.3-cp39-cp39-win32.whl", hash = "sha256:f72657f1596199dc1e4e7a10f52a4784ead8a711f4e5b59bea95bdb97cf0e4fd"}, + {file = "matplotlib-3.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:f15edcb0629a0801738925fe27070480f446fcaa15de65946ff946ad99a59a40"}, + {file = "matplotlib-3.4.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:556965514b259204637c360d213de28d43a1f4aed1eca15596ce83f768c5a56f"}, + {file = "matplotlib-3.4.3-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:54a026055d5f8614f184e588f6e29064019a0aa8448450214c0b60926d62d919"}, + {file = "matplotlib-3.4.3.tar.gz", hash = "sha256:fc4f526dfdb31c9bd6b8ca06bf9fab663ca12f3ec9cdf4496fb44bc680140318"}, +] +matplotlib-inline = [ + {file = "matplotlib-inline-0.1.3.tar.gz", hash = "sha256:a04bfba22e0d1395479f866853ec1ee28eea1485c1d69a6faf00dc3e24ff34ee"}, + {file = "matplotlib_inline-0.1.3-py3-none-any.whl", hash = "sha256:aed605ba3b72462d64d475a21a9296f400a19c4f74a31b59103d2a99ffd5aa5c"}, +] +mistune = [ + {file = "mistune-0.8.4-py2.py3-none-any.whl", hash = "sha256:88a1051873018da288eee8538d476dffe1262495144b33ecb586c4ab266bb8d4"}, + {file = "mistune-0.8.4.tar.gz", hash = "sha256:59a3429db53c50b5c6bcc8a07f8848cb00d7dc8bdb431a4ab41920d201d4756e"}, +] +mypy-extensions = [ + {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, + {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, +] +nbclient = [ + {file = "nbclient-0.5.8-py3-none-any.whl", hash = "sha256:e85d4d6280d0a0237c1a6ec7a5e0757cf40a1fcb8c47253516b3a1f87f4ceae8"}, + {file = "nbclient-0.5.8.tar.gz", hash = "sha256:34f52cc9cb831a5d8ccd7031537e354c75dc61a24487f998712d1289de320a25"}, +] +nbconvert = [ + {file = "nbconvert-6.3.0-py3-none-any.whl", hash = "sha256:8f23fbeabda4a500685d788ee091bf22cf34119304314304fb39f16e2fc32f37"}, + {file = "nbconvert-6.3.0.tar.gz", hash = "sha256:5e77d6203854944520105e38f2563a813a4a3708e8563aa598928a3b5ee1081a"}, +] +nbformat = [ + {file = "nbformat-5.1.3-py3-none-any.whl", hash = "sha256:eb8447edd7127d043361bc17f2f5a807626bc8e878c7709a1c647abda28a9171"}, + {file = "nbformat-5.1.3.tar.gz", hash = "sha256:b516788ad70771c6250977c1374fcca6edebe6126fd2adb5a69aa5c2356fd1c8"}, +] +nest-asyncio = [ + {file = "nest_asyncio-1.5.1-py3-none-any.whl", hash = "sha256:76d6e972265063fe92a90b9cc4fb82616e07d586b346ed9d2c89a4187acea39c"}, + {file = "nest_asyncio-1.5.1.tar.gz", hash = "sha256:afc5a1c515210a23c461932765691ad39e8eba6551c055ac8d5546e69250d0aa"}, +] +netifaces = [ + {file = "netifaces-0.10.9-cp27-cp27m-macosx_10_13_x86_64.whl", hash = "sha256:b2ff3a0a4f991d2da5376efd3365064a43909877e9fabfa801df970771161d29"}, + {file = "netifaces-0.10.9-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:0c4304c6d5b33fbd9b20fdc369f3a2fef1a8bbacfb6fd05b9708db01333e9e7b"}, + {file = "netifaces-0.10.9-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:7a25a8e28281504f0e23e181d7a9ed699c72f061ca6bdfcd96c423c2a89e75fc"}, + {file = "netifaces-0.10.9-cp27-cp27m-win32.whl", hash = "sha256:6d84e50ec28e5d766c9911dce945412dc5b1ce760757c224c71e1a9759fa80c2"}, + {file = "netifaces-0.10.9-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f911b7f0083d445c8d24cfa5b42ad4996e33250400492080f5018a28c026db2b"}, + {file = "netifaces-0.10.9-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:4921ed406386246b84465950d15a4f63480c1458b0979c272364054b29d73084"}, + {file = "netifaces-0.10.9-cp33-cp33m-manylinux1_i686.whl", hash = "sha256:5b3167f923f67924b356c1338eb9ba275b2ba8d64c7c2c47cf5b5db49d574994"}, + {file = "netifaces-0.10.9-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:db881478f1170c6dd524175ba1c83b99d3a6f992a35eca756de0ddc4690a1940"}, + {file = "netifaces-0.10.9-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:f0427755c68571df37dc58835e53a4307884a48dec76f3c01e33eb0d4a3a81d7"}, + {file = "netifaces-0.10.9-cp34-cp34m-win32.whl", hash = "sha256:7cc6fd1eca65be588f001005446a47981cbe0b2909f5be8feafef3bf351a4e24"}, + {file = "netifaces-0.10.9-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:b47e8f9ff6846756be3dc3fb242ca8e86752cd35a08e06d54ffc2e2a2aca70ea"}, + {file = "netifaces-0.10.9-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f8885cc48c8c7ad51f36c175e462840f163cb4687eeb6c6d7dfaf7197308e36b"}, + {file = "netifaces-0.10.9-cp35-cp35m-win32.whl", hash = "sha256:755050799b5d5aedb1396046f270abfc4befca9ccba3074f3dbbb3cb34f13aae"}, + {file = "netifaces-0.10.9-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:ad10acab2ef691eb29a1cc52c3be5ad1423700e993cc035066049fa72999d0dc"}, + {file = "netifaces-0.10.9-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:563a1a366ee0fb3d96caab79b7ac7abd2c0a0577b157cc5a40301373a0501f89"}, + {file = "netifaces-0.10.9-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:30ed89ab8aff715caf9a9d827aa69cd02ad9f6b1896fd3fb4beb998466ed9a3c"}, + {file = "netifaces-0.10.9-cp36-cp36m-win32.whl", hash = "sha256:75d3a4ec5035db7478520ac547f7c176e9fd438269e795819b67223c486e5cbe"}, + {file = "netifaces-0.10.9-cp36-cp36m-win_amd64.whl", hash = "sha256:078986caf4d6a602a4257d3686afe4544ea74362b8928e9f4389b5cd262bc215"}, + {file = "netifaces-0.10.9-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:3095218b66d359092b82f07c5422293c2f6559cf8d36b96b379cc4cdc26eeffa"}, + {file = "netifaces-0.10.9-cp37-cp37m-win32.whl", hash = "sha256:da298241d87bcf468aa0f0705ba14572ad296f24c4fda5055d6988701d6fd8e1"}, + {file = "netifaces-0.10.9-cp37-cp37m-win_amd64.whl", hash = "sha256:86b8a140e891bb23c8b9cb1804f1475eb13eea3dbbebef01fcbbf10fbafbee42"}, + {file = "netifaces-0.10.9.tar.gz", hash = "sha256:2dee9ffdd16292878336a58d04a20f0ffe95555465fee7c9bd23b3490ef2abf3"}, +] +notebook = [ + {file = "notebook-6.4.5-py3-none-any.whl", hash = "sha256:f7b4362698fed34f44038de0517b2e5136c1e7c379797198c1736121d3d597bd"}, + {file = "notebook-6.4.5.tar.gz", hash = "sha256:872e20da9ae518bbcac3e4e0092d5bd35454e847dedb8cb9739e9f3b68406be0"}, +] +numpy = [ + {file = "numpy-1.21.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8890b3360f345e8360133bc078d2dacc2843b6ee6059b568781b15b97acbe39f"}, + {file = "numpy-1.21.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:69077388c5a4b997442b843dbdc3a85b420fb693ec8e33020bb24d647c164fa5"}, + {file = "numpy-1.21.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e89717274b41ebd568cd7943fc9418eeb49b1785b66031bc8a7f6300463c5898"}, + {file = "numpy-1.21.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b78ecfa070460104934e2caf51694ccd00f37d5e5dbe76f021b1b0b0d221823"}, + {file = "numpy-1.21.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:615d4e328af7204c13ae3d4df7615a13ff60a49cb0d9106fde07f541207883ca"}, + {file = "numpy-1.21.4-cp310-cp310-win_amd64.whl", hash = "sha256:1403b4e2181fc72664737d848b60e65150f272fe5a1c1cbc16145ed43884065a"}, + {file = "numpy-1.21.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:74b85a17528ca60cf98381a5e779fc0264b4a88b46025e6bcbe9621f46bb3e63"}, + {file = "numpy-1.21.4-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:92aafa03da8658609f59f18722b88f0a73a249101169e28415b4fa148caf7e41"}, + {file = "numpy-1.21.4-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5d95668e727c75b3f5088ec7700e260f90ec83f488e4c0aaccb941148b2cd377"}, + {file = "numpy-1.21.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5162ec777ba7138906c9c274353ece5603646c6965570d82905546579573f73"}, + {file = "numpy-1.21.4-cp37-cp37m-win32.whl", hash = "sha256:81225e58ef5fce7f1d80399575576fc5febec79a8a2742e8ef86d7b03beef49f"}, + {file = "numpy-1.21.4-cp37-cp37m-win_amd64.whl", hash = "sha256:32fe5b12061f6446adcbb32cf4060a14741f9c21e15aaee59a207b6ce6423469"}, + {file = "numpy-1.21.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c449eb870616a7b62e097982c622d2577b3dbc800aaf8689254ec6e0197cbf1e"}, + {file = "numpy-1.21.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2e4ed57f45f0aa38beca2a03b6532e70e548faf2debbeb3291cfc9b315d9be8f"}, + {file = "numpy-1.21.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1247ef28387b7bb7f21caf2dbe4767f4f4175df44d30604d42ad9bd701ebb31f"}, + {file = "numpy-1.21.4-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:34f3456f530ae8b44231c63082c8899fe9c983fd9b108c997c4b1c8c2d435333"}, + {file = "numpy-1.21.4-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4c9c23158b87ed0e70d9a50c67e5c0b3f75bcf2581a8e34668d4e9d7474d76c6"}, + {file = "numpy-1.21.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4799be6a2d7d3c33699a6f77201836ac975b2e1b98c2a07f66a38f499cb50ce"}, + {file = "numpy-1.21.4-cp38-cp38-win32.whl", hash = "sha256:bc988afcea53e6156546e5b2885b7efab089570783d9d82caf1cfd323b0bb3dd"}, + {file = "numpy-1.21.4-cp38-cp38-win_amd64.whl", hash = "sha256:170b2a0805c6891ca78c1d96ee72e4c3ed1ae0a992c75444b6ab20ff038ba2cd"}, + {file = "numpy-1.21.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:fde96af889262e85aa033f8ee1d3241e32bf36228318a61f1ace579df4e8170d"}, + {file = "numpy-1.21.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c885bfc07f77e8fee3dc879152ba993732601f1f11de248d4f357f0ffea6a6d4"}, + {file = "numpy-1.21.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9e6f5f50d1eff2f2f752b3089a118aee1ea0da63d56c44f3865681009b0af162"}, + {file = "numpy-1.21.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ad010846cdffe7ec27e3f933397f8a8d6c801a48634f419e3d075db27acf5880"}, + {file = "numpy-1.21.4-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c74c699b122918a6c4611285cc2cad4a3aafdb135c22a16ec483340ef97d573c"}, + {file = "numpy-1.21.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9864424631775b0c052f3bd98bc2712d131b3e2cd95d1c0c68b91709170890b0"}, + {file = "numpy-1.21.4-cp39-cp39-win32.whl", hash = "sha256:b1e2312f5b8843a3e4e8224b2b48fe16119617b8fc0a54df8f50098721b5bed2"}, + {file = "numpy-1.21.4-cp39-cp39-win_amd64.whl", hash = "sha256:e3c3e990274444031482a31280bf48674441e0a5b55ddb168f3a6db3e0c38ec8"}, + {file = "numpy-1.21.4-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a3deb31bc84f2b42584b8c4001c85d1934dbfb4030827110bc36bfd11509b7bf"}, + {file = "numpy-1.21.4.zip", hash = "sha256:e6c76a87633aa3fa16614b61ccedfae45b91df2767cf097aa9c933932a7ed1e0"}, +] +oauthlib = [ + {file = "oauthlib-3.1.1-py2.py3-none-any.whl", hash = "sha256:42bf6354c2ed8c6acb54d971fce6f88193d97297e18602a3a886603f9d7730cc"}, + {file = "oauthlib-3.1.1.tar.gz", hash = "sha256:8f0215fcc533dd8dd1bee6f4c412d4f0cd7297307d43ac61666389e3bc3198a3"}, +] +opencv-python = [ + {file = "opencv-python-3.4.16.57.tar.gz", hash = "sha256:fa1e5ad9b2cd3b3f83d0ba7aceb20706cd79d91e5028c283d14ef75299203352"}, + {file = "opencv_python-3.4.16.57-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66a7973ff3e39e5b55d5f37dd305189fb6245d7710c7fe3d562aa8df4f89b3bf"}, + {file = "opencv_python-3.4.16.57-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:3eafb8c4e8efb80455648eb845644aa18d7d121d5ac8d01e9ed74236ae8d2cfc"}, + {file = "opencv_python-3.4.16.57-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:6f6d76e06dad8e1432b9dfd9d0ae5b60c54d232a3dce73f17f9ef547e9770d1e"}, + {file = "opencv_python-3.4.16.57-cp310-cp310-win32.whl", hash = "sha256:fd30a0f77dfead731144aae843edd5e2d89fc1b7104147503aaf908b87c8b268"}, + {file = "opencv_python-3.4.16.57-cp310-cp310-win_amd64.whl", hash = "sha256:f47e6d4d61cb90ba9fac0cc0d80a35b71f3db32341f1fb67a39730b4e31c9985"}, + {file = "opencv_python-3.4.16.57-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:11351d0990e0994b1e5cbf02da248746d6c1e5c05dacf8d149607c8d8eb4e763"}, + {file = "opencv_python-3.4.16.57-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:fde2cb8ee6aa15417996140e18703e63db9b460bb467709e4e91966f7dac99fc"}, + {file = "opencv_python-3.4.16.57-cp36-cp36m-win32.whl", hash = "sha256:ba31e3debe484ef902be06f681d795f86ec6493780b902e1dd12c25037f482f4"}, + {file = "opencv_python-3.4.16.57-cp36-cp36m-win_amd64.whl", hash = "sha256:c221511f3eec66a5c2ef34706b5bad5181506e46b2a8c3c2840f381dfb4ce261"}, + {file = "opencv_python-3.4.16.57-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:0859665853dee1e3ae4ed21b6d1218c85378f6cfc2a6aa9fbb5e5306beda0bac"}, + {file = "opencv_python-3.4.16.57-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:8c52c5eabd6fc5488f76a65caa8db0b253316ce9ed78870b8472e96a426c7cec"}, + {file = "opencv_python-3.4.16.57-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:4cba52764275f0d23e65ed3ded7aa7cd4975339cd47d88ddb073aeb0853f51f3"}, + {file = "opencv_python-3.4.16.57-cp37-cp37m-win32.whl", hash = "sha256:9936248c3f17fcfda434934a0b104c6652330cdd05c388de165a4811b9178c75"}, + {file = "opencv_python-3.4.16.57-cp37-cp37m-win_amd64.whl", hash = "sha256:7db9ef3272d1becbd6752a7537539a6fba7872822451841edc8a68d18a193610"}, + {file = "opencv_python-3.4.16.57-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:598f9682bf9a30a1e0c142123c8c30bb870c58ee2e1d7f049ca2dd5f46fd5fab"}, + {file = "opencv_python-3.4.16.57-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fc695fa8c95145fd74c6cd7c61f2bbdae8992ffa1754eb887b62ffc0fdb9f1d6"}, + {file = "opencv_python-3.4.16.57-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:fedba9f88f1b0a495cd46e6467808c028b38225c74a72416f2b6f765d47f0528"}, + {file = "opencv_python-3.4.16.57-cp38-cp38-win32.whl", hash = "sha256:b8562ac95a2c5ab991e49b706174ec5bf311833fc649dcd1d7f9554cbc48a731"}, + {file = "opencv_python-3.4.16.57-cp38-cp38-win_amd64.whl", hash = "sha256:2db066d915ffd7f8b596151ef4260cbe364160e5fb056322094fc7fbfc42cd07"}, + {file = "opencv_python-3.4.16.57-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:1b21211a2b69109aa1b5092957f3ee7811b5a44548de1c245d4ade4e36fd7982"}, + {file = "opencv_python-3.4.16.57-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccb127cc16d214287a36f689a1a5bb5087ba3740846cb228ae7a71873702b978"}, + {file = "opencv_python-3.4.16.57-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80b25549d5182fddcb292731cf132acf91fc6957f2e53b39f98f1729a1d64646"}, + {file = "opencv_python-3.4.16.57-cp39-cp39-win32.whl", hash = "sha256:f2d293a7b5bb1abe953634ee0a22fc589cbbe3934c7495bdb0882227ca267ea9"}, + {file = "opencv_python-3.4.16.57-cp39-cp39-win_amd64.whl", hash = "sha256:e41c3a74e7a57ef3b9edc40737e9af47d0c8aa55a78a7beb63f120291cbfbc80"}, +] +packaging = [ + {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"}, + {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"}, +] +pandas = [ + {file = "pandas-1.3.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9707bdc1ea9639c886b4d3be6e2a45812c1ac0c2080f94c31b71c9fa35556f9b"}, + {file = "pandas-1.3.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c2f44425594ae85e119459bb5abb0748d76ef01d9c08583a667e3339e134218e"}, + {file = "pandas-1.3.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:372d72a3d8a5f2dbaf566a5fa5fa7f230842ac80f29a931fb4b071502cf86b9a"}, + {file = "pandas-1.3.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d99d2350adb7b6c3f7f8f0e5dfb7d34ff8dd4bc0a53e62c445b7e43e163fce63"}, + {file = "pandas-1.3.4-cp310-cp310-win_amd64.whl", hash = "sha256:4acc28364863127bca1029fb72228e6f473bb50c32e77155e80b410e2068eeac"}, + {file = "pandas-1.3.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c2646458e1dce44df9f71a01dc65f7e8fa4307f29e5c0f2f92c97f47a5bf22f5"}, + {file = "pandas-1.3.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5298a733e5bfbb761181fd4672c36d0c627320eb999c59c65156c6a90c7e1b4f"}, + {file = "pandas-1.3.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22808afb8f96e2269dcc5b846decacb2f526dd0b47baebc63d913bf847317c8f"}, + {file = "pandas-1.3.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b528e126c13816a4374e56b7b18bfe91f7a7f6576d1aadba5dee6a87a7f479ae"}, + {file = "pandas-1.3.4-cp37-cp37m-win32.whl", hash = "sha256:fe48e4925455c964db914b958f6e7032d285848b7538a5e1b19aeb26ffaea3ec"}, + {file = "pandas-1.3.4-cp37-cp37m-win_amd64.whl", hash = "sha256:eaca36a80acaacb8183930e2e5ad7f71539a66805d6204ea88736570b2876a7b"}, + {file = "pandas-1.3.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:42493f8ae67918bf129869abea8204df899902287a7f5eaf596c8e54e0ac7ff4"}, + {file = "pandas-1.3.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a388960f979665b447f0847626e40f99af8cf191bce9dc571d716433130cb3a7"}, + {file = "pandas-1.3.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ba0aac1397e1d7b654fccf263a4798a9e84ef749866060d19e577e927d66e1b"}, + {file = "pandas-1.3.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f567e972dce3bbc3a8076e0b675273b4a9e8576ac629149cf8286ee13c259ae5"}, + {file = "pandas-1.3.4-cp38-cp38-win32.whl", hash = "sha256:c1aa4de4919358c5ef119f6377bc5964b3a7023c23e845d9db7d9016fa0c5b1c"}, + {file = "pandas-1.3.4-cp38-cp38-win_amd64.whl", hash = "sha256:dd324f8ee05925ee85de0ea3f0d66e1362e8c80799eb4eb04927d32335a3e44a"}, + {file = "pandas-1.3.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d47750cf07dee6b55d8423471be70d627314277976ff2edd1381f02d52dbadf9"}, + {file = "pandas-1.3.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d1dc09c0013d8faa7474574d61b575f9af6257ab95c93dcf33a14fd8d2c1bab"}, + {file = "pandas-1.3.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10e10a2527db79af6e830c3d5842a4d60383b162885270f8cffc15abca4ba4a9"}, + {file = "pandas-1.3.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35c77609acd2e4d517da41bae0c11c70d31c87aae8dd1aabd2670906c6d2c143"}, + {file = "pandas-1.3.4-cp39-cp39-win32.whl", hash = "sha256:003ba92db58b71a5f8add604a17a059f3068ef4e8c0c365b088468d0d64935fd"}, + {file = "pandas-1.3.4-cp39-cp39-win_amd64.whl", hash = "sha256:a51528192755f7429c5bcc9e80832c517340317c861318fea9cea081b57c9afd"}, + {file = "pandas-1.3.4.tar.gz", hash = "sha256:a2aa18d3f0b7d538e21932f637fbfe8518d085238b429e4790a35e1e44a96ffc"}, +] +pandocfilters = [ + {file = "pandocfilters-1.5.0-py2.py3-none-any.whl", hash = "sha256:33aae3f25fd1a026079f5d27bdd52496f0e0803b3469282162bafdcbdf6ef14f"}, + {file = "pandocfilters-1.5.0.tar.gz", hash = "sha256:0b679503337d233b4339a817bfc8c50064e2eff681314376a47cb582305a7a38"}, +] +parso = [ + {file = "parso-0.8.2-py2.py3-none-any.whl", hash = "sha256:a8c4922db71e4fdb90e0d0bc6e50f9b273d3397925e5e60a717e719201778d22"}, + {file = "parso-0.8.2.tar.gz", hash = "sha256:12b83492c6239ce32ff5eed6d3639d6a536170723c6f3f1506869f1ace413398"}, +] +pathlib = [ + {file = "pathlib-1.0.1-py3-none-any.whl", hash = "sha256:f35f95ab8b0f59e6d354090350b44a80a80635d22efdedfa84c7ad1cf0a74147"}, + {file = "pathlib-1.0.1.tar.gz", hash = "sha256:6940718dfc3eff4258203ad5021090933e5c04707d5ca8cc9e73c94a7894ea9f"}, +] +pathspec = [ + {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, + {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, +] +pdoc3 = [ + {file = "pdoc3-0.10.0-py3-none-any.whl", hash = "sha256:ba45d1ada1bd987427d2bf5cdec30b2631a3ff5fb01f6d0e77648a572ce6028b"}, + {file = "pdoc3-0.10.0.tar.gz", hash = "sha256:5f22e7bcb969006738e1aa4219c75a32f34c2d62d46dc9d2fb2d3e0b0287e4b7"}, +] +pettingzoo = [ + {file = "PettingZoo-1.13.1.tar.gz", hash = "sha256:b95d0a9e6e2ca61188ad0b72a2bc4b68a3b21ca0c85d0971e42c9c71c66abd73"}, +] +pexpect = [ + {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, + {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, +] +pickleshare = [ + {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, + {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, +] +pillow = [ + {file = "Pillow-8.4.0-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:81f8d5c81e483a9442d72d182e1fb6dcb9723f289a57e8030811bac9ea3fef8d"}, + {file = "Pillow-8.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3f97cfb1e5a392d75dd8b9fd274d205404729923840ca94ca45a0af57e13dbe6"}, + {file = "Pillow-8.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb9fc393f3c61f9054e1ed26e6fe912c7321af2f41ff49d3f83d05bacf22cc78"}, + {file = "Pillow-8.4.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d82cdb63100ef5eedb8391732375e6d05993b765f72cb34311fab92103314649"}, + {file = "Pillow-8.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62cc1afda735a8d109007164714e73771b499768b9bb5afcbbee9d0ff374b43f"}, + {file = "Pillow-8.4.0-cp310-cp310-win32.whl", hash = "sha256:e3dacecfbeec9a33e932f00c6cd7996e62f53ad46fbe677577394aaa90ee419a"}, + {file = "Pillow-8.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:620582db2a85b2df5f8a82ddeb52116560d7e5e6b055095f04ad828d1b0baa39"}, + {file = "Pillow-8.4.0-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:1bc723b434fbc4ab50bb68e11e93ce5fb69866ad621e3c2c9bdb0cd70e345f55"}, + {file = "Pillow-8.4.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:72cbcfd54df6caf85cc35264c77ede902452d6df41166010262374155947460c"}, + {file = "Pillow-8.4.0-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70ad9e5c6cb9b8487280a02c0ad8a51581dcbbe8484ce058477692a27c151c0a"}, + {file = "Pillow-8.4.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25a49dc2e2f74e65efaa32b153527fc5ac98508d502fa46e74fa4fd678ed6645"}, + {file = "Pillow-8.4.0-cp36-cp36m-win32.whl", hash = "sha256:93ce9e955cc95959df98505e4608ad98281fff037350d8c2671c9aa86bcf10a9"}, + {file = "Pillow-8.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:2e4440b8f00f504ee4b53fe30f4e381aae30b0568193be305256b1462216feff"}, + {file = "Pillow-8.4.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:8c803ac3c28bbc53763e6825746f05cc407b20e4a69d0122e526a582e3b5e153"}, + {file = "Pillow-8.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8a17b5d948f4ceeceb66384727dde11b240736fddeda54ca740b9b8b1556b29"}, + {file = "Pillow-8.4.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1394a6ad5abc838c5cd8a92c5a07535648cdf6d09e8e2d6df916dfa9ea86ead8"}, + {file = "Pillow-8.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:792e5c12376594bfcb986ebf3855aa4b7c225754e9a9521298e460e92fb4a488"}, + {file = "Pillow-8.4.0-cp37-cp37m-win32.whl", hash = "sha256:d99ec152570e4196772e7a8e4ba5320d2d27bf22fdf11743dd882936ed64305b"}, + {file = "Pillow-8.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:7b7017b61bbcdd7f6363aeceb881e23c46583739cb69a3ab39cb384f6ec82e5b"}, + {file = "Pillow-8.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:d89363f02658e253dbd171f7c3716a5d340a24ee82d38aab9183f7fdf0cdca49"}, + {file = "Pillow-8.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0a0956fdc5defc34462bb1c765ee88d933239f9a94bc37d132004775241a7585"}, + {file = "Pillow-8.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b7bb9de00197fb4261825c15551adf7605cf14a80badf1761d61e59da347779"}, + {file = "Pillow-8.4.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72b9e656e340447f827885b8d7a15fc8c4e68d410dc2297ef6787eec0f0ea409"}, + {file = "Pillow-8.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5a4532a12314149d8b4e4ad8ff09dde7427731fcfa5917ff16d0291f13609df"}, + {file = "Pillow-8.4.0-cp38-cp38-win32.whl", hash = "sha256:82aafa8d5eb68c8463b6e9baeb4f19043bb31fefc03eb7b216b51e6a9981ae09"}, + {file = "Pillow-8.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:066f3999cb3b070a95c3652712cffa1a748cd02d60ad7b4e485c3748a04d9d76"}, + {file = "Pillow-8.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:5503c86916d27c2e101b7f71c2ae2cddba01a2cf55b8395b0255fd33fa4d1f1a"}, + {file = "Pillow-8.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4acc0985ddf39d1bc969a9220b51d94ed51695d455c228d8ac29fcdb25810e6e"}, + {file = "Pillow-8.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b052a619a8bfcf26bd8b3f48f45283f9e977890263e4571f2393ed8898d331b"}, + {file = "Pillow-8.4.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:493cb4e415f44cd601fcec11c99836f707bb714ab03f5ed46ac25713baf0ff20"}, + {file = "Pillow-8.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8831cb7332eda5dc89b21a7bce7ef6ad305548820595033a4b03cf3091235ed"}, + {file = "Pillow-8.4.0-cp39-cp39-win32.whl", hash = "sha256:5e9ac5f66616b87d4da618a20ab0a38324dbe88d8a39b55be8964eb520021e02"}, + {file = "Pillow-8.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:3eb1ce5f65908556c2d8685a8f0a6e989d887ec4057326f6c22b24e8a172c66b"}, + {file = "Pillow-8.4.0-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:ddc4d832a0f0b4c52fff973a0d44b6c99839a9d016fe4e6a1cb8f3eea96479c2"}, + {file = "Pillow-8.4.0-pp36-pypy36_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a3e5ddc44c14042f0844b8cf7d2cd455f6cc80fd7f5eefbe657292cf601d9ad"}, + {file = "Pillow-8.4.0-pp36-pypy36_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c70e94281588ef053ae8998039610dbd71bc509e4acbc77ab59d7d2937b10698"}, + {file = "Pillow-8.4.0-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:3862b7256046fcd950618ed22d1d60b842e3a40a48236a5498746f21189afbbc"}, + {file = "Pillow-8.4.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4901622493f88b1a29bd30ec1a2f683782e57c3c16a2dbc7f2595ba01f639df"}, + {file = "Pillow-8.4.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84c471a734240653a0ec91dec0996696eea227eafe72a33bd06c92697728046b"}, + {file = "Pillow-8.4.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:244cf3b97802c34c41905d22810846802a3329ddcb93ccc432870243211c79fc"}, + {file = "Pillow-8.4.0.tar.gz", hash = "sha256:b8e2f83c56e141920c39464b852de3719dfbfb6e3c99a2d8da0edf4fb33176ed"}, +] +platformdirs = [ + {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, + {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, +] +prometheus-client = [ + {file = "prometheus_client-0.12.0-py2.py3-none-any.whl", hash = "sha256:317453ebabff0a1b02df7f708efbab21e3489e7072b61cb6957230dd004a0af0"}, + {file = "prometheus_client-0.12.0.tar.gz", hash = "sha256:1b12ba48cee33b9b0b9de64a1047cbd3c5f2d0ab6ebcead7ddda613a750ec3c5"}, +] +prompt-toolkit = [ + {file = "prompt_toolkit-3.0.22-py3-none-any.whl", hash = "sha256:48d85cdca8b6c4f16480c7ce03fd193666b62b0a21667ca56b4bb5ad679d1170"}, + {file = "prompt_toolkit-3.0.22.tar.gz", hash = "sha256:449f333dd120bd01f5d296a8ce1452114ba3a71fae7288d2f0ae2c918764fa72"}, +] +protobuf = [ + {file = "protobuf-3.19.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d80f80eb175bf5f1169139c2e0c5ada98b1c098e2b3c3736667f28cbbea39fc8"}, + {file = "protobuf-3.19.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:a529e7df52204565bcd33738a7a5f288f3d2d37d86caa5d78c458fa5fabbd54d"}, + {file = "protobuf-3.19.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28ccea56d4dc38d35cd70c43c2da2f40ac0be0a355ef882242e8586c6d66666f"}, + {file = "protobuf-3.19.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b30a7de128c46b5ecb343917d9fa737612a6e8280f440874e5cc2ba0d79b8f6"}, + {file = "protobuf-3.19.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5935c8ce02e3d89c7900140a8a42b35bc037ec07a6aeb61cc108be8d3c9438a6"}, + {file = "protobuf-3.19.1-cp36-cp36m-win32.whl", hash = "sha256:74f33edeb4f3b7ed13d567881da8e5a92a72b36495d57d696c2ea1ae0cfee80c"}, + {file = "protobuf-3.19.1-cp36-cp36m-win_amd64.whl", hash = "sha256:038daf4fa38a7e818dd61f51f22588d61755160a98db087a046f80d66b855942"}, + {file = "protobuf-3.19.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e51561d72efd5bd5c91490af1f13e32bcba8dab4643761eb7de3ce18e64a853"}, + {file = "protobuf-3.19.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:6e8ea9173403219239cdfd8d946ed101f2ab6ecc025b0fda0c6c713c35c9981d"}, + {file = "protobuf-3.19.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db3532d9f7a6ebbe2392041350437953b6d7a792de10e629c1e4f5a6b1fe1ac6"}, + {file = "protobuf-3.19.1-cp37-cp37m-win32.whl", hash = "sha256:615b426a177780ce381ecd212edc1e0f70db8557ed72560b82096bd36b01bc04"}, + {file = "protobuf-3.19.1-cp37-cp37m-win_amd64.whl", hash = "sha256:d8919368410110633717c406ab5c97e8df5ce93020cfcf3012834f28b1fab1ea"}, + {file = "protobuf-3.19.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:71b0250b0cfb738442d60cab68abc166de43411f2a4f791d31378590bfb71bd7"}, + {file = "protobuf-3.19.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:3cd0458870ea7d1c58e948ac8078f6ba8a7ecc44a57e03032ed066c5bb318089"}, + {file = "protobuf-3.19.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:655264ed0d0efe47a523e2255fc1106a22f6faab7cc46cfe99b5bae085c2a13e"}, + {file = "protobuf-3.19.1-cp38-cp38-win32.whl", hash = "sha256:b691d996c6d0984947c4cf8b7ae2fe372d99b32821d0584f0b90277aa36982d3"}, + {file = "protobuf-3.19.1-cp38-cp38-win_amd64.whl", hash = "sha256:e7e8d2c20921f8da0dea277dfefc6abac05903ceac8e72839b2da519db69206b"}, + {file = "protobuf-3.19.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fd390367fc211cc0ffcf3a9e149dfeca78fecc62adb911371db0cec5c8b7472d"}, + {file = "protobuf-3.19.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d83e1ef8cb74009bebee3e61cc84b1c9cd04935b72bca0cbc83217d140424995"}, + {file = "protobuf-3.19.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36d90676d6f426718463fe382ec6274909337ca6319d375eebd2044e6c6ac560"}, + {file = "protobuf-3.19.1-cp39-cp39-win32.whl", hash = "sha256:e7b24c11df36ee8e0c085e5b0dc560289e4b58804746fb487287dda51410f1e2"}, + {file = "protobuf-3.19.1-cp39-cp39-win_amd64.whl", hash = "sha256:77d2fadcf369b3f22859ab25bd12bb8e98fb11e05d9ff9b7cd45b711c719c002"}, + {file = "protobuf-3.19.1-py2.py3-none-any.whl", hash = "sha256:e813b1c9006b6399308e917ac5d298f345d95bb31f46f02b60cd92970a9afa17"}, + {file = "protobuf-3.19.1.tar.gz", hash = "sha256:62a8e4baa9cb9e064eb62d1002eca820857ab2138440cb4b3ea4243830f94ca7"}, +] +psutil = [ + {file = "psutil-5.8.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:0066a82f7b1b37d334e68697faba68e5ad5e858279fd6351c8ca6024e8d6ba64"}, + {file = "psutil-5.8.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:0ae6f386d8d297177fd288be6e8d1afc05966878704dad9847719650e44fc49c"}, + {file = "psutil-5.8.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:12d844996d6c2b1d3881cfa6fa201fd635971869a9da945cf6756105af73d2df"}, + {file = "psutil-5.8.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:02b8292609b1f7fcb34173b25e48d0da8667bc85f81d7476584d889c6e0f2131"}, + {file = "psutil-5.8.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6ffe81843131ee0ffa02c317186ed1e759a145267d54fdef1bc4ea5f5931ab60"}, + {file = "psutil-5.8.0-cp27-none-win32.whl", hash = "sha256:ea313bb02e5e25224e518e4352af4bf5e062755160f77e4b1767dd5ccb65f876"}, + {file = "psutil-5.8.0-cp27-none-win_amd64.whl", hash = "sha256:5da29e394bdedd9144c7331192e20c1f79283fb03b06e6abd3a8ae45ffecee65"}, + {file = "psutil-5.8.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:74fb2557d1430fff18ff0d72613c5ca30c45cdbfcddd6a5773e9fc1fe9364be8"}, + {file = "psutil-5.8.0-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:74f2d0be88db96ada78756cb3a3e1b107ce8ab79f65aa885f76d7664e56928f6"}, + {file = "psutil-5.8.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:99de3e8739258b3c3e8669cb9757c9a861b2a25ad0955f8e53ac662d66de61ac"}, + {file = "psutil-5.8.0-cp36-cp36m-win32.whl", hash = "sha256:36b3b6c9e2a34b7d7fbae330a85bf72c30b1c827a4366a07443fc4b6270449e2"}, + {file = "psutil-5.8.0-cp36-cp36m-win_amd64.whl", hash = "sha256:52de075468cd394ac98c66f9ca33b2f54ae1d9bff1ef6b67a212ee8f639ec06d"}, + {file = "psutil-5.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c6a5fd10ce6b6344e616cf01cc5b849fa8103fbb5ba507b6b2dee4c11e84c935"}, + {file = "psutil-5.8.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:61f05864b42fedc0771d6d8e49c35f07efd209ade09a5afe6a5059e7bb7bf83d"}, + {file = "psutil-5.8.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:0dd4465a039d343925cdc29023bb6960ccf4e74a65ad53e768403746a9207023"}, + {file = "psutil-5.8.0-cp37-cp37m-win32.whl", hash = "sha256:1bff0d07e76114ec24ee32e7f7f8d0c4b0514b3fae93e3d2aaafd65d22502394"}, + {file = "psutil-5.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:fcc01e900c1d7bee2a37e5d6e4f9194760a93597c97fee89c4ae51701de03563"}, + {file = "psutil-5.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6223d07a1ae93f86451d0198a0c361032c4c93ebd4bf6d25e2fb3edfad9571ef"}, + {file = "psutil-5.8.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d225cd8319aa1d3c85bf195c4e07d17d3cd68636b8fc97e6cf198f782f99af28"}, + {file = "psutil-5.8.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:28ff7c95293ae74bf1ca1a79e8805fcde005c18a122ca983abf676ea3466362b"}, + {file = "psutil-5.8.0-cp38-cp38-win32.whl", hash = "sha256:ce8b867423291cb65cfc6d9c4955ee9bfc1e21fe03bb50e177f2b957f1c2469d"}, + {file = "psutil-5.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:90f31c34d25b1b3ed6c40cdd34ff122b1887a825297c017e4cbd6796dd8b672d"}, + {file = "psutil-5.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6323d5d845c2785efb20aded4726636546b26d3b577aded22492908f7c1bdda7"}, + {file = "psutil-5.8.0-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:245b5509968ac0bd179287d91210cd3f37add77dad385ef238b275bad35fa1c4"}, + {file = "psutil-5.8.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:90d4091c2d30ddd0a03e0b97e6a33a48628469b99585e2ad6bf21f17423b112b"}, + {file = "psutil-5.8.0-cp39-cp39-win32.whl", hash = "sha256:ea372bcc129394485824ae3e3ddabe67dc0b118d262c568b4d2602a7070afdb0"}, + {file = "psutil-5.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:f4634b033faf0d968bb9220dd1c793b897ab7f1189956e1aa9eae752527127d3"}, + {file = "psutil-5.8.0.tar.gz", hash = "sha256:0c9ccb99ab76025f2f0bbecf341d4656e9c1351db8cc8a03ccd62e318ab4b5c6"}, +] +ptyprocess = [ + {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, + {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, +] +py = [ + {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, + {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, +] +pyasn1 = [ + {file = "pyasn1-0.4.8-py2.4.egg", hash = "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"}, + {file = "pyasn1-0.4.8-py2.5.egg", hash = "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf"}, + {file = "pyasn1-0.4.8-py2.6.egg", hash = "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00"}, + {file = "pyasn1-0.4.8-py2.7.egg", hash = "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8"}, + {file = "pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"}, + {file = "pyasn1-0.4.8-py3.1.egg", hash = "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86"}, + {file = "pyasn1-0.4.8-py3.2.egg", hash = "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7"}, + {file = "pyasn1-0.4.8-py3.3.egg", hash = "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576"}, + {file = "pyasn1-0.4.8-py3.4.egg", hash = "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12"}, + {file = "pyasn1-0.4.8-py3.5.egg", hash = "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2"}, + {file = "pyasn1-0.4.8-py3.6.egg", hash = "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359"}, + {file = "pyasn1-0.4.8-py3.7.egg", hash = "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776"}, + {file = "pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"}, +] +pyasn1-modules = [ + {file = "pyasn1-modules-0.2.8.tar.gz", hash = "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e"}, + {file = "pyasn1_modules-0.2.8-py2.4.egg", hash = "sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199"}, + {file = "pyasn1_modules-0.2.8-py2.5.egg", hash = "sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405"}, + {file = "pyasn1_modules-0.2.8-py2.6.egg", hash = "sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb"}, + {file = "pyasn1_modules-0.2.8-py2.7.egg", hash = "sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8"}, + {file = "pyasn1_modules-0.2.8-py2.py3-none-any.whl", hash = "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74"}, + {file = "pyasn1_modules-0.2.8-py3.1.egg", hash = "sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d"}, + {file = "pyasn1_modules-0.2.8-py3.2.egg", hash = "sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45"}, + {file = "pyasn1_modules-0.2.8-py3.3.egg", hash = "sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4"}, + {file = "pyasn1_modules-0.2.8-py3.4.egg", hash = "sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811"}, + {file = "pyasn1_modules-0.2.8-py3.5.egg", hash = "sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed"}, + {file = "pyasn1_modules-0.2.8-py3.6.egg", hash = "sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0"}, + {file = "pyasn1_modules-0.2.8-py3.7.egg", hash = "sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd"}, +] +pycparser = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] +pycryptodome = [ + {file = "pycryptodome-3.11.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ffd0cac13ff41f2d15ed39dc6ba1d2ad88dd2905d656c33d8235852f5d6151fd"}, + {file = "pycryptodome-3.11.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:ead516e03dfe062aefeafe4a29445a6449b0fc43bc8cb30194b2754917a63798"}, + {file = "pycryptodome-3.11.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:4ce6b09547bf2c7cede3a017f79502eaed3e819c13cdb3cb357aea1b004e4cc6"}, + {file = "pycryptodome-3.11.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:014c758af7fa38cab85b357a496b76f4fc9dda1f731eb28358d66fef7ad4a3e1"}, + {file = "pycryptodome-3.11.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:a843350d08c3d22f6c09c2f17f020d8dcfa59496165d7425a3fba0045543dda7"}, + {file = "pycryptodome-3.11.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:53989477044be41fa4a63da09d5038c2a34b2f4554cfea2e3933b17186ee9e19"}, + {file = "pycryptodome-3.11.0-cp27-cp27m-win32.whl", hash = "sha256:f9bad2220b80b4ed74f089db012ab5ab5419143a33fad6c8aedcc2a9341eac70"}, + {file = "pycryptodome-3.11.0-cp27-cp27m-win_amd64.whl", hash = "sha256:3c7ed5b07274535979c730daf5817db5e983ea80b04c22579eee8da4ca3ae4f8"}, + {file = "pycryptodome-3.11.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:8f3a60926be78422e662b0d0b18351b426ce27657101c8a50bad80300de6a701"}, + {file = "pycryptodome-3.11.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:fce7e22d96030b35345637c563246c24d4513bd3b413e1c40293114837ab8912"}, + {file = "pycryptodome-3.11.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:bc3c61ff92efdcc14af4a7b81da71d849c9acee51d8fd8ac9841a7620140d6c6"}, + {file = "pycryptodome-3.11.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:b33c9b3d1327d821e28e9cc3a6512c14f8b17570ddb4cfb9a52247ed0fcc5d8b"}, + {file = "pycryptodome-3.11.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:75e78360d1dd6d02eb288fd8275bb4d147d6e3f5337935c096d11dba1fa84748"}, + {file = "pycryptodome-3.11.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:621a90147a5e255fdc2a0fec2d56626b76b5d72ea9e60164c9a5a8976d45b0c9"}, + {file = "pycryptodome-3.11.0-cp35-abi3-manylinux1_i686.whl", hash = "sha256:0ca7a6b4fc1f9fafe990b95c8cda89099797e2cfbf40e55607f2f2f5a3355dcb"}, + {file = "pycryptodome-3.11.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:b59bf823cfafde8ef1105d8984f26d1694dff165adb7198b12e3e068d7999b15"}, + {file = "pycryptodome-3.11.0-cp35-abi3-manylinux2010_i686.whl", hash = "sha256:ce81b9c6aaa0f920e2ab05eb2b9f4ccd102e3016b2f37125593b16a83a4b0cc2"}, + {file = "pycryptodome-3.11.0-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:ae29fcd56152f417bfba50a36a56a7a5f9fb74ff80bab98704cac704de6568ab"}, + {file = "pycryptodome-3.11.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:ae31cb874f6f0cedbed457c6374e7e54d7ed45c1a4e11a65a9c80968da90a650"}, + {file = "pycryptodome-3.11.0-cp35-abi3-win32.whl", hash = "sha256:6db1f9fa1f52226621905f004278ce7bd90c8f5363ffd5d7ab3755363d98549a"}, + {file = "pycryptodome-3.11.0-cp35-abi3-win_amd64.whl", hash = "sha256:d7e5f6f692421e5219aa3b545eb0cffd832cd589a4b9dcd4a5eb4260e2c0d68a"}, + {file = "pycryptodome-3.11.0-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:da796e9221dda61a0019d01742337eb8a322de8598b678a4344ca0a436380315"}, + {file = "pycryptodome-3.11.0-pp27-pypy_73-manylinux1_x86_64.whl", hash = "sha256:ed45ef92d21db33685b789de2c015e9d9a18a74760a8df1fc152faee88cdf741"}, + {file = "pycryptodome-3.11.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:4169ed515742425ff21e4bd3fabbb6994ffb64434472fb72230019bdfa36b939"}, + {file = "pycryptodome-3.11.0-pp27-pypy_73-win32.whl", hash = "sha256:f19edd42368e9057c39492947bb99570dc927123e210008f2af7cf9b505c6892"}, + {file = "pycryptodome-3.11.0-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:06162fcfed2f9deee8383fd59eaeabc7b7ffc3af50d3fad4000032deb8f700b0"}, + {file = "pycryptodome-3.11.0-pp36-pypy36_pp73-manylinux1_x86_64.whl", hash = "sha256:6eda8a3157c91ba60b26a07bedd6c44ab8bda6cd79b6b5ea9744ba62c39b7b1e"}, + {file = "pycryptodome-3.11.0-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:7ff701fc283412e651eaab4319b3cd4eaa0827e94569cd37ee9075d5c05fe655"}, + {file = "pycryptodome-3.11.0-pp36-pypy36_pp73-win32.whl", hash = "sha256:2a4bcc8a9977fee0979079cd33a9e9f0d3ddba5660d35ffe874cf84f1dd399d2"}, + {file = "pycryptodome-3.11.0.tar.gz", hash = "sha256:428096bbf7a77e207f418dfd4d7c284df8ade81d2dc80f010e92753a3e406ad0"}, +] +pycryptodomex = [ + {file = "pycryptodomex-3.11.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:7abfd84a362e4411f7c5f5758c18cbf377a2a2be64b9232e78544d75640c677e"}, + {file = "pycryptodomex-3.11.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:6a76d7821ae43df8a0e814cca32114875916b9fc2158603b364853de37eb9002"}, + {file = "pycryptodomex-3.11.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:1580db5878b1d16a233550829f7c189c43005f7aa818f2f95c7dddbd6a7163cc"}, + {file = "pycryptodomex-3.11.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:c825611a951baad63faeb9ef1517ef96a20202d6029ae2485b729152cc703fab"}, + {file = "pycryptodomex-3.11.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:7cc5ee80b2d5ee8f59a761741cfb916a068c97cac5e700c8ce01e1927616aa2f"}, + {file = "pycryptodomex-3.11.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:fbe09e3ae95f47c7551a24781d2e348974cde4a0b33bc3b1566f6216479db2b1"}, + {file = "pycryptodomex-3.11.0-cp27-cp27m-win32.whl", hash = "sha256:9eace1e5420abc4f9e76de01e49caca349b7c80bda9c1643193e23a06c2a332c"}, + {file = "pycryptodomex-3.11.0-cp27-cp27m-win_amd64.whl", hash = "sha256:adc25aa8cfc537373dd46ae97863f16fd955edee14bf54d3eb52bde4e4ac8c7b"}, + {file = "pycryptodomex-3.11.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cf30b5e03d974874185b989839c396d799f6e2d4b4d5b2d8bd3ba464eb3cc33f"}, + {file = "pycryptodomex-3.11.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:c91772cf6808cc2d80279e80b491c48cb688797b6d914ff624ca95d855c24ee5"}, + {file = "pycryptodomex-3.11.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:c391ec5c423a374a36b90f7c8805fdf51a0410a2b5be9cebd8990e0021cb6da4"}, + {file = "pycryptodomex-3.11.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:64a83ab6f54496ab968a6f21a41a620afe0a742573d609fd03dcab7210645153"}, + {file = "pycryptodomex-3.11.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:252ac9c1e1ae1c256a75539e234be3096f2d100b9f4bae42ef88067787b9b249"}, + {file = "pycryptodomex-3.11.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:bf2ea67eaa1fff0aecef6da881144f0f91e314b4123491f9a4fa8df0598e48fe"}, + {file = "pycryptodomex-3.11.0-cp35-abi3-manylinux1_i686.whl", hash = "sha256:fe2b8c464ba335e71aed74f830bf2b2881913f8905d166f9c0fe06ca44a1cb5e"}, + {file = "pycryptodomex-3.11.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:ff0826f3886e85708a0e8ef7ec47020723b998cfed6ae47962d915fcb89ec780"}, + {file = "pycryptodomex-3.11.0-cp35-abi3-manylinux2010_i686.whl", hash = "sha256:1d4d13c59d2cfbc0863c725f5812d66ff0d6836ba738ef26a52e1291056a1c7c"}, + {file = "pycryptodomex-3.11.0-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:2b586d13ef07fa6197b6348a48dbbe9525f4f496205de14edfa4e91d99e69672"}, + {file = "pycryptodomex-3.11.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:f35ccfa44a1dd267e392cd76d8525cfcfabee61dd070e15ad2119c54c0c31ddf"}, + {file = "pycryptodomex-3.11.0-cp35-abi3-win32.whl", hash = "sha256:5baf690d27f39f2ba22f06e8e32c5f1972573ca65db6bdbb8b2c7177a0112dab"}, + {file = "pycryptodomex-3.11.0-cp35-abi3-win_amd64.whl", hash = "sha256:919cadcedad552e78349d1626115cfd246fc03ad469a4a62c91a12204f0f0d85"}, + {file = "pycryptodomex-3.11.0-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:c10b2f6bcbaa9aa51fe08207654100074786d423b03482c0cbe44406ca92d146"}, + {file = "pycryptodomex-3.11.0-pp27-pypy_73-manylinux1_x86_64.whl", hash = "sha256:91662b27f5aa8a6d2ad63be9a7d1a403e07bf3c2c5b265a7cc5cbadf6f988e06"}, + {file = "pycryptodomex-3.11.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:207e53bdbf3a26de6e9dcf3ebaf67ba70a61f733f84c464eca55d278211c1b71"}, + {file = "pycryptodomex-3.11.0-pp27-pypy_73-win32.whl", hash = "sha256:1dd4271d8d022216533c3547f071662b44d703fd5dbb632c4b5e77b3ee47567f"}, + {file = "pycryptodomex-3.11.0-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c43ddcff251e8b427b3e414b026636617276e008a9d78a44a9195d4bdfcaa0fe"}, + {file = "pycryptodomex-3.11.0-pp36-pypy36_pp73-manylinux1_x86_64.whl", hash = "sha256:ef25d682d0d9ab25c5022a298b5cba9084c7b148a3e71846df2c67ea664eacc7"}, + {file = "pycryptodomex-3.11.0-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:4c7c6418a3c08b2ebfc2cf50ce52de267618063b533083a2c73b40ec54a1b6f5"}, + {file = "pycryptodomex-3.11.0-pp36-pypy36_pp73-win32.whl", hash = "sha256:15d25c532de744648f0976c56bd10d07b2a44b7eb2a6261ffe2497980b1102d8"}, + {file = "pycryptodomex-3.11.0.tar.gz", hash = "sha256:0398366656bb55ebdb1d1d493a7175fc48ade449283086db254ac44c7d318d6d"}, +] +pygments = [ + {file = "Pygments-2.10.0-py3-none-any.whl", hash = "sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380"}, + {file = "Pygments-2.10.0.tar.gz", hash = "sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6"}, +] +pyparsing = [ + {file = "pyparsing-3.0.5-py3-none-any.whl", hash = "sha256:4881e3d2979f27b41a3a2421b10be9cbfa7ce2baa6c7117952222f8bbea6650c"}, + {file = "pyparsing-3.0.5.tar.gz", hash = "sha256:9329d1c1b51f0f76371c4ded42c5ec4cc0be18456b22193e0570c2da98ed288b"}, +] +pyqt5 = [ + {file = "PyQt5-5.15.6-cp36-abi3-macosx_10_13_x86_64.whl", hash = "sha256:33ced1c876f6a26e7899615a5a4efef2167c263488837c7beed023a64cebd051"}, + {file = "PyQt5-5.15.6-cp36-abi3-manylinux1_x86_64.whl", hash = "sha256:9d6efad0377aa78bf081a20ac752ce86096ded18f04c592d98f5b92dc879ad0a"}, + {file = "PyQt5-5.15.6-cp36-abi3-win32.whl", hash = "sha256:9d2dcdaf82263ae56023410a7af15d1fd746c8e361733a7d0d1bd1f004ec2793"}, + {file = "PyQt5-5.15.6-cp36-abi3-win_amd64.whl", hash = "sha256:f411ecda52e488e1d3c5cce7563e1b2ca9cf0b7531e3c25b03d9a7e56e07e7fc"}, + {file = "PyQt5-5.15.6.tar.gz", hash = "sha256:80343bcab95ffba619f2ed2467fd828ffeb0a251ad7225be5fc06dcc333af452"}, +] +pyqt5-qt5 = [ + {file = "PyQt5_Qt5-5.15.2-py3-none-macosx_10_13_intel.whl", hash = "sha256:76980cd3d7ae87e3c7a33bfebfaee84448fd650bad6840471d6cae199b56e154"}, + {file = "PyQt5_Qt5-5.15.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:1988f364ec8caf87a6ee5d5a3a5210d57539988bf8e84714c7d60972692e2f4a"}, + {file = "PyQt5_Qt5-5.15.2-py3-none-win32.whl", hash = "sha256:9cc7a768b1921f4b982ebc00a318ccb38578e44e45316c7a4a850e953e1dd327"}, + {file = "PyQt5_Qt5-5.15.2-py3-none-win_amd64.whl", hash = "sha256:750b78e4dba6bdf1607febedc08738e318ea09e9b10aea9ff0d73073f11f6962"}, +] +pyqt5-sip = [ + {file = "PyQt5_sip-12.9.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6d5bca2fc222d58e8093ee8a81a6e3437067bb22bc3f86d06ec8be721e15e90a"}, + {file = "PyQt5_sip-12.9.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:d59af63120d1475b2bf94fe8062610720a9be1e8940ea146c7f42bb449d49067"}, + {file = "PyQt5_sip-12.9.0-cp310-cp310-win32.whl", hash = "sha256:0fc9aefacf502696710b36cdc9fa2a61487f55ee883dbcf2c2a6477e261546f7"}, + {file = "PyQt5_sip-12.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:485972daff2fb0311013f471998f8ec8262ea381bded244f9d14edaad5f54271"}, + {file = "PyQt5_sip-12.9.0-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:d85002238b5180bce4b245c13d6face848faa1a7a9e5c6e292025004f2fd619a"}, + {file = "PyQt5_sip-12.9.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:83c3220b1ca36eb8623ba2eb3766637b19eb0ce9f42336ad8253656d32750c0a"}, + {file = "PyQt5_sip-12.9.0-cp36-cp36m-win32.whl", hash = "sha256:d8b2bdff7bbf45bc975c113a03b14fd669dc0c73e1327f02706666a7dd51a197"}, + {file = "PyQt5_sip-12.9.0-cp36-cp36m-win_amd64.whl", hash = "sha256:69a3ad4259172e2b1aa9060de211efac39ddd734a517b1924d9c6c0cc4f55f96"}, + {file = "PyQt5_sip-12.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:42274a501ab4806d2c31659170db14c282b8313d2255458064666d9e70d96206"}, + {file = "PyQt5_sip-12.9.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:6a8701892a01a5a2a4720872361197cc80fdd5f49c8482d488ddf38c9c84f055"}, + {file = "PyQt5_sip-12.9.0-cp37-cp37m-win32.whl", hash = "sha256:ac57d796c78117eb39edd1d1d1aea90354651efac9d3590aac67fa4983f99f1f"}, + {file = "PyQt5_sip-12.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4347bd81d30c8e3181e553b3734f91658cfbdd8f1a19f254777f906870974e6d"}, + {file = "PyQt5_sip-12.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c446971c360a0a1030282a69375a08c78e8a61d568bfd6dab3dcc5cf8817f644"}, + {file = "PyQt5_sip-12.9.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:fc43f2d7c438517ee33e929e8ae77132749c15909afab6aeece5fcf4147ffdb5"}, + {file = "PyQt5_sip-12.9.0-cp38-cp38-win32.whl", hash = "sha256:055581c6fed44ba4302b70eeb82e979ff70400037358908f251cd85cbb3dbd93"}, + {file = "PyQt5_sip-12.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:c5216403d4d8d857ec4a61f631d3945e44fa248aa2415e9ee9369ab7c8a4d0c7"}, + {file = "PyQt5_sip-12.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a25b9843c7da6a1608f310879c38e6434331aab1dc2fe6cb65c14f1ecf33780e"}, + {file = "PyQt5_sip-12.9.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:dd05c768c2b55ffe56a9d49ce6cc77cdf3d53dbfad935258a9e347cbfd9a5850"}, + {file = "PyQt5_sip-12.9.0-cp39-cp39-win32.whl", hash = "sha256:4f8e05fe01d54275877c59018d8e82dcdd0bc5696053a8b830eecea3ce806121"}, + {file = "PyQt5_sip-12.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:b09f4cd36a4831229fb77c424d89635fa937d97765ec90685e2f257e56a2685a"}, + {file = "PyQt5_sip-12.9.0.tar.gz", hash = "sha256:d3e4489d7c2b0ece9d203ae66e573939f7f60d4d29e089c9f11daa17cfeaae32"}, +] +pyrsistent = [ + {file = "pyrsistent-0.18.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f4c8cabb46ff8e5d61f56a037974228e978f26bfefce4f61a4b1ac0ba7a2ab72"}, + {file = "pyrsistent-0.18.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:da6e5e818d18459fa46fac0a4a4e543507fe1110e808101277c5a2b5bab0cd2d"}, + {file = "pyrsistent-0.18.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5e4395bbf841693eaebaa5bb5c8f5cdbb1d139e07c975c682ec4e4f8126e03d2"}, + {file = "pyrsistent-0.18.0-cp36-cp36m-win32.whl", hash = "sha256:527be2bfa8dc80f6f8ddd65242ba476a6c4fb4e3aedbf281dfbac1b1ed4165b1"}, + {file = "pyrsistent-0.18.0-cp36-cp36m-win_amd64.whl", hash = "sha256:2aaf19dc8ce517a8653746d98e962ef480ff34b6bc563fc067be6401ffb457c7"}, + {file = "pyrsistent-0.18.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58a70d93fb79dc585b21f9d72487b929a6fe58da0754fa4cb9f279bb92369396"}, + {file = "pyrsistent-0.18.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:4916c10896721e472ee12c95cdc2891ce5890898d2f9907b1b4ae0f53588b710"}, + {file = "pyrsistent-0.18.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:73ff61b1411e3fb0ba144b8f08d6749749775fe89688093e1efef9839d2dcc35"}, + {file = "pyrsistent-0.18.0-cp37-cp37m-win32.whl", hash = "sha256:b29b869cf58412ca5738d23691e96d8aff535e17390128a1a52717c9a109da4f"}, + {file = "pyrsistent-0.18.0-cp37-cp37m-win_amd64.whl", hash = "sha256:097b96f129dd36a8c9e33594e7ebb151b1515eb52cceb08474c10a5479e799f2"}, + {file = "pyrsistent-0.18.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:772e94c2c6864f2cd2ffbe58bb3bdefbe2a32afa0acb1a77e472aac831f83427"}, + {file = "pyrsistent-0.18.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c1a9ff320fa699337e05edcaae79ef8c2880b52720bc031b219e5b5008ebbdef"}, + {file = "pyrsistent-0.18.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cd3caef37a415fd0dae6148a1b6957a8c5f275a62cca02e18474608cb263640c"}, + {file = "pyrsistent-0.18.0-cp38-cp38-win32.whl", hash = "sha256:e79d94ca58fcafef6395f6352383fa1a76922268fa02caa2272fff501c2fdc78"}, + {file = "pyrsistent-0.18.0-cp38-cp38-win_amd64.whl", hash = "sha256:a0c772d791c38bbc77be659af29bb14c38ced151433592e326361610250c605b"}, + {file = "pyrsistent-0.18.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d5ec194c9c573aafaceebf05fc400656722793dac57f254cd4741f3c27ae57b4"}, + {file = "pyrsistent-0.18.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:6b5eed00e597b5b5773b4ca30bd48a5774ef1e96f2a45d105db5b4ebb4bca680"}, + {file = "pyrsistent-0.18.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:48578680353f41dca1ca3dc48629fb77dfc745128b56fc01096b2530c13fd426"}, + {file = "pyrsistent-0.18.0-cp39-cp39-win32.whl", hash = "sha256:f3ef98d7b76da5eb19c37fda834d50262ff9167c65658d1d8f974d2e4d90676b"}, + {file = "pyrsistent-0.18.0-cp39-cp39-win_amd64.whl", hash = "sha256:404e1f1d254d314d55adb8d87f4f465c8693d6f902f67eb6ef5b4526dc58e6ea"}, + {file = "pyrsistent-0.18.0.tar.gz", hash = "sha256:773c781216f8c2900b42a7b638d5b517bb134ae1acbebe4d1e8f1f41ea60eb4b"}, +] +python-dateutil = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] +pytz = [ + {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"}, + {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"}, +] +pywin32 = [ + {file = "pywin32-302-cp310-cp310-win32.whl", hash = "sha256:251b7a9367355ccd1a4cd69cd8dd24bd57b29ad83edb2957cfa30f7ed9941efa"}, + {file = "pywin32-302-cp310-cp310-win_amd64.whl", hash = "sha256:79cf7e6ddaaf1cd47a9e50cc74b5d770801a9db6594464137b1b86aa91edafcc"}, + {file = "pywin32-302-cp36-cp36m-win32.whl", hash = "sha256:fe21c2fb332d03dac29de070f191bdbf14095167f8f2165fdc57db59b1ecc006"}, + {file = "pywin32-302-cp36-cp36m-win_amd64.whl", hash = "sha256:d3761ab4e8c5c2dbc156e2c9ccf38dd51f936dc77e58deb940ffbc4b82a30528"}, + {file = "pywin32-302-cp37-cp37m-win32.whl", hash = "sha256:48dd4e348f1ee9538dd4440bf201ea8c110ea6d9f3a5010d79452e9fa80480d9"}, + {file = "pywin32-302-cp37-cp37m-win_amd64.whl", hash = "sha256:496df89f10c054c9285cc99f9d509e243f4e14ec8dfc6d78c9f0bf147a893ab1"}, + {file = "pywin32-302-cp38-cp38-win32.whl", hash = "sha256:e372e477d938a49266136bff78279ed14445e00718b6c75543334351bf535259"}, + {file = "pywin32-302-cp38-cp38-win_amd64.whl", hash = "sha256:543552e66936378bd2d673c5a0a3d9903dba0b0a87235ef0c584f058ceef5872"}, + {file = "pywin32-302-cp39-cp39-win32.whl", hash = "sha256:2393c1a40dc4497fd6161b76801b8acd727c5610167762b7c3e9fd058ef4a6ab"}, + {file = "pywin32-302-cp39-cp39-win_amd64.whl", hash = "sha256:af5aea18167a31efcacc9f98a2ca932c6b6a6d91ebe31f007509e293dea12580"}, +] +pywinpty = [ + {file = "pywinpty-1.1.5-cp310-none-win_amd64.whl", hash = "sha256:59e38276f732121b7b708b488055132c695ab7f8790b6ebee9b5b277e30c40e1"}, + {file = "pywinpty-1.1.5-cp36-none-win_amd64.whl", hash = "sha256:0f73bea7f4ecc4711d3706bb0adea0b426c384ff38b619e169d58e20bc307eb0"}, + {file = "pywinpty-1.1.5-cp37-none-win_amd64.whl", hash = "sha256:4cefeef61ab82e9e2bfe228d83a49117e33899931766dd18d576ea5c9187c1e0"}, + {file = "pywinpty-1.1.5-cp38-none-win_amd64.whl", hash = "sha256:44c78a9a74f1b6bff957f8b0acad0525f48f716ac61fd9d39e1eb6f87f1a46a0"}, + {file = "pywinpty-1.1.5-cp39-none-win_amd64.whl", hash = "sha256:ad12ddf276446e0440a760b7c0ba128d39602bc8e6641e0ef8447f1a466a8346"}, + {file = "pywinpty-1.1.5.tar.gz", hash = "sha256:92125f0f8e4e64bb5f3bf270a182c9206dc1765542c59bc07441908a9db17504"}, +] +pyyaml = [ + {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"}, + {file = "PyYAML-5.4.1-cp27-cp27m-win32.whl", hash = "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393"}, + {file = "PyYAML-5.4.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8"}, + {file = "PyYAML-5.4.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185"}, + {file = "PyYAML-5.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541"}, + {file = "PyYAML-5.4.1-cp36-cp36m-win32.whl", hash = "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5"}, + {file = "PyYAML-5.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df"}, + {file = "PyYAML-5.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"}, + {file = "PyYAML-5.4.1-cp37-cp37m-win32.whl", hash = "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b"}, + {file = "PyYAML-5.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf"}, + {file = "PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc"}, + {file = "PyYAML-5.4.1-cp38-cp38-win32.whl", hash = "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"}, + {file = "PyYAML-5.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696"}, + {file = "PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6"}, + {file = "PyYAML-5.4.1-cp39-cp39-win32.whl", hash = "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10"}, + {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, + {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, +] +pyzmq = [ + {file = "pyzmq-22.3.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:6b217b8f9dfb6628f74b94bdaf9f7408708cb02167d644edca33f38746ca12dd"}, + {file = "pyzmq-22.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2841997a0d85b998cbafecb4183caf51fd19c4357075dfd33eb7efea57e4c149"}, + {file = "pyzmq-22.3.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f89468059ebc519a7acde1ee50b779019535db8dcf9b8c162ef669257fef7a93"}, + {file = "pyzmq-22.3.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea12133df25e3a6918718fbb9a510c6ee5d3fdd5a346320421aac3882f4feeea"}, + {file = "pyzmq-22.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c532fd68b93998aab92356be280deec5de8f8fe59cd28763d2cc8a58747b7f"}, + {file = "pyzmq-22.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f907c7359ce8bf7f7e63c82f75ad0223384105f5126f313400b7e8004d9b33c3"}, + {file = "pyzmq-22.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:902319cfe23366595d3fa769b5b751e6ee6750a0a64c5d9f757d624b2ac3519e"}, + {file = "pyzmq-22.3.0-cp310-cp310-win32.whl", hash = "sha256:67db33bea0a29d03e6eeec55a8190e033318cee3cbc732ba8fd939617cbf762d"}, + {file = "pyzmq-22.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:7661fc1d5cb73481cf710a1418a4e1e301ed7d5d924f91c67ba84b2a1b89defd"}, + {file = "pyzmq-22.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:79244b9e97948eaf38695f4b8e6fc63b14b78cc37f403c6642ba555517ac1268"}, + {file = "pyzmq-22.3.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab888624ed68930442a3f3b0b921ad7439c51ba122dbc8c386e6487a658e4a4e"}, + {file = "pyzmq-22.3.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:18cd854b423fce44951c3a4d3e686bac8f1243d954f579e120a1714096637cc0"}, + {file = "pyzmq-22.3.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:de8df0684398bd74ad160afdc2a118ca28384ac6f5e234eb0508858d8d2d9364"}, + {file = "pyzmq-22.3.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:62bcade20813796c426409a3e7423862d50ff0639f5a2a95be4b85b09a618666"}, + {file = "pyzmq-22.3.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:ea5a79e808baef98c48c884effce05c31a0698c1057de8fc1c688891043c1ce1"}, + {file = "pyzmq-22.3.0-cp36-cp36m-win32.whl", hash = "sha256:3c1895c95be92600233e476fe283f042e71cf8f0b938aabf21b7aafa62a8dac9"}, + {file = "pyzmq-22.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:851977788b9caa8ed011f5f643d3ee8653af02c5fc723fa350db5125abf2be7b"}, + {file = "pyzmq-22.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b4ebed0977f92320f6686c96e9e8dd29eed199eb8d066936bac991afc37cbb70"}, + {file = "pyzmq-22.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42abddebe2c6a35180ca549fadc7228d23c1e1f76167c5ebc8a936b5804ea2df"}, + {file = "pyzmq-22.3.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1e41b32d6f7f9c26bc731a8b529ff592f31fc8b6ef2be9fa74abd05c8a342d7"}, + {file = "pyzmq-22.3.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:be4e0f229cf3a71f9ecd633566bd6f80d9fa6afaaff5489492be63fe459ef98c"}, + {file = "pyzmq-22.3.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:08c4e315a76ef26eb833511ebf3fa87d182152adf43dedee8d79f998a2162a0b"}, + {file = "pyzmq-22.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:badb868fff14cfd0e200eaa845887b1011146a7d26d579aaa7f966c203736b92"}, + {file = "pyzmq-22.3.0-cp37-cp37m-win32.whl", hash = "sha256:7c58f598d9fcc52772b89a92d72bf8829c12d09746a6d2c724c5b30076c1f11d"}, + {file = "pyzmq-22.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2b97502c16a5ec611cd52410bdfaab264997c627a46b0f98d3f666227fd1ea2d"}, + {file = "pyzmq-22.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d728b08448e5ac3e4d886b165385a262883c34b84a7fe1166277fe675e1c197a"}, + {file = "pyzmq-22.3.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:480b9931bfb08bf8b094edd4836271d4d6b44150da051547d8c7113bf947a8b0"}, + {file = "pyzmq-22.3.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7dc09198e4073e6015d9a8ea093fc348d4e59de49382476940c3dd9ae156fba8"}, + {file = "pyzmq-22.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ca6cd58f62a2751728016d40082008d3b3412a7f28ddfb4a2f0d3c130f69e74"}, + {file = "pyzmq-22.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:468bd59a588e276961a918a3060948ae68f6ff5a7fa10bb2f9160c18fe341067"}, + {file = "pyzmq-22.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c88fa7410e9fc471e0858638f403739ee869924dd8e4ae26748496466e27ac59"}, + {file = "pyzmq-22.3.0-cp38-cp38-win32.whl", hash = "sha256:c0f84360dcca3481e8674393bdf931f9f10470988f87311b19d23cda869bb6b7"}, + {file = "pyzmq-22.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:f762442bab706fd874064ca218b33a1d8e40d4938e96c24dafd9b12e28017f45"}, + {file = "pyzmq-22.3.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:954e73c9cd4d6ae319f1c936ad159072b6d356a92dcbbabfd6e6204b9a79d356"}, + {file = "pyzmq-22.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f43b4a2e6218371dd4f41e547bd919ceeb6ebf4abf31a7a0669cd11cd91ea973"}, + {file = "pyzmq-22.3.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:acebba1a23fb9d72b42471c3771b6f2f18dcd46df77482612054bd45c07dfa36"}, + {file = "pyzmq-22.3.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cf98fd7a6c8aaa08dbc699ffae33fd71175696d78028281bc7b832b26f00ca57"}, + {file = "pyzmq-22.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d072f7dfbdb184f0786d63bda26e8a0882041b1e393fbe98940395f7fab4c5e2"}, + {file = "pyzmq-22.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:53f4fd13976789ffafedd4d46f954c7bb01146121812b72b4ddca286034df966"}, + {file = "pyzmq-22.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d1b5d457acbadcf8b27561deeaa386b0217f47626b29672fa7bd31deb6e91e1b"}, + {file = "pyzmq-22.3.0-cp39-cp39-win32.whl", hash = "sha256:e6a02cf7271ee94674a44f4e62aa061d2d049001c844657740e156596298b70b"}, + {file = "pyzmq-22.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:d3dcb5548ead4f1123851a5ced467791f6986d68c656bc63bfff1bf9e36671e2"}, + {file = "pyzmq-22.3.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3a4c9886d61d386b2b493377d980f502186cd71d501fffdba52bd2a0880cef4f"}, + {file = "pyzmq-22.3.0-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:80e043a89c6cadefd3a0712f8a1322038e819ebe9dbac7eca3bce1721bcb63bf"}, + {file = "pyzmq-22.3.0-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1621e7a2af72cced1f6ec8ca8ca91d0f76ac236ab2e8828ac8fe909512d566cb"}, + {file = "pyzmq-22.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:d6157793719de168b199194f6b6173f0ccd3bf3499e6870fac17086072e39115"}, + {file = "pyzmq-22.3.0.tar.gz", hash = "sha256:8eddc033e716f8c91c6a2112f0a8ebc5e00532b4a6ae1eb0ccc48e027f9c671c"}, +] +qtconsole = [ + {file = "qtconsole-5.2.0-py3-none-any.whl", hash = "sha256:a287f9f0f7365ccb2f2a88e0cd4da883822e94d15b75dc19098cd8eec44d70d1"}, + {file = "qtconsole-5.2.0.tar.gz", hash = "sha256:6bb4df839609f240194213407872076f871e3a3884cf8e785068e8c7f39344c6"}, +] +qtpy = [ + {file = "QtPy-1.11.2-py2.py3-none-any.whl", hash = "sha256:83c502973e9fdd7b648d8267a421229ea3d9a0651c22e4c65a4d9228479c39b6"}, + {file = "QtPy-1.11.2.tar.gz", hash = "sha256:d6e4ae3a41f1fcb19762b58f35ad6dd443b4bdc867a4cb81ef10ccd85403c92b"}, +] +requests = [ + {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, + {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"}, +] +requests-oauthlib = [ + {file = "requests-oauthlib-1.3.0.tar.gz", hash = "sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a"}, + {file = "requests_oauthlib-1.3.0-py2.py3-none-any.whl", hash = "sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d"}, + {file = "requests_oauthlib-1.3.0-py3.7.egg", hash = "sha256:fa6c47b933f01060936d87ae9327fead68768b69c6c9ea2109c48be30f2d4dbc"}, +] +rosbag = [] +roscpp = [] +rosgraph = [] +rosgraph-msgs = [] +roslib = [] +rospkg = [ + {file = "rospkg-1.3.0-py3-none-any.whl", hash = "sha256:dc8fab3ed3f163bc301f94ec65ed39a2c40ded6757615a0fb9f2cb2c82470fbe"}, + {file = "rospkg-1.3.0.tar.gz", hash = "sha256:e024f9d617c55c76dd47530dceb0882c85cb83234450b8df3d1cb809e009f6cb"}, +] +rospy = [] +rsa = [ + {file = "rsa-4.7.2-py3-none-any.whl", hash = "sha256:78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2"}, + {file = "rsa-4.7.2.tar.gz", hash = "sha256:9d689e6ca1b3038bc82bf8d23e944b6b6037bc02301a574935b2dd946e0353b9"}, +] +scipy = [ + {file = "scipy-1.7.2-1-cp310-cp310-win_amd64.whl", hash = "sha256:dc2d1bf41294e63c7302bf499973ac0c7f73c93c01763db43055f6525234bf11"}, + {file = "scipy-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:97eb573e361a73a553b915dc195c6f72a08249964b1a33f157f9659f3b6210d1"}, + {file = "scipy-1.7.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:359b60a0cccd17723b9d5e329a5212a710e771a3ddde800e472fb93732756c46"}, + {file = "scipy-1.7.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82c5befebf54d799d77e5f0205c03030f57f69ba2541baa44d2e6ad138c28cd3"}, + {file = "scipy-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:54951f51d731c832b1b8885e0a92e89f33d087de7e40d02078bf0d49c7cbdbb5"}, + {file = "scipy-1.7.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:30bdda199667e74b50208a793eb1ba47a04e5e3fa16f5ff06c6f7969ae78e4da"}, + {file = "scipy-1.7.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e3efe7ef75dfe627b354ab0af0dbc918eadee97cc80ff1aabea6d3e01114ebdd"}, + {file = "scipy-1.7.2-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:17fd991a275e4283453f89d404209aa92059ac68d76d804b4bc1716a3742e1b5"}, + {file = "scipy-1.7.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74f518ce542533054695f743e4271cb8986b63f95bb51d70fcee4f3929cbff7d"}, + {file = "scipy-1.7.2-cp37-cp37m-win32.whl", hash = "sha256:1437073f1d4664990879aa8f9547524764372e0fef84a077be4b19e82bba7a8d"}, + {file = "scipy-1.7.2-cp37-cp37m-win_amd64.whl", hash = "sha256:39f838ea5ce8da868785193d88d05cf5a6d5c390804ec99de29a28e1dcdd53e6"}, + {file = "scipy-1.7.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e08b81fcd9bf98740b58dc6fdd7879e33a64dcb682201c1135f7d4a75216bb05"}, + {file = "scipy-1.7.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:7b1d0f5f524518f1a86f288443528e4ff4a739c0966db663af4129b7ac7849f8"}, + {file = "scipy-1.7.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cac71d5476a6f56b50459da21f6221707e0051ebd428b2137db32ef4a43bb15e"}, + {file = "scipy-1.7.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d175ba93e00d8eef8f7cd70d4d88a9106a86800c82ea03cf2268c36d6545483"}, + {file = "scipy-1.7.2-cp38-cp38-win32.whl", hash = "sha256:8b5726a0fedeaa6beb1095e4466998bdd1d1e960b28db9b5a16c89cbd7b2ebf1"}, + {file = "scipy-1.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:8482c8e45857ab0a5446eb7460d2307a27cbbe659d6d2257820c6d6eb950fd0f"}, + {file = "scipy-1.7.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1ea6233f5a365cb7945b4304bd06323ece3ece85d6a3fa8598d2f53e513467c9"}, + {file = "scipy-1.7.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:d86abd1ddf421dea5e9cebfeb4de0d205b3dc04e78249afedba9c6c3b2227ff2"}, + {file = "scipy-1.7.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d25272c03ee3c0fe5e0dff1bb7889280bb6c9e1766fa9c7bde81ad8a5f78694"}, + {file = "scipy-1.7.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5273d832fb9cd5724ee0d335c16a903b923441107dd973d27fc4293075a9f4e3"}, + {file = "scipy-1.7.2-cp39-cp39-win32.whl", hash = "sha256:87cf3964db0f1cce17aeed5bfc1b89a6b4b07dbfc48e50d21fa3549e00456803"}, + {file = "scipy-1.7.2-cp39-cp39-win_amd64.whl", hash = "sha256:a80eb01c43fd98257ec7a49ff5cec0edba32031b5f86503f55399a48cb2c5379"}, + {file = "scipy-1.7.2.tar.gz", hash = "sha256:fa2dbabaaecdb502641b0b3c00dec05fb475ae48655c66da16c9ed24eda1e711"}, +] +send2trash = [ + {file = "Send2Trash-1.8.0-py3-none-any.whl", hash = "sha256:f20eaadfdb517eaca5ce077640cb261c7d2698385a6a0f072a4a5447fd49fa08"}, + {file = "Send2Trash-1.8.0.tar.gz", hash = "sha256:d2c24762fd3759860a0aff155e45871447ea58d2be6bdd39b5c8f966a0c99c2d"}, +] +sensor-msgs = [] +six = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] +stable-baselines3 = [] +std-msgs = [] +supersuit = [ + {file = "SuperSuit-3.3.1.tar.gz", hash = "sha256:bc9a7810425a4168c3db18138d1f60ae6c1e27f02f4e7a83f4a555a0010b1cef"}, +] +tensorboard = [ + {file = "tensorboard-2.7.0-py3-none-any.whl", hash = "sha256:239f78a4a8dff200ce585a030c787773a8c1184d5c159252f5f85bac4e3c3b38"}, +] +tensorboard-data-server = [ + {file = "tensorboard_data_server-0.6.1-py3-none-any.whl", hash = "sha256:809fe9887682d35c1f7d1f54f0f40f98bb1f771b14265b453ca051e2ce58fca7"}, + {file = "tensorboard_data_server-0.6.1-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:fa8cef9be4fcae2f2363c88176638baf2da19c5ec90addb49b1cde05c95c88ee"}, + {file = "tensorboard_data_server-0.6.1-py3-none-manylinux2010_x86_64.whl", hash = "sha256:d8237580755e58eff68d1f3abefb5b1e39ae5c8b127cc40920f9c4fb33f4b98a"}, +] +tensorboard-plugin-wit = [ + {file = "tensorboard_plugin_wit-1.8.0-py3-none-any.whl", hash = "sha256:2a80d1c551d741e99b2f197bb915d8a133e24adb8da1732b840041860f91183a"}, +] +terminado = [ + {file = "terminado-0.12.1-py3-none-any.whl", hash = "sha256:09fdde344324a1c9c6e610ee4ca165c4bb7f5bbf982fceeeb38998a988ef8452"}, + {file = "terminado-0.12.1.tar.gz", hash = "sha256:b20fd93cc57c1678c799799d117874367cc07a3d2d55be95205b1a88fa08393f"}, +] +testpath = [ + {file = "testpath-0.5.0-py3-none-any.whl", hash = "sha256:8044f9a0bab6567fc644a3593164e872543bb44225b0e24846e2c89237937589"}, + {file = "testpath-0.5.0.tar.gz", hash = "sha256:1acf7a0bcd3004ae8357409fc33751e16d37ccc650921da1094a86581ad1e417"}, +] +tf = [] +tf2-msgs = [] +tf2-py = [] +tf2-ros = [] +tomli = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] +torch = [ + {file = "torch-1.10.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:56022b0ce94c54e95a2f63fc5a1494feb1fc3d5c7a9b35a62944651d03edef05"}, + {file = "torch-1.10.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:13e1ffab502aa32d6841a018771b47028d02dbbc685c5b79cfd61db5464dae4e"}, + {file = "torch-1.10.0-cp36-cp36m-win_amd64.whl", hash = "sha256:3c0a942e0df104c80b0eedc30d2a19cdc3d28601bc6e280bf24b2e6255016d3b"}, + {file = "torch-1.10.0-cp36-none-macosx_10_9_x86_64.whl", hash = "sha256:eea16c01af1980ba709c00e8d5e6c09bedb5b30f9fa2085f6a52a78d7dc4e125"}, + {file = "torch-1.10.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:b812e8d40d7037748da40bb695bd849e7b2e7faad4cd06df53d2cc4531926fda"}, + {file = "torch-1.10.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:034df0b20603bfc81325094586647302891b9b20be7e36f152c7dd6af00deac1"}, + {file = "torch-1.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:67fc509e207b8e7330f2e76e77800950317d31d035a4d19593db991962afead4"}, + {file = "torch-1.10.0-cp37-none-macosx_10_9_x86_64.whl", hash = "sha256:4499055547087d7ef7e8a754f09c2c4f1470297ae3e5490363dba66c75501b21"}, + {file = "torch-1.10.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:ab0cf330714c8f79a837c04784a7a5658b014cf5a4ca527e7b710155ae519cdf"}, + {file = "torch-1.10.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e01ba5946267014abfdb30248bcdbd457aaa20cff749febe7fc191e5ae096af4"}, + {file = "torch-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:9013002adcb42bac05dcdbf0a03dd9f6bb5d7ab8b9817041c1176a014870786b"}, + {file = "torch-1.10.0-cp38-none-macosx_10_9_x86_64.whl", hash = "sha256:aef7afb62e9b174b4e0e5e1e4a42e3bab3b8490a668d666f62f7d4517559fbf2"}, + {file = "torch-1.10.0-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:d6185827b285780653cdd81d77a09fdca76a5b190d5986d552be2a5c442cfaa4"}, + {file = "torch-1.10.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:d82e68302c9b5c76ed585e04d61be0ca2184f70cb8ffeba8610570609ad5d7c9"}, + {file = "torch-1.10.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:e5822200bf80a1495ad98a2bb41803eeba4a85ce373e35fc65765f7f888f5374"}, + {file = "torch-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:ca2c88fa4376e2648785029ab108e6e7abd784eb6535fc6036004b9254f9f7c1"}, + {file = "torch-1.10.0-cp39-none-macosx_10_9_x86_64.whl", hash = "sha256:d6ef87470b44df9970e84542547d5ba7720bb89616602441df555a39b124e2bc"}, + {file = "torch-1.10.0-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:eea675ec01ec4b4a0655fd2984f166a5ca3b933dae6ad4eb4e52eba7026dc176"}, +] +tornado = [ + {file = "tornado-6.1-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32"}, + {file = "tornado-6.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:0d321a39c36e5f2c4ff12b4ed58d41390460f798422c4504e09eb5678e09998c"}, + {file = "tornado-6.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9de9e5188a782be6b1ce866e8a51bc76a0fbaa0e16613823fc38e4fc2556ad05"}, + {file = "tornado-6.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:61b32d06ae8a036a6607805e6720ef00a3c98207038444ba7fd3d169cd998910"}, + {file = "tornado-6.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:3e63498f680547ed24d2c71e6497f24bca791aca2fe116dbc2bd0ac7f191691b"}, + {file = "tornado-6.1-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:6c77c9937962577a6a76917845d06af6ab9197702a42e1346d8ae2e76b5e3675"}, + {file = "tornado-6.1-cp35-cp35m-win32.whl", hash = "sha256:6286efab1ed6e74b7028327365cf7346b1d777d63ab30e21a0f4d5b275fc17d5"}, + {file = "tornado-6.1-cp35-cp35m-win_amd64.whl", hash = "sha256:fa2ba70284fa42c2a5ecb35e322e68823288a4251f9ba9cc77be04ae15eada68"}, + {file = "tornado-6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0a00ff4561e2929a2c37ce706cb8233b7907e0cdc22eab98888aca5dd3775feb"}, + {file = "tornado-6.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:748290bf9112b581c525e6e6d3820621ff020ed95af6f17fedef416b27ed564c"}, + {file = "tornado-6.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:e385b637ac3acaae8022e7e47dfa7b83d3620e432e3ecb9a3f7f58f150e50921"}, + {file = "tornado-6.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:25ad220258349a12ae87ede08a7b04aca51237721f63b1808d39bdb4b2164558"}, + {file = "tornado-6.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:65d98939f1a2e74b58839f8c4dab3b6b3c1ce84972ae712be02845e65391ac7c"}, + {file = "tornado-6.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:e519d64089b0876c7b467274468709dadf11e41d65f63bba207e04217f47c085"}, + {file = "tornado-6.1-cp36-cp36m-win32.whl", hash = "sha256:b87936fd2c317b6ee08a5741ea06b9d11a6074ef4cc42e031bc6403f82a32575"}, + {file = "tornado-6.1-cp36-cp36m-win_amd64.whl", hash = "sha256:cc0ee35043162abbf717b7df924597ade8e5395e7b66d18270116f8745ceb795"}, + {file = "tornado-6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7250a3fa399f08ec9cb3f7b1b987955d17e044f1ade821b32e5f435130250d7f"}, + {file = "tornado-6.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:ed3ad863b1b40cd1d4bd21e7498329ccaece75db5a5bf58cd3c9f130843e7102"}, + {file = "tornado-6.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:dcef026f608f678c118779cd6591c8af6e9b4155c44e0d1bc0c87c036fb8c8c4"}, + {file = "tornado-6.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:70dec29e8ac485dbf57481baee40781c63e381bebea080991893cd297742b8fd"}, + {file = "tornado-6.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:d3f7594930c423fd9f5d1a76bee85a2c36fd8b4b16921cae7e965f22575e9c01"}, + {file = "tornado-6.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:3447475585bae2e77ecb832fc0300c3695516a47d46cefa0528181a34c5b9d3d"}, + {file = "tornado-6.1-cp37-cp37m-win32.whl", hash = "sha256:e7229e60ac41a1202444497ddde70a48d33909e484f96eb0da9baf8dc68541df"}, + {file = "tornado-6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:cb5ec8eead331e3bb4ce8066cf06d2dfef1bfb1b2a73082dfe8a161301b76e37"}, + {file = "tornado-6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:20241b3cb4f425e971cb0a8e4ffc9b0a861530ae3c52f2b0434e6c1b57e9fd95"}, + {file = "tornado-6.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c77da1263aa361938476f04c4b6c8916001b90b2c2fdd92d8d535e1af48fba5a"}, + {file = "tornado-6.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:fba85b6cd9c39be262fcd23865652920832b61583de2a2ca907dbd8e8a8c81e5"}, + {file = "tornado-6.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:1e8225a1070cd8eec59a996c43229fe8f95689cb16e552d130b9793cb570a288"}, + {file = "tornado-6.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d14d30e7f46a0476efb0deb5b61343b1526f73ebb5ed84f23dc794bdb88f9d9f"}, + {file = "tornado-6.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8f959b26f2634a091bb42241c3ed8d3cedb506e7c27b8dd5c7b9f745318ddbb6"}, + {file = "tornado-6.1-cp38-cp38-win32.whl", hash = "sha256:34ca2dac9e4d7afb0bed4677512e36a52f09caa6fded70b4e3e1c89dbd92c326"}, + {file = "tornado-6.1-cp38-cp38-win_amd64.whl", hash = "sha256:6196a5c39286cc37c024cd78834fb9345e464525d8991c21e908cc046d1cc02c"}, + {file = "tornado-6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0ba29bafd8e7e22920567ce0d232c26d4d47c8b5cf4ed7b562b5db39fa199c5"}, + {file = "tornado-6.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:33892118b165401f291070100d6d09359ca74addda679b60390b09f8ef325ffe"}, + {file = "tornado-6.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7da13da6f985aab7f6f28debab00c67ff9cbacd588e8477034c0652ac141feea"}, + {file = "tornado-6.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:e0791ac58d91ac58f694d8d2957884df8e4e2f6687cdf367ef7eb7497f79eaa2"}, + {file = "tornado-6.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:66324e4e1beede9ac79e60f88de548da58b1f8ab4b2f1354d8375774f997e6c0"}, + {file = "tornado-6.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:a48900ecea1cbb71b8c71c620dee15b62f85f7c14189bdeee54966fbd9a0c5bd"}, + {file = "tornado-6.1-cp39-cp39-win32.whl", hash = "sha256:d3d20ea5782ba63ed13bc2b8c291a053c8d807a8fa927d941bd718468f7b950c"}, + {file = "tornado-6.1-cp39-cp39-win_amd64.whl", hash = "sha256:548430be2740e327b3fe0201abe471f314741efcb0067ec4f2d7dcfb4825f3e4"}, + {file = "tornado-6.1.tar.gz", hash = "sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791"}, +] +traitlets = [ + {file = "traitlets-5.1.1-py3-none-any.whl", hash = "sha256:2d313cc50a42cd6c277e7d7dc8d4d7fedd06a2c215f78766ae7b1a66277e0033"}, + {file = "traitlets-5.1.1.tar.gz", hash = "sha256:059f456c5a7c1c82b98c2e8c799f39c9b8128f6d0d46941ee118daace9eb70c7"}, +] +typing-extensions = [ + {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, + {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, + {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, +] +urllib3 = [ + {file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"}, + {file = "urllib3-1.26.7.tar.gz", hash = "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece"}, +] +wcwidth = [ + {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, + {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, +] +webencodings = [ + {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, + {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, +] +werkzeug = [ + {file = "Werkzeug-2.0.2-py3-none-any.whl", hash = "sha256:63d3dc1cf60e7b7e35e97fa9861f7397283b75d765afcaefd993d6046899de8f"}, + {file = "Werkzeug-2.0.2.tar.gz", hash = "sha256:aa2bb6fc8dee8d6c504c0ac1e7f5f7dc5810a9903e793b6f715a9f015bdadb9a"}, +] +widgetsnbextension = [ + {file = "widgetsnbextension-3.5.2-py2.py3-none-any.whl", hash = "sha256:763a9fdc836d141fa080005a886d63f66f73d56dba1fb5961afc239c77708569"}, + {file = "widgetsnbextension-3.5.2.tar.gz", hash = "sha256:e0731a60ba540cd19bbbefe771a9076dcd2dde90713a8f87f27f53f2d1db7727"}, +] +zipp = [ + {file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"}, + {file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"}, +] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..17871ff86 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,40 @@ +[tool.poetry] +name = "arena-rosnav" +version = "0.1.0" +description = "" +authors = ["Your Name "] + +[[tool.poetry.source]] +name = "ros" +url = "https://rospypi.github.io/simple/" +secondary = true + +[tool.poetry.dependencies] +python = ">=3.8,<3.10" +rospy = "^1.15.7" +rosbag = "^1.15.7" +tf = "^1.12.1" +tf2-ros = "^0.6.5" +PyYAML = "^5.4.1" +catkin-pkg = "^0.4.23" +netifaces = "^0.10.9" +pathlib = "^1.0.1" +empy = "^3.3.4" +setuptools = "^56.2.0" +filelock = "^3.0.12" +PyQt5 = "^5.15.4" +scipy = "^1.7.1" +PettingZoo = "1.13.1" +SuperSuit = "^3.3.0" +stable-baselines3 = {git = "https://github.com/ignc-research/stable-baselines3", rev = "marl"} +tensorboard = "^2.7.0" +notebook = "^6.4.5" +jupyter = "^1.0.0" + +[tool.poetry.dev-dependencies] +pdoc3 = "^0.10.0" +black = {version = "^22.3.0", allow-prereleases = true} + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/task_generator/scripts/__pycache__/clear_costmap.cpython-38.pyc b/task_generator/scripts/__pycache__/clear_costmap.cpython-38.pyc index 7746ab08d..83286bbc7 100644 Binary files a/task_generator/scripts/__pycache__/clear_costmap.cpython-38.pyc and b/task_generator/scripts/__pycache__/clear_costmap.cpython-38.pyc differ diff --git a/task_generator/task_generator/__pycache__/__init__.cpython-38.pyc b/task_generator/task_generator/__pycache__/__init__.cpython-38.pyc index 6b95fc612..c9fe4e596 100644 Binary files a/task_generator/task_generator/__pycache__/__init__.cpython-38.pyc and b/task_generator/task_generator/__pycache__/__init__.cpython-38.pyc differ diff --git a/task_generator/task_generator/__pycache__/obstacles_manager.cpython-38.pyc b/task_generator/task_generator/__pycache__/obstacles_manager.cpython-38.pyc index 101cdfd3b..657abe12b 100644 Binary files a/task_generator/task_generator/__pycache__/obstacles_manager.cpython-38.pyc and b/task_generator/task_generator/__pycache__/obstacles_manager.cpython-38.pyc differ diff --git a/task_generator/task_generator/__pycache__/robot_manager.cpython-38.pyc b/task_generator/task_generator/__pycache__/robot_manager.cpython-38.pyc index 8149f67f5..f8ac9e363 100644 Binary files a/task_generator/task_generator/__pycache__/robot_manager.cpython-38.pyc and b/task_generator/task_generator/__pycache__/robot_manager.cpython-38.pyc differ diff --git a/task_generator/task_generator/__pycache__/tasks.cpython-38.pyc b/task_generator/task_generator/__pycache__/tasks.cpython-38.pyc index c1b60355d..812775137 100644 Binary files a/task_generator/task_generator/__pycache__/tasks.cpython-38.pyc and b/task_generator/task_generator/__pycache__/tasks.cpython-38.pyc differ diff --git a/task_generator/task_generator/__pycache__/utils.cpython-38.pyc b/task_generator/task_generator/__pycache__/utils.cpython-38.pyc index d032aeb82..53fc29e7f 100644 Binary files a/task_generator/task_generator/__pycache__/utils.cpython-38.pyc and b/task_generator/task_generator/__pycache__/utils.cpython-38.pyc differ diff --git a/task_generator/task_generator/marl_robot_manager.py b/task_generator/task_generator/marl_robot_manager.py new file mode 100755 index 000000000..414eec98e --- /dev/null +++ b/task_generator/task_generator/marl_robot_manager.py @@ -0,0 +1,296 @@ +# from math import ceil, sqrt +from typing import Union + +import math +import os + +from torch.nn.modules.module import T +import rospy +import rospkg +import tf +import yaml + +from flatland_msgs.srv import ( + MoveModel, + MoveModelRequest, + SpawnModelRequest, + SpawnModel, + StepWorld, +) +from geometry_msgs.msg import Pose2D, PoseStamped +from nav_msgs.msg import OccupancyGrid + +from .utils import generate_freespace_indices, get_random_pos_on_map + + +class RobotManager: + """ + A manager class using flatland provided services to spawn, move and delete Robot. Currently only one robot + is managed + """ + + def __init__( + self, + ns: str, + map_: OccupancyGrid, + robot_yaml_path: str, + robot_type: str, + robot_id: str = "myrobot", + timeout=20, + ) -> None: + """[summary] + + Args: + ns(namespace): if ns == '', we will use global namespace + map_ (OccupancyGrid): the map info + robot_yaml_path (str): the file name of the base robot yaml file. + + """ + """SET A METHOD TO EXTRACT IF MARL IS BEIN REQUESTED""" + MARL = rospy.get_param("num_robots") > 1 + + self.ns = ns + self.ns_prefix = "" if ns == "" else "/" + ns + "/" + + self.robot_id = robot_id + self.robot_type = robot_type + + self.is_training_mode = rospy.get_param("/train_mode") + self.step_size = rospy.get_param("step_size") + + self._get_robot_config(robot_yaml_path) + robot_yaml_path = ( + self._generate_robot_config_with_adjusted_topics() + if MARL + else robot_yaml_path + ) + + # setup proxy to handle services provided by flatland + rospy.wait_for_service(f"{self.ns_prefix}move_model", timeout=timeout) + rospy.wait_for_service(f"{self.ns_prefix}spawn_model", timeout=timeout) + + self._srv_move_model = rospy.ServiceProxy( + f"{self.ns_prefix}move_model", MoveModel + ) + self._srv_spawn_model = rospy.ServiceProxy( + f"{self.ns_prefix}spawn_model", SpawnModel + ) + # it's only needed in training mode to send the clock signal. + self._step_world = rospy.ServiceProxy(f"{self.ns_prefix}step_world", StepWorld) + + # publisher + goal_topic = ( + f"{self.ns_prefix}{self.robot_id}/goal" if MARL else f"{self.ns_prefix}goal" + ) + self._goal_pub = rospy.Publisher( + f"{goal_topic}", PoseStamped, queue_size=1, latch=True + ) + + self.update_map(map_) + self._spawn_robot(robot_yaml_path) + + # remove temporary config file + if MARL: + os.remove(robot_yaml_path) + + def _spawn_robot(self, robot_yaml_path: str) -> None: + request = SpawnModelRequest() + request.yaml_path = robot_yaml_path + request.name = self.robot_id + request.ns = self.ns + self._srv_spawn_model(request) + + def _get_robot_config(self, robot_yaml_path: str) -> None: + """Get robot info e.g robot name, radius, Laser related infomation + + Args: + robot_yaml_path ([type]): [description] + """ + robot_config = os.path.join( + rospkg.RosPack().get_path("arena_local_planner_drl"), + "configs", + "action_spaces", + "default_settings_" + self.robot_type + ".yaml", + ) + with open(robot_config, "r", encoding="utf-8") as target: + config = yaml.load(target, Loader=yaml.FullLoader) + self.ROBOT_RADIUS = config["robot"]["radius"] + + with open(robot_yaml_path, "r") as f: + self._robot_data = yaml.safe_load(f) + + # get laser_update_rate + for plugin in self._robot_data["plugins"]: + if plugin["type"] == "Laser": + self.LASER_UPDATE_RATE = plugin.setdefault("update_rate", 1) + + def _generate_robot_config_with_adjusted_topics(self) -> str: + """Generates a robot-specific config file (yaml) where the publication \ + and subscription topics are adjusted with the robot's namespace. + + Returns: + str: Path of the robot-specific adjusted config file. + + Note: + - The namespaces consist of: [simulation ns] / [robot name] / *topic*\ + e.g.: sim_1/myrobot/scan + - The yaml files are temporarily dumped into *../simulator_setup/tmp_robot_configs* + """ + self._robot_data["bodies"][0]["name"] = ( + self.robot_id + "_" + self._robot_data["bodies"][0]["name"] + ) + + for plugin in self._robot_data["plugins"]: + if plugin["type"] == "DiffDrive": + plugin["body"] = self._robot_data["bodies"][0]["name"] + plugin["odom_frame_id"] = self.robot_id + "_" + plugin["odom_frame_id"] + plugin["odom_pub"] = self.robot_id + "/" + plugin["odom_pub"] + plugin["twist_sub"] = ( + self.robot_id + "/" + plugin.get("twist_sub", "cmd_vel") + ) + + elif plugin["type"] == "Laser": + plugin["topic"] = self.robot_id + "/" + plugin["topic"] + plugin["body"] = self._robot_data["bodies"][0]["name"] + plugin["frame"] = self.robot_id + "_" + plugin["frame"] + + tmp_folder_path = os.path.join( + rospkg.RosPack().get_path("simulator_setup"), "tmp_robot_configs" + ) + os.makedirs(tmp_folder_path, exist_ok=True) + tmp_config_name = self.ns + self.robot_id + ".robot_config.yaml" + tmp_config_path = os.path.join(tmp_folder_path, tmp_config_name) + + with open(tmp_config_path, "w") as fd: + yaml.dump(self._robot_data, fd) + + return tmp_config_path + + def update_map(self, new_map: OccupancyGrid): + self.map = new_map + # a tuple stores the indices of the non-occupied spaces. format ((y,....),(x,...) + self._free_space_indices = generate_freespace_indices(self.map) + + def move_robot(self, pose: Pose2D): + """Move the robot to a given position. + + Args: + pose (Pose2D): Target postion. + """ + # call service move_model + + srv_request = MoveModelRequest() + srv_request.name = self.robot_id + srv_request.pose = pose + + # call service + self._srv_move_model(srv_request) + if self.is_training_mode: + # a necessaray procedure to let the flatland publish the + # laser,odom's Transformation, which are needed for creating + # global path + # assert self.step_size * \ + # self.LASER_UPDATE_RATE == 1, f"TO run the traning successfully, make sure the laser_update_rate*step_size == 1 \ + # \n\tcurrent step_size:\t {self.step_size}\n\tcurrent laser's update rate:\t {self.LASER_UPDATE_RATE} " + for _ in range(math.ceil(1 / (self.step_size * self.LASER_UPDATE_RATE))): + self._step_world() + + def set_start_pos_random(self): + start_pos = Pose2D() + start_pos.x, start_pos, start_pos.theta = get_random_pos_on_map( + self._free_space_indices, self.map, self.ROBOT_RADIUS * 2 + ) + self.move_robot(start_pos) + + def set_start_pos_goal_pos( + self, + start_pos: Union[Pose2D, None] = None, + goal_pos: Union[Pose2D, None] = None, + min_dist=1, + forbidden_zones: Union[list, None] = None, + ): + """Set up start position and the goal postion. Path validation checking will be conducted. If it failed, an + exception will be raised. + + Args: + start_pos (Union[Pose2D,None], optional): start position. if None, it will be set randomly. Defaults to None. + goal_pos (Union[Pose2D,None], optional): [description]. if None, it will be set randomly .Defaults to None. + min_dist (float): minimum distance between start_pos and goal_pos + forbidden_zones (list): a list of tuples with the format (x,y,r), where the the robot should not be reset. + Exception: + Exception("can not generate a path with the given start position and the goal position of the robot") + """ + + def dist(x1, y1, x2, y2): + return math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2) + + if start_pos is None or goal_pos is None: + # if any of them need to be random generated, we set a higher threshold,otherwise only try once + max_try_times = 20 + else: + max_try_times = 1 + + i_try = 0 + start_pos_ = None + goal_pos_ = None + while i_try < max_try_times: + + if start_pos is None: + start_pos_ = Pose2D() + (start_pos_.x, start_pos_.y, start_pos_.theta,) = get_random_pos_on_map( + self._free_space_indices, + self.map, + self.ROBOT_RADIUS * 2, + forbidden_zones=forbidden_zones, + ) + else: + start_pos_ = start_pos + + if goal_pos is None: + goal_pos_ = Pose2D() + (goal_pos_.x, goal_pos_.y, goal_pos_.theta,) = get_random_pos_on_map( + self._free_space_indices, self.map, self.ROBOT_RADIUS * 2 + ) + else: + goal_pos_ = goal_pos + + if dist(start_pos_.x, start_pos_.y, goal_pos_.x, goal_pos_.y) < min_dist: + i_try += 1 + continue + # move the robot to the start pos + self.move_robot(start_pos_) + try: + # publish the goal, if the gobal plath planner can't generate a path, a, exception will be raised. + self.publish_goal(goal_pos_.x, goal_pos_.y, goal_pos_.theta) + break + except rospy.ServiceException: + i_try += 1 + if i_try == max_try_times: + # TODO Define specific type of Exception + raise rospy.ServiceException( + "can not generate a path with the given start position and the goal position of the robot" + ) + else: + return start_pos_, goal_pos_ + + def publish_goal(self, x, y, theta): + """ + Publishing goal (x, y, theta) + :param x x-position of the goal + :param y y-position of the goal + :param theta theta-position of the goal + """ + goal = PoseStamped() + goal.header.stamp = rospy.get_rostime() + goal.header.frame_id = "map" + goal.pose.position.x = x + goal.pose.position.y = y + quaternion = tf.transformations.quaternion_from_euler(0, 0, 0) + goal.pose.orientation.w = quaternion[0] + goal.pose.orientation.x = quaternion[1] + goal.pose.orientation.y = quaternion[2] + goal.pose.orientation.z = quaternion[3] + self._goal_pub.publish(goal) + + def __mean_square_dist_(self, x, y): + return math.sqrt(math.pow(x, 2) + math.pow(y, 2)) diff --git a/task_generator/task_generator/marl_tasks.py b/task_generator/task_generator/marl_tasks.py new file mode 100644 index 000000000..14989314d --- /dev/null +++ b/task_generator/task_generator/marl_tasks.py @@ -0,0 +1,309 @@ +from typing import Type, Union, List + +import json +import os +import rospkg +import rospy +import yaml + +from abc import ABC, abstractmethod +from enum import Enum, unique +from threading import Lock +from filelock import FileLock + +from nav_msgs.msg import OccupancyGrid +from nav_msgs.srv import GetMap +from std_msgs.msg import Bool + +from .obstacles_manager import ObstaclesManager +from .marl_robot_manager import RobotManager + + +class ABSMARLTask(ABC): + """An abstract class for the DRL agent navigation tasks.""" + + def __init__( + self, + obstacles_manager: ObstaclesManager, + robot_manager: List[RobotManager], + ): + self.obstacles_manager = obstacles_manager + self.robot_manager = robot_manager + self._service_client_get_map = rospy.ServiceProxy("/static_map", GetMap) + self._map_lock = Lock() + rospy.Subscriber("/map", OccupancyGrid, self._update_map) + # a mutex keep the map is not unchanged during reset task. + + @abstractmethod + def reset(self): + """ + Funciton to reset the task/scenery. Make sure that _map_lock is used. + """ + + def _update_map(self, map_: OccupancyGrid): + with self._map_lock: + self.obstacles_manager.update_map(map_) + for manager in self.robot_manager: + manager.update_map(map_) + + +class RandomMARLTask(ABSMARLTask): + """Sets a randomly drawn start and goal position for each robot episodically.""" + + def __init__( + self, + obstacles_manager: ObstaclesManager, + robot_manager: List[RobotManager], + ): + super().__init__(obstacles_manager, robot_manager) + self._num_robots = len(self.robot_manager) + + def reset(self): + """[summary]""" + with self._map_lock: + max_fail_times = 3 + fail_times = 0 + while fail_times < max_fail_times: + try: + starts, goals = [None] * self._num_robots, [None] * self._num_robots + for i, manager in enumerate(self.robot_manager): + start_pos, goal_pos = manager.set_start_pos_goal_pos( + forbidden_zones=starts + ) + starts[i] = ( + start_pos.x, + start_pos.y, + manager.ROBOT_RADIUS * 1.5, + ) + goals[i] = ( + goal_pos.x, + goal_pos.y, + manager.ROBOT_RADIUS * 1.5, + ) + self.obstacles_manager.reset_pos_obstacles_random( + forbidden_zones=starts + goals + ) + break + except rospy.ServiceException as e: + rospy.logwarn(repr(e)) + fail_times += 1 + if fail_times == max_fail_times: + raise Exception("reset error!") + + +class StagedMARLRandomTask(RandomMARLTask): + """ + Enforces the paradigm of curriculum learning. + The training stages are defined in 'training_curriculum.yaml' + """ + + def __init__( + self, + ns: str, + obstacles_manager: ObstaclesManager, + robot_manager: List[RobotManager], + start_stage: int = 1, + PATHS=None, + ) -> None: + super().__init__(obstacles_manager, robot_manager) + self.ns = ns + self.ns_prefix = f"/{ns}/" if ns else "" + + self._curr_stage = start_stage + self._stages = {} + self._PATHS = PATHS + self._read_stages_from_yaml() + + # check start stage format + if not isinstance(start_stage, int): + raise ValueError("Given start_stage not an Integer!") + if self._curr_stage < 1 or self._curr_stage > len(self._stages): + raise IndexError( + "Start stage given for training curriculum out of bounds! Has to be between {1 to %d}!" + % len(self._stages) + ) + rospy.set_param("/curr_stage", self._curr_stage) + + # hyperparamters.json location + self.json_file = os.path.join(self._PATHS.get("model"), "hyperparameters.json") + if not rospy.get_param("debug_mode"): + assert os.path.isfile(self.json_file), ( + "Found no 'hyperparameters.json' at %s" % self.json_file + ) + + self._lock_json = FileLock(f"{self.json_file}.lock") + + # subs for triggers + self._sub_next = rospy.Subscriber( + f"{self.ns_prefix}next_stage", Bool, self.next_stage + ) + self._sub_previous = rospy.Subscriber( + f"{self.ns_prefix}previous_stage", Bool, self.previous_stage + ) + + self._initiate_stage() + + def next_stage(self, *args, **kwargs): + if self._curr_stage < len(self._stages): + self._curr_stage = self._curr_stage + 1 + self._initiate_stage() + + if self.ns == "eval_sim": + rospy.set_param("/curr_stage", self._curr_stage) + if not rospy.get_param("debug_mode"): + with self._lock_json: + self._update_curr_stage_json() + + if self._curr_stage == len(self._stages): + rospy.set_param("/last_stage_reached", True) + else: + print( + f"({self.ns}) INFO: Tried to trigger next stage but already reached last one" + ) + + def previous_stage(self, *args, **kwargs): + if self._curr_stage > 1: + rospy.set_param("/last_stage_reached", False) + + self._curr_stage = self._curr_stage - 1 + self._initiate_stage() + + if self.ns == "eval_sim": + rospy.set_param("/curr_stage", self._curr_stage) + with self._lock_json: + self._update_curr_stage_json() + else: + print( + f"({self.ns}) INFO: Tried to trigger previous stage but already reached first one" + ) + + def _initiate_stage(self): + self._remove_obstacles() + + static_obstacles = self._stages[self._curr_stage]["static"] + dynamic_obstacles = self._stages[self._curr_stage]["dynamic"] + + self.obstacles_manager.register_random_static_obstacles( + self._stages[self._curr_stage]["static"] + ) + self.obstacles_manager.register_random_dynamic_obstacles( + self._stages[self._curr_stage]["dynamic"] + ) + + print( + f"({self.ns}) Stage {self._curr_stage}:" + f"Spawning {static_obstacles} static and {dynamic_obstacles} dynamic obstacles!" + ) + + def _read_stages_from_yaml(self): + file_location = self._PATHS.get("curriculum") + if os.path.isfile(file_location): + with open(file_location, "r") as file: + self._stages = yaml.load(file, Loader=yaml.FullLoader) + assert isinstance( + self._stages, dict + ), "'training_curriculum.yaml' has wrong fromat! Has to encode dictionary!" + else: + raise FileNotFoundError( + "Couldn't find 'training_curriculum.yaml' in %s " + % self._PATHS.get("curriculum") + ) + + def _update_curr_stage_json(self): + with open(self.json_file, "r") as file: + hyperparams = json.load(file) + try: + hyperparams["curr_stage"] = self._curr_stage + except Exception as e: + raise Warning( + f" {e} \n Parameter 'curr_stage' not found in 'hyperparameters.json'!" + ) + else: + with open(self.json_file, "w", encoding="utf-8") as target: + json.dump(hyperparams, target, ensure_ascii=False, indent=4) + + def _remove_obstacles(self): + self.obstacles_manager.remove_obstacles() + + +@unique +class ARENA_TASKS(Enum): + MANUAL = "manual" + RANDOM = "random" + STAGED = "staged" + SCENARIO = "scenario" + + +def get_mode(mode: str) -> ARENA_TASKS: + return ARENA_TASKS(mode) + + +def get_MARL_task( + ns: str, + mode: str, + robot_ids: List[str], + PATHS: dict, + start_stage: int = 1, +) -> ABSMARLTask: + """Function to return desired navigation task manager. + + Args: + ns (str): Environments' ROS namespace. There should only be one env per ns. + mode (str): avigation task mode for the agents. Modes to chose from: ['random', 'staged']. \ + Defaults to "random". + robot_ids (List[str]): List containing all robots' names in order to address the right namespaces. + start_stage (int, optional): Starting difficulty level for the learning curriculum. Defaults to 1. + PATHS (dict, optional): Dictionary containing program related paths. Defaults to None. + + Raises: + NotImplementedError: The manual task mode is currently not implemented. + NotImplementedError: The scenario task mode is currently not implemented. + + Returns: + ABSMARLTask: A task manager instance. + """ + assert type(robot_ids) is list + + task_mode = get_mode(mode) + + # get the map + service_client_get_map = rospy.ServiceProxy("/static_map", GetMap) + map_response = service_client_get_map() + + # use rospkg to get the path where the model config yaml file stored + models_folder_path = rospkg.RosPack().get_path("simulator_setup") + + # robot's yaml file is needed to get its configurations etc. + robot_model = rospy.get_param("model") + base_robot_yaml = os.path.join( + models_folder_path, "robot", f"{robot_model}.model.yaml" + ) + + robot_manager = [ + RobotManager( + ns=ns, + map_=map_response.map, + robot_yaml_path=base_robot_yaml, + robot_type=robot_model, + robot_id=name, + ) + for name in robot_ids + ] + + obstacles_manager = ObstaclesManager(ns, map_response.map) + + task = None + if task_mode == ARENA_TASKS.MANUAL: + raise NotImplementedError + if task_mode == ARENA_TASKS.RANDOM: + rospy.set_param("/task_mode", "random") + obstacles_manager.register_random_obstacles(10, 1.0) + task = RandomMARLTask(obstacles_manager, robot_manager) + if task_mode == ARENA_TASKS.STAGED: + rospy.set_param("/task_mode", "staged") + task = StagedMARLRandomTask( + ns, obstacles_manager, robot_manager, start_stage, PATHS + ) + if task_mode == ARENA_TASKS.SCENARIO: + raise NotImplementedError + return task diff --git a/task_generator/task_generator/robot_manager.py b/task_generator/task_generator/robot_manager.py index 89f9ef0db..97baca81e 100755 --- a/task_generator/task_generator/robot_manager.py +++ b/task_generator/task_generator/robot_manager.py @@ -1,5 +1,6 @@ # from math import ceil, sqrt import math +import rospkg import yaml import os import threading @@ -26,9 +27,7 @@ class RobotManager: is managed """ - def __init__( - self, ns: str, map_: OccupancyGrid, robot_yaml_path: str, timeout=20 - ): + def __init__(self, ns: str, map_: OccupancyGrid, robot_yaml_path: str, timeout=20): """[summary] Args: @@ -54,9 +53,7 @@ def __init__( f"{self.ns_prefix}spawn_model", SpawnModel ) # it's only needed in training mode to send the clock signal. - self._step_world = rospy.ServiceProxy( - f"{self.ns_prefix}step_world", StepWorld - ) + self._step_world = rospy.ServiceProxy(f"{self.ns_prefix}step_world", StepWorld) # publisher # publish the start position of the robot @@ -99,7 +96,18 @@ def _get_robot_configration(self, robot_yaml_path): robot_yaml_path ([type]): [description] """ self.ROBOT_NAME = os.path.basename(robot_yaml_path).split(".")[0] - self.ROBOT_RADIUS = rospy.get_param("radius") + + robot_config = os.path.join( + rospkg.RosPack().get_path("arena_local_planner_drl"), + "configs", + "action_spaces", + "default_settings_" + self.ROBOT_NAME + ".yaml", + ) + + with open(robot_config, "r", encoding="utf-8") as target: + config = yaml.load(target, Loader=yaml.FullLoader) + self.ROBOT_RADIUS = config["robot"]["radius"] + with open(robot_yaml_path, "r") as f: robot_data = yaml.safe_load(f) @@ -134,9 +142,7 @@ def move_robot(self, pose: Pose2D): # assert self.step_size * \ # self.LASER_UPDATE_RATE == 1, f"TO run the traning successfully, make sure the laser_update_rate*step_size == 1 \ # \n\tcurrent step_size:\t {self.step_size}\n\tcurrent laser's update rate:\t {self.LASER_UPDATE_RATE} " - for _ in range( - math.ceil(1 / (self.step_size * self.LASER_UPDATE_RATE)) - ): + for _ in range(math.ceil(1 / (self.step_size * self.LASER_UPDATE_RATE))): self._step_world() def set_start_pos_random(self): @@ -179,31 +185,20 @@ def dist(x1, y1, x2, y2): if start_pos is None: start_pos_ = Pose2D() - ( - start_pos_.x, - start_pos_.y, - start_pos_.theta, - ) = get_random_pos_on_map( + (start_pos_.x, start_pos_.y, start_pos_.theta,) = get_random_pos_on_map( self._free_space_indices, self.map, self.ROBOT_RADIUS * 2 ) else: start_pos_ = start_pos if goal_pos is None: goal_pos_ = Pose2D() - ( - goal_pos_.x, - goal_pos_.y, - goal_pos_.theta, - ) = get_random_pos_on_map( + (goal_pos_.x, goal_pos_.y, goal_pos_.theta,) = get_random_pos_on_map( self._free_space_indices, self.map, self.ROBOT_RADIUS * 2 ) else: goal_pos_ = goal_pos - if ( - dist(start_pos_.x, start_pos_.y, goal_pos_.x, goal_pos_.y) - < min_dist - ): + if dist(start_pos_.x, start_pos_.y, goal_pos_.x, goal_pos_.y) < min_dist: i_try += 1 continue # move the robot to the start pos diff --git a/task_generator/task_generator/utils.py b/task_generator/task_generator/utils.py index 9653e8af0..eac16f5d9 100755 --- a/task_generator/task_generator/utils.py +++ b/task_generator/task_generator/utils.py @@ -30,7 +30,11 @@ def get_random_pos_on_map(free_space_indices, map_: OccupancyGrid, safe_dist: fl def is_pos_valid(x_in_meters, y_in_meters): for forbidden_zone in forbidden_zones: - if (x_in_meters-forbidden_zone[0])**2+(y_in_meters-forbidden_zone[1])**2 < (forbidden_zone[2]+safe_dist)**2: + if ( + forbidden_zone + and (x_in_meters - forbidden_zone[0]) ** 2 + (y_in_meters - forbidden_zone[1]) ** 2 + < (forbidden_zone[2] + safe_dist) ** 2 + ): return False # in pixel @@ -48,8 +52,7 @@ def is_pos_valid(x_in_meters, y_in_meters): try: value = map_.data[index] except IndexError: - print("IndexError: index: %d, map_length: %d" % - (index, len(map_.data))) + print("IndexError: index: %d, map_length: %d" % (index, len(map_.data))) return False if value != 0: @@ -57,7 +60,8 @@ def is_pos_valid(x_in_meters, y_in_meters): return True assert len(free_space_indices) == 2 and len(free_space_indices[0]) == len( - free_space_indices[1]), "free_space_indices is not correctly setup" + free_space_indices[1] + ), "free_space_indices is not correctly setup" if forbidden_zones is None: forbidden_zones = [] @@ -66,7 +70,7 @@ def is_pos_valid(x_in_meters, y_in_meters): n_check_failed = 0 x_in_meters, y_in_meters = None, None while not pos_valid: - idx = random.randint(0, n_freespace_cells-1) + idx = random.randint(0, n_freespace_cells - 1) # in cells y_in_cells, x_in_cells = free_space_indices[0][idx], free_space_indices[1][idx] # convert x, y in meters @@ -76,8 +80,7 @@ def is_pos_valid(x_in_meters, y_in_meters): if not pos_valid: n_check_failed += 1 if n_check_failed > 100: - raise Exception( - "cann't find any no-occupied space please check the map information") + raise Exception("cann't find any no-occupied space please check the map information") # in radius theta = random.uniform(-math.pi, math.pi)