Workspace for DonkeyJet
Introducing my ongoing robotics project, currently named DonkeyJet, inspired by the Donkey Car project. This mobile robot is built on an RC car frame and powered by Jetson Nano, providing a hands-on platform for practicing robotics knowledge. The goal is to continually enhance its capabilities while exploring various aspects of robotics technology. While I am not certain about the name DonkeyJet, I invite you to follow me on this exciting journey of discovery as I document my progress and share insights with fellow enthusiasts in my weblog here.
Docker Images
We are using docker for this project. Read more here.
- setup remote docker build
- add Jetson IP to
/etc/hosts
asjetson
- some docker docs
- https://www.docker.com/blog/multi-arch-build-and-images-the-simple-way/
Setup for building docker image for multiple platforms which images are built natively on the corresponding hardware without emulation.
/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
export REGISTRY="<the docker registry to be used, or dockerhub user>"
docker context create jetson --docker "host=tcp://jetson:2375"
docker context create localamd64 --docker "host=unix:///var/run/docker.sock"
# just one time
# docker buildx create --use --driver-opt network=host --config=buildkitd.toml --name MultiPlatform
docker buildx create --use --driver-opt network=host --config=buildkitd-arm64.toml --name mybuilder jetson
docker buildx create --append --driver-opt network=host --config=buildkitd-amd64.toml --name mybuilder localamd64
Docker image with CUDA and ROS2
docker buildx build \
--platform linux/amd64,linux/arm64 \
-f ros2_base2.Dockerfile \
-t ${REGISTRY}/ros2_base2:latest \
--push .
# test the images
docker pull ${REGISTRY}/ros2_base2:latest
docker run \
--name ros2_base \
--rm \
-it \
--runtime nvidia \
--network host \
--gpus all \
-e DISPLAY \
${REGISTRY}/ros2_base2:latest \
bash
# test images
ros2 run demo_nodes_cpp talker
ros2 run demo_nodes_cpp listener
ROS2 Workspace Docker Container
# build my image
docker buildx build \
--platform linux/amd64,linux/arm64 \
-f ros2_ws.Dockerfile \
--build-arg BASE_IMAGE=${REGISTRY}/ros2_base2:latest \
-t ${REGISTRY}/ros2_ws:latest \
--push .
docker buildx build \
--platform linux/amd64,linux/arm64 \
-f ros2_ws.Dockerfile \
--build-arg BASE_IMAGE=${REGISTRY}/ros2_base2:latest \
-t ${REGISTRY}/ros2_ws:latest \
. --output registry.insecure=true,push=true,type=image
Docker For Development
export JETSON_IP=
function BUILD_AND_RUN(){
docker -H $JETSON_IP pull ${REGISTRY}/ros2_base2:latest
docker -H $JETSON_IP buildx build -f ros2_ws.Dockerfile --build-arg BASE_IMAGE=${REGISTRY}/ros2_base2:latest -t ${REGISTRY}/ros2_ws:latest .
docker -H $JETSON_IP run --name ros2_ws --rm -it --runtime nvidia --network host --gpus all --privileged -e DISPLAY -v /dev:/dev -v /proc:/proc -v /sys:/sys ${REGISTRY}/ros2_ws:latest bash -ic "$@"
}
export EXEC_RUN="docker -H $JETSON_IP exec -it ros2_ws /bin/bash -ic"
# Run nodes separately
BUILD_AND_RUN "ros2 run bot_hardware joy"
$EXEC_RUN "ros2 run bot_hardware pca9685"
# run the launch file
BUILD_AND_RUN "ros2 launch bot_hardware manual_control_launch.py"
# local dev env
docker run \
--name ros2_base \
--rm \
-it \
--runtime nvidia \
--network host \
--gpus all \
--privileged \
-e DISPLAY \
-v `pwd`/ros2_ws/src:/root/ros2_ws/src \
-v `pwd`/ros2_ws_tutorial/src:/root/ros2_ws_tutorial/src \
${REGISTRY}/ros2_base2:latest \
bash
Docker image with CUDA, ROS2, Realsense
docker buildx build \
--platform linux/amd64,linux/arm64 \
-f realsense.Dockerfile \
--build-arg BASE_IMAGE=${REGISTRY}/ros2_base2:latest \
-t ${REGISTRY}/ros2_realsense:latest \
--push .
# on jetson run only once
sudo curl https://raw.githubusercontent.com/IntelRealSense/librealsense/master/config/99-realsense-libusb.rules -o /etc/udev/rules.d/99-realsense-libusb.rules \
&& sudo udevadm control --reload-rules \
&& sudo udevadm trigger
docker run \
--name ros2_realsense \
--rm \
-it \
--runtime nvidia \
--network host \
--gpus all \
--privileged \
${REGISTRY}/ros2_realsense:latest \
bash
# to test run the following in the docker container
rs-depth
ros2 launch realsense2_camera rs_launch.py initial_reset:=true
Joystick
Read more About Joystick in Linux.
Test the joystick
With GUI
sudo apt install -y jstest-gtk
jstest-gtk
Without GUI
jstest /dev/input/js0
With ros
docker -H 192.168.68.68 pull ${REGISTRY}/ros2_base2:latest
docker -H 192.168.68.68 run \
--rm -it --runtime nvidia --network host \
--gpus all --privileged \
-v /dev:/dev -v /proc:/proc -v /sys:/sys \
${REGISTRY}/ros2_base2:latest \
bash
Run motors
docker run \
--name realsense \
--rm \
-it \
--privileged \
--network host \
-e DISPLAY \
--runtime nvidia \
--gpus all \
${REGISTRY}/ros2_realsense:latest \
bash
-v /dev/input:/dev/input \
-v /dev/v4l:/dev/v4l \
-v /dev:/dev \
-v /proc:/proc \
-v /sys:/sys \
# issue about Jetson.GPIO inside docker:
# https://forums.developer.nvidia.com/t/jetson-gpio-not-working-on-python-inside-the-container/180435
python -m pip install adafruit-circuitpython-servokit Jetson.GPIO
i2cdetect -y -r 1
- More about I2C in Linux
- PCA9685 datasheet
- PCA9685 Adafruit info
- The I2C address is
0x40
. - About Actutation
- I2C in Linux
PWM Signals
- PWM Period: 20 ms, PWM Frequency: 50Hz
- 1ms - 2ms high or Duty cycle: 1% - 10% with 50Hz freq
- Servo from left to right
- Throttle form full backward to full forward.
freq = 60
prescaler = 0x66 = 25M / (4096 * frequency)
i2cset -y 1 0x40 0x00 0x90
i2cset -y 1 0x40 0xFE 0x66
i2cset -y 1 0x40 0x00 0xA0
# steering
i2cset -y 1 0x40 0x0A 0x00 && \
i2cset -y 1 0x40 0x0B 0x00 && \
i2cset -y 1 0x40 0x0C 0xFA && \
i2cset -y 1 0x40 0x0D 0x00
i2cset -y 1 0x40 0x0A 0x00 0x00 0x4F 0x01 i
# throttle (85 instead of 6f is good value for test)
i2cset -y 1 0x40 0x06 0x00 && \
i2cset -y 1 0x40 0x07 0x00 && \
i2cset -y 1 0x40 0x08 0x85 && \
i2cset -y 1 0x40 0x09 0x01
i2cset -y 1 0x40 0x06 0x00 0x00 0x4F 0x01 i