diff --git a/docker-compose.yml b/docker-compose.yml index 2afea6f..d8826cd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -88,6 +88,37 @@ services: - POLL_INTERVAL=${POLL_INTERVAL:-15} restart: unless-stopped + teleop: + build: + context: teleop + dockerfile: Dockerfile + platforms: + - linux/amd64 + - linux/arm64 + image: raspbot_v2_teleop:latest + network_mode: host + ipc: host + stdin_open: true + tty: true + devices: + - ${JOYSTICK_DEV:-/dev/input/js0}:/dev/input/js0 + - ${JOYSTICK2_DEV:-/dev/input/js1}:/dev/input/js1 + - ${JOYSTICK_EVENT_DEV:-/dev/input/event0}:/dev/input/event0 + environment: + - ROS_DOMAIN_ID=${ROS_DOMAIN_ID:-0} + # Joystick config name — must match a file in teleop_twist_joy/config/ (without .config.yaml). + # e.g. ps5, ps4, xbox, atk3. Leave unset to use teleop_twist_joy defaults. + - JOY_CONFIG=${JOY_CONFIG:-} + # FastDDS profile restricts DDS traffic to a single interface. + # Override FASTDDS_INTERFACE in .env or on the command line (e.g. eth0, wlan1). + - FASTDDS_DEFAULT_PROFILES_FILE=/fastdds_wifi.xml + - FASTDDS_INTERFACE=${FASTDDS_INTERFACE:-wlan0} + # Not started by default — run explicitly: + # keyboard: docker compose run --rm teleop teleop-keyboard + # joystick: docker compose run --rm teleop teleop-joystick + profiles: + - teleop + webui: build: context: webui diff --git a/teleop/Dockerfile b/teleop/Dockerfile new file mode 100644 index 0000000..9fe6f6b --- /dev/null +++ b/teleop/Dockerfile @@ -0,0 +1,21 @@ +ARG ROS_DISTRO=kilted +FROM ros:${ROS_DISTRO}-ros-base +ARG ROS_DISTRO + +RUN apt-get update && apt-get install -y --no-install-recommends \ + ros-${ROS_DISTRO}-teleop-twist-keyboard \ + ros-${ROS_DISTRO}-teleop-twist-joy \ + && rm -rf /var/lib/apt/lists/* + +COPY src/fastdds_wifi.xml /fastdds_wifi.xml +COPY src/teleop-keyboard /usr/local/bin/teleop-keyboard +COPY src/teleop-joystick /usr/local/bin/teleop-joystick +RUN chmod +x /usr/local/bin/teleop-keyboard /usr/local/bin/teleop-joystick + +RUN echo '#!/bin/bash' > /entrypoint.sh \ + && echo 'set -e' >> /entrypoint.sh \ + && echo "source /opt/ros/${ROS_DISTRO}/setup.bash" >> /entrypoint.sh \ + && echo 'exec "$@"' >> /entrypoint.sh \ + && chmod +x /entrypoint.sh + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/teleop/README.md b/teleop/README.md new file mode 100644 index 0000000..2c533cc --- /dev/null +++ b/teleop/README.md @@ -0,0 +1,158 @@ +# Teleop + +Container for manually driving the robot via keyboard or joystick. +Both modes publish `TwistStamped` on `/cmd_vel` as required by the mecanum drive controller. + +The container is not started by the default `docker compose up` — it must be launched explicitly with `docker compose run`. + +## Prerequisites + +Build the image once before first use: + +```bash +docker compose build teleop +``` + +## Keyboard + +```bash +docker compose run --rm teleop teleop-keyboard +``` + +Use the standard `teleop_twist_keyboard` bindings (`i`, `,`, `j`, `l`, etc.) to drive. +Press `k` to stop. + +## Joystick + +```bash +docker compose run --rm teleop teleop-joystick +``` + +The script starts `joy_node` and `teleop_twist_joy_node` together; both are stopped +when you press Ctrl+C. + +The controller layout defaults to `ps5`. Override `JOY_CONFIG` with any config name +from the `teleop_twist_joy` package (e.g. `ps4`, `xbox`, `atk3`): + +```bash +JOY_CONFIG=xbox docker compose run --rm teleop teleop-joystick +``` + +To list all available configs: + +```bash +docker compose run --rm teleop bash -c \ + "ls \$(ros2 pkg prefix teleop_twist_joy)/share/teleop_twist_joy/config/" +``` + +The container expects the joystick at `/dev/input/js0`. +If your device is at a different path, set `JOYSTICK_DEV` before running: + +```bash +JOYSTICK_DEV=/dev/input/js1 docker compose run --rm teleop teleop-joystick +``` + +## Running from a remote machine + +The container includes a FastDDS profile that restricts DDS discovery and traffic +to a single network interface, preventing traffic leaking onto unintended interfaces +(e.g. a wired link alongside the robot's Wi-Fi). + +The interface defaults to `wlan0`. Override it with the `FASTDDS_INTERFACE` variable: + +```bash +FASTDDS_INTERFACE=wlan1 docker compose run --rm teleop teleop-keyboard +``` + +Or set it permanently in your `.env` file: + +``` +FASTDDS_INTERFACE=wlan0 +``` + +The robot containers do not currently apply this FastDDS profile, so both ends must +be reachable on the configured interface for DDS discovery to succeed. Ensure the +`ROS_DOMAIN_ID` matches on all machines. + + +## Useful commands + +### Working out the network interface to bind to + +TODO: show how to find the correct network interface to bind FastDDS to... +TODO: Create a script to do this? + +Look at the output of `ip addr`, and see which interface is on the sane network as the robot. + +For example, this output + +```bash +___snip___ +3: wlp195s0: mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether 84:9e:56:9c:a1:b5 brd ff:ff:ff:ff:ff:ff + inet 192.168.1.207/24 brd 192.168.1.255 scope global dynamic noprefixroute wlp195s0 + valid_lft 79183sec preferred_lft 79183sec + inet6 fe80::32f4:b953:b7ca:e415/64 scope link noprefixroute + valid_lft forever preferred_lft forever +___snip___ +``` +shows that interface wlp195s0 is on the same network as my robot at ip address 192.168.1.166/24. + +You should therefore set `FASTDDS_INTERFACE=wlp195s0`. + +### Working out the correct devices to pass through + +I am assuming you have a PS DualSense controller, because this is what I used to test. + +```bash +cat /proc/bus/input/devices | grep -A 8 "DualSense" +N: Name="Sony Interactive Entertainment DualSense Wireless Controller" +P: Phys= +S: Sysfs=/devices/pci0000:00/0000:00:08.3/0000:c7:00.0/usb3/3-1/3-1:1.3/0003:054C:0CE6.0001/input/input3 +U: Uniq=a0:ab:51:b5:7e:fb +H: Handlers=event3 js0 +B: PROP=0 +B: EV=20000b +B: KEY=7fdb000000000000 0 0 0 0 +B: ABS=3003f +-- +N: Name="Sony Interactive Entertainment DualSense Wireless Controller Motion Sensors" +P: Phys= +S: Sysfs=/devices/pci0000:00/0000:00:08.3/0000:c7:00.0/usb3/3-1/3-1:1.3/0003:054C:0CE6.0001/input/input5 +U: Uniq=a0:ab:51:b5:7e:fb +H: Handlers=event5 js1 +B: PROP=40 +B: EV=19 +B: ABS=3f +B: MSC=20 +-- +N: Name="Sony Interactive Entertainment DualSense Wireless Controller Touchpad" +P: Phys= +S: Sysfs=/devices/pci0000:00/0000:00:08.3/0000:c7:00.0/usb3/3-1/3-1:1.3/0003:054C:0CE6.0001/input/input6 +U: Uniq=a0:ab:51:b5:7e:fb +H: Handlers=mouse0 event6 +B: PROP=5 +B: EV=b +B: KEY=2420 10000 0 0 0 0 +B: ABS=260800000000003 +``` + +This shows me that the primary control input is on `js0` and `event3`. So I would need to launch the container like this: + +```bash +# Note that /dev/input/js0 is already mapped by default +JOYSTICK_EVENT_DEV=/dev/input/event3 docker compose run --rm teleop teleop-joystick +``` + +### Test the joystick is bound in the container + +Install the jstest package + +```bash +# In the container +apt update +apt-get install joystick +# Inside the container, the joystick is always mapped to js0 +jstest /dev/input/js0 + +``` \ No newline at end of file diff --git a/teleop/src/fastdds_wifi.xml b/teleop/src/fastdds_wifi.xml new file mode 100644 index 0000000..211ee52 --- /dev/null +++ b/teleop/src/fastdds_wifi.xml @@ -0,0 +1,20 @@ + + + + + udp_wifi + UDPv4 + +
${FASTDDS_INTERFACE}
+
+
+
+ + + + udp_wifi + + false + + +
\ No newline at end of file diff --git a/teleop/src/teleop-joystick b/teleop/src/teleop-joystick new file mode 100644 index 0000000..18e539e --- /dev/null +++ b/teleop/src/teleop-joystick @@ -0,0 +1,13 @@ +#!/bin/bash +ros2 run joy joy_node & +JOY_PID=$! +trap "kill $JOY_PID 2>/dev/null" EXIT + +PARAMS=(-p publish_stamped_twist:=true) +if [[ -n "${JOY_CONFIG}" ]]; then + CONFIG_PATH="$(ros2 pkg prefix teleop_twist_joy)/share/teleop_twist_joy/config/${JOY_CONFIG}.config.yaml" + PARAMS=(--params-file "$CONFIG_PATH" "${PARAMS[@]}") +fi + +exec ros2 run teleop_twist_joy teleop_node \ + --ros-args "${PARAMS[@]}" "$@" diff --git a/teleop/src/teleop-keyboard b/teleop/src/teleop-keyboard new file mode 100644 index 0000000..7daddba --- /dev/null +++ b/teleop/src/teleop-keyboard @@ -0,0 +1,3 @@ +#!/bin/bash +exec ros2 run teleop_twist_keyboard teleop_twist_keyboard \ + --ros-args -p stamped:=true "$@" diff --git a/troubleshooting.md b/troubleshooting.md index 52bc1ba..2a90811 100644 --- a/troubleshooting.md +++ b/troubleshooting.md @@ -20,4 +20,5 @@ If you are getting a message like: This could be because there is no `/tf` topic available. This topic is used to describe the relationship between coordinate systems (robot position, lidar position, camera position etc). - If this is the case, you can changet the fixed frame reference to the lidar itself. Change the `Global Options -> Fixed Frame` option from `map` to `laser` to tell the system to use the laser as the base of all transforms. \ No newline at end of file + If this is the case, you can changet the fixed frame reference to the lidar itself. Change the `Global Options -> Fixed Frame` option from `map` to `laser` to tell the system to use the laser as the base of all transforms. +