diff --git a/README.md b/README.md index 70ea9d1..98772f5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Joy2Twist -Dockerized ROS node allowing control of ROS-powered mobile robots with Logitech F710 gamepad. Joy2Twist node is converting `sensor_msgs/Joy` message to `geometry_msgs/Twist` in order to provide velocity commands for the mobile robot. Therefore this package is compliant (but not supported by Husarion) with any other gamepad controller which is able to publish the `sensor_msgs/Joy` message. +Dockerized ROS node allowing control of ROS-powered mobile robots with Logitech F710 gamepad. Joy2Twist node is converting `sensor_msgs/Joy` message to `geometry_msgs/Twist` in order to provide velocity commands for the mobile robot. Therefore this package is compliant (but not supported by Husarion) with any other gamepad controller which is able to publish the `sensor_msgs/Joy` message. ## Setup joy @@ -46,7 +46,7 @@ ROS node is translating `/joy` topic to `/cmd_vel` topic. Following parameters change joystick axes mapped to given robot axes of freedom. For more information about parameter values, refer to the joy package [wiki page](http://wiki.ros.org/joy#Logitech_Wireless_Gamepad_F710_.28DirectInput_Mode.29). -- `~axis_linear_x` *(int, default: 3)* +- `~axis_linear_x` *(int, default: 3)* - `~axis_linear_y` *(int, default: 2)* - `~axis_angular_z` *(int, default: 0)* @@ -67,31 +67,60 @@ The robot can be operated at 3 scales of speed depending on pressed buttons. It' Available on [Docker Hub](https://hub.docker.com/r/husarion/joy2twist/tags) -### Demo +## Demo -#### Controlling ROSbot 2 with a Logitech F710 gamepad +### Controlling ROSbot 2 with a Logitech F710 gamepad -1. Clone this repo on your ROSbot: +Connect Logitech F710 dongle to the ROSbot 2 and run (on ROSbot): - ```bash - git clone https://github.com/husarion/joy2twist.git - cd joy2twist/ - ``` +```bash +cd joy2twist/demo/single_robot +docker compose -f compose.rosbot.melodic.yaml up + ``` -2. Create `demo/.env` based on `demo/.env.template` file and modify it if needed (see comments) +### Different namespace demo with a Logitech F710 gamepad - ```bash - #SBC <> STM32 serial connection. Set: - #SERIAL_PORT=/dev/ttyS1 # ROSbot 2 - #SERIAL_PORT=/dev/ttyS4 # ROSbot 2 PRO - SERIAL_PORT=/dev/ttyAMA0 # ROSbot 2R - ``` +Connect a Logitech F710 USB dongle to your PC. Clone this repo to your PC and go to the `joy2twist/demo/` directory and run in a separate terminal: -3. Launch on ROSbot +```bash +./sync_with_robot.sh +``` + +Change the namespace in the `multiple_robots/.env` file: + +```bash +ROS_NAMESPACE=robot1 +``` + +Now SSH to your robot: + +```bash +ssh husarion@ +``` + +Go to the folder `/home/husarion/demo/multiple_robots`, and launch the container for ROSbot: + +```bash +docker compose -f compose.rosbot2r.yaml up +``` + +> **Topic filtering** +> +> If you will then check on the PC the available ROS 2 nodes you will get: +> +> ```bash +> $ ros2 topic list +> /parameter_events +> /robot1/cmd_vel +> /rosout +> ``` +> +> Note that nly the single `/robot1/cmd_vel` topic is available outside the robot thanks to the configuration from the `ros2router_config.yaml` file. +> +> To control the robot by using the teleop, just run: `ros2 run teleop_twist_keyboard teleop_twist_keyboard __ns:=/robot1` + +To run the `joy2twist` container execute the following command on your PC in the `joy2twist/demo/multiple_robots` directory: - Go to the `joy2twist/demo` folder and run: - - ```bash - cd joy2twist/demo - docker compose -f compose.rosbot.yaml up - ``` +``` +docker compose -f compose.pc.yaml up +``` \ No newline at end of file diff --git a/demo/.env.template b/demo/.env.template deleted file mode 100644 index e1a34b3..0000000 --- a/demo/.env.template +++ /dev/null @@ -1,4 +0,0 @@ -# SBC <> STM32 serial connection. Set: -# SERIAL_PORT=/dev/ttyS1 # ROSbot 2 -# SERIAL_PORT=/dev/ttyS4 # ROSbot 2 PRO -SERIAL_PORT=/dev/ttyAMA0 # ROSbbot 2R diff --git a/demo/multiple_robots/.env b/demo/multiple_robots/.env new file mode 100644 index 0000000..8d729f2 --- /dev/null +++ b/demo/multiple_robots/.env @@ -0,0 +1 @@ +ROS_NAMESPACE=robot1 \ No newline at end of file diff --git a/demo/multiple_robots/compose.pc.yaml b/demo/multiple_robots/compose.pc.yaml new file mode 100644 index 0000000..9360cd0 --- /dev/null +++ b/demo/multiple_robots/compose.pc.yaml @@ -0,0 +1,13 @@ +services: + joy2twist: + image: husarion/joy2twist:humble-add-namespace + network_mode: host + ipc: host + devices: + - /dev/input + volumes: + - ./joy2twist.yaml:/joy2twist.yaml + command: > + ros2 launch joy2twist gamepad_controller.launch.py + joy2twist_params_file:=/joy2twist.yaml + namespace:=${ROS_NAMESPACE} \ No newline at end of file diff --git a/demo/multiple_robots/compose.rosbot2r.yaml b/demo/multiple_robots/compose.rosbot2r.yaml new file mode 100644 index 0000000..d8a68a6 --- /dev/null +++ b/demo/multiple_robots/compose.rosbot2r.yaml @@ -0,0 +1,21 @@ +services: + + rosbot: + image: husarion/rosbot:humble-ros2-add-namespaces + network_mode: bridge # using docker0 network interface + command: ros2 launch rosbot_bringup bringup.launch.py namespace:=${ROS_NAMESPACE} + + microros: + image: husarion/micro-ros-agent:humble-3.1.3-20231122 + network_mode: bridge # using docker0 network interface + devices: + - ${SERIAL_PORT:?err} + command: ros2 run micro_ros_agent micro_ros_agent serial -D $SERIAL_PORT serial -b 576000 # -v6 + + ros2router: + image: husarnet/ros2router:1.3.0 + network_mode: host + volumes: + - ./ros2router_config.yaml:/var/tmp/DDS_ROUTER_CONFIGURATION.yaml + environment: + - AUTO_CONFIG=FALSE \ No newline at end of file diff --git a/demo/multiple_robots/flash_firmware.sh b/demo/multiple_robots/flash_firmware.sh new file mode 100755 index 0000000..5afacd9 --- /dev/null +++ b/demo/multiple_robots/flash_firmware.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +DOCKER_IMAGE=$(yq .services.rosbot.image $(dirname "$0")/compose.rosbot2r.yaml) + +docker stop $(docker ps -q) + +docker run --rm -it --privileged \ +$DOCKER_IMAGE \ +/flash-firmware.py /root/firmware.bin \ No newline at end of file diff --git a/demo/multiple_robots/joy2twist.yaml b/demo/multiple_robots/joy2twist.yaml new file mode 100644 index 0000000..83e821c --- /dev/null +++ b/demo/multiple_robots/joy2twist.yaml @@ -0,0 +1,22 @@ +/**: + ros__parameters: + linear_velocity_factor: + fast: 1.0 + regular: 0.5 + slow: 0.2 + + angular_velocity_factor: + fast: 1.0 + regular: 0.5 + slow: 0.2 + + # This button mapping should be adjusted to the specific controller + # The following map is suited for Logitech F710 + button_index_map: + axis: + angular_z: 0 # Left joystick + linear_x: 3 # Right joystick + linear_y: 2 # Right joystick + dead_man_switch: 4 # LB + fast_mode: 7 # RT + slow_mode: 5 # RB diff --git a/demo/multiple_robots/ros2router_config.yaml b/demo/multiple_robots/ros2router_config.yaml new file mode 100644 index 0000000..0bf850b --- /dev/null +++ b/demo/multiple_robots/ros2router_config.yaml @@ -0,0 +1,16 @@ +version: v3.0 +allowlist: + - name: "rt/robot1/cmd_vel" + type: "geometry_msgs::msg::dds_::Twist_" +blocklist: [] +builtin-topics: [] +participants: + - name: DockerParticipant + kind: local + domain: 0 + whitelist-interfaces: + - 172.17.0.1 # docker0 IP address + - name: HostParticipant + kind: local + domain: 0 + ignore-participant-flags: filter_different_and_same_process # Discovery traffic from own host is discarded \ No newline at end of file diff --git a/demo/compose.panther.yaml b/demo/single_robot/compose.panther.yaml similarity index 100% rename from demo/compose.panther.yaml rename to demo/single_robot/compose.panther.yaml diff --git a/demo/compose.rosbot.yaml b/demo/single_robot/compose.rosbot2r.ros1.yaml similarity index 97% rename from demo/compose.rosbot.yaml rename to demo/single_robot/compose.rosbot2r.ros1.yaml index b0b4822..7681c70 100644 --- a/demo/compose.rosbot.yaml +++ b/demo/single_robot/compose.rosbot2r.ros1.yaml @@ -34,7 +34,7 @@ services: restart: unless-stopped tty: true devices: - - ${SERIAL_PORT} + - ${SERIAL_PORT:?err} environment: - SERIAL_PORT - ROS_MASTER_URI=http://ros-master:11311 diff --git a/demo/single_robot/compose.rosbotxl.ros2.sim.yaml b/demo/single_robot/compose.rosbotxl.ros2.sim.yaml new file mode 100644 index 0000000..92362db --- /dev/null +++ b/demo/single_robot/compose.rosbotxl.ros2.sim.yaml @@ -0,0 +1,31 @@ +x-gpu-config: + &gpu-config + runtime: nvidia + environment: + - DISPLAY=${DISPLAY:?err} + - NVIDIA_VISIBLE_DEVICES=all + - NVIDIA_DRIVER_CAPABILITIES=all + +x-cpu-config: + &cpu-config + environment: + - DISPLAY=${DISPLAY:?err} + - LIBGL_ALWAYS_SOFTWARE=1 + +services: + rosbot_xl: + image: husarion/rosbot-xl-gazebo:humble-0.8.2-20230913-stable + <<: *gpu-config + volumes: + - /tmp/.X11-unix:/tmp/.X11-unix:rw + - /dev:/dev + command: ros2 launch rosbot_xl_gazebo simulation.launch.py mecanum:=True + + joy2twist: + image: husarion/joy2twist:humble-1.0.0-20230424-stable + devices: + - /dev/input/js0 + volumes: + - ../joy2twist/config/joy2twist.yaml:/joy2twist.yaml + command: ros2 launch joy2twist gamepad_controller.launch.py + joy2twist_params_file:=/joy2twist.yaml diff --git a/demo/sync_with_robot.sh b/demo/sync_with_robot.sh new file mode 100755 index 0000000..be105ba --- /dev/null +++ b/demo/sync_with_robot.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# If your ROSbot's IP addr is 10.5.10.64 execute: +# ./sync_with_robot.sh 10.5.10.64 + +sshpass -p "husarion" rsync -vRr --delete ./ husarion@$1:/home/husarion/${PWD##*/} + +while inotifywait -r -e modify,create,delete,move ./ ; do + sshpass -p "husarion" rsync -vRr --delete ./ husarion@$1:/home/husarion/${PWD##*/} +done \ No newline at end of file diff --git a/joy2twist/launch/gamepad_controller.launch.py b/joy2twist/launch/gamepad_controller.launch.py index ef999f7..520d8bb 100644 --- a/joy2twist/launch/gamepad_controller.launch.py +++ b/joy2twist/launch/gamepad_controller.launch.py @@ -8,6 +8,12 @@ def generate_launch_description(): + namespace = LaunchConfiguration("namespace") + declare_namespace_arg = DeclareLaunchArgument( + "namespace", + default_value="", + description="Namespace for all topics and tfs", + ) joy2twist_cfg_path = PathJoinSubstitution( [FindPackageShare("joy2twist"), "config", "joy2twist.yaml"] @@ -19,12 +25,14 @@ def generate_launch_description(): description="ROS2 parameters file to use with joy2twist node", ) - joy2twist_launch = create_include_launch( - package="joy2twist", - rel_launch_path="launch/joy2twist.launch.py", - arguments={ - "joy2twist_params_file": LaunchConfiguration("joy2twist_params_file") - }, + joy2twist_launch = IncludeLaunchDescription( + PythonLaunchDescriptionSource( + [PathJoinSubstitution([FindPackageShare("joy2twist"), "launch", "joy2twist.launch.py"])] + ), + launch_arguments={ + "joy2twist_params_file": LaunchConfiguration("joy2twist_params_file"), + "namespace": namespace, + }.items(), ) joy_linux_node = Node( @@ -32,18 +40,9 @@ def generate_launch_description(): executable="joy_linux_node", # output={"stdout": "screen", "stderr": "screen"}, emulate_tty="true", + namespace=namespace ) - actions = [joy2twist_params_file_argument, joy2twist_launch, joy_linux_node] + actions = [declare_namespace_arg, joy2twist_params_file_argument, joy2twist_launch, joy_linux_node] return LaunchDescription(actions) - - -def create_include_launch(package: str, rel_launch_path: str, arguments: dict): - included_launch = IncludeLaunchDescription( - PythonLaunchDescriptionSource( - [PathJoinSubstitution([FindPackageShare(package), rel_launch_path])] - ), - launch_arguments=arguments.items(), - ) - return included_launch diff --git a/joy2twist/launch/joy2twist.launch.py b/joy2twist/launch/joy2twist.launch.py index b916824..fea2f0b 100644 --- a/joy2twist/launch/joy2twist.launch.py +++ b/joy2twist/launch/joy2twist.launch.py @@ -7,6 +7,12 @@ def generate_launch_description(): + namespace = LaunchConfiguration("namespace") + declare_namespace_arg = DeclareLaunchArgument( + "namespace", + default_value="", + description="Namespace for all topics and tfs", + ) joy2twist_cfg_path = PathJoinSubstitution( [FindPackageShare("joy2twist"), "config", "joy2twist.yaml"] @@ -24,8 +30,9 @@ def generate_launch_description(): parameters=[LaunchConfiguration("joy2twist_params_file")], # output={"stdout": "screen", "stderr": "screen"}, emulate_tty="true", + namespace=namespace ) - actions = [joy2twist_params_file_argument, joy2twist_node] + actions = [declare_namespace_arg, joy2twist_params_file_argument, joy2twist_node] return LaunchDescription(actions)