Add container that can be run on a remote machine to move the robot
This commit is contained in:
@@ -88,6 +88,37 @@ services:
|
|||||||
- POLL_INTERVAL=${POLL_INTERVAL:-15}
|
- POLL_INTERVAL=${POLL_INTERVAL:-15}
|
||||||
restart: unless-stopped
|
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:
|
webui:
|
||||||
build:
|
build:
|
||||||
context: webui
|
context: webui
|
||||||
|
|||||||
@@ -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"]
|
||||||
@@ -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: <BROADCAST,MULTICAST,UP,LOWER_UP> 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
|
||||||
|
|
||||||
|
```
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<profiles xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles">
|
||||||
|
<transport_descriptors>
|
||||||
|
<transport_descriptor>
|
||||||
|
<transport_id>udp_wifi</transport_id>
|
||||||
|
<type>UDPv4</type>
|
||||||
|
<interfaceWhiteList>
|
||||||
|
<address>${FASTDDS_INTERFACE}</address>
|
||||||
|
</interfaceWhiteList>
|
||||||
|
</transport_descriptor>
|
||||||
|
</transport_descriptors>
|
||||||
|
<participant profile_name="default_profile" is_default_profile="true">
|
||||||
|
<rtps>
|
||||||
|
<userTransports>
|
||||||
|
<transport_id>udp_wifi</transport_id>
|
||||||
|
</userTransports>
|
||||||
|
<useBuiltinTransports>false</useBuiltinTransports>
|
||||||
|
</rtps>
|
||||||
|
</participant>
|
||||||
|
</profiles>
|
||||||
@@ -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[@]}" "$@"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
exec ros2 run teleop_twist_keyboard teleop_twist_keyboard \
|
||||||
|
--ros-args -p stamped:=true "$@"
|
||||||
@@ -21,3 +21,4 @@ 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).
|
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.
|
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.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user