Contents

Bebop Drone ROS 1 in Docker

Bebop Drone ROS 1 in Docker

Whoever has worked with ROS notices that it takes some time to install it on a new machine. So to containerize it allows you to run ROS on any machine without having to actually install it. This is very useful if you want to run ROS on multiple machines, or you want to have a homogen environment for your ROS project.

Introduction

“it just works on this one computer”

In this post I am showing that it is possible to run the bebop Drone diver together with ROS 1 in a docker container. The docker container is based on the ROS docker image. For this project we are going to use ros:melodic. The drone driver is based on the Parrot Bebop driver

Prerequisites

Architecture


┌─────────────────────────────────────────┐
│ Docker compose                          │
│           ┌──────────────┐              │
│        ┌─►│  ROS Master  │◄──┐          │
│        │  └──────────────┘   │          │
│        │ ROS                 │ ROS      │
│        ▼                     ▼          │
│   ┌───────────────┐  ROS  ┌────────┐    │
│   │ Beebop Driver │◄─────►│ Python │    │
│   └───────────────┘       └────────┘    │
│        │ UDP                            │
└────────┼────────────────────────────────┘
         │ wifi
      xx  xx
      xx  xx
        xx
      xx  xx
      xx  xx
    Beebop Drone

The Beebop drone is connected to the computer via wifi. the ROS master, the Beebop driver and the python script each one of them runs in thier own docker container. The Beebop driver is a ROS node that is responsible for the communication with the drone, while python script is a ROS node that is responsible for the control of the drone.

To make this architecture woking we need to make sure that the docker containers can communicate with each other. So all containers are going to be in the same network. Furthermore we need to make sure that the drone connector can communicate directly with the drone. So we have to export the UDP port 43210 from the docker container to the host machine. Otherwise we get the following error:

connector   | [ERROR] [1673947830.046306262]: [ARNETWORK_Sender] 09:30:30:045 | ARNETWORK_Sender_ProcessBufferToSend:405 - [0xffff7c0033d0] Timeout waiting for ack in buffer 11
connector   | [ERROR] [1673947830.046451179]: [ARNETWORK_Sender] 09:30:30:046 | ARNETWORK_Sender_ProcessBufferToSend:421 - [0xffff7c0033d0] Will retry sending data of buffer 11
connector   | [ERROR] [1673947830.198080554]: [ARNETWORK_Sender] 09:30:30:197 | ARNETWORK_Sender_ProcessBufferToSend:405 - [0xffff7c0033d0] Timeout waiting for ack in buffer 11
connector   | [ERROR] [1673947830.198203429]: [ARNETWORK_Sender] 09:30:30:198 | ARNETWORK_Sender_ProcessBufferToSend:421 - [0xffff7c0033d0] Will retry sending data of buffer 11

Docker compose file

The docker compose file is a yaml file that defines the docker containers and the network that they are going to be in. The docker compose file is going to be in the root of the project. The docker compose file is going to look like this:

version: "3"

services:
  drone-connector:
    container_name: connector
    hostname: drone-connector
    build: ./ros-drone
    environment:
      - ROS_HOSTNAME=drone-connector
      - ROS_MASTER_URI=http://rosmaster:11311
    command: /bin/bash -c "source /entrypoint.sh; sleep 3; roslaunch bebop_driver bebop_node.launch"
    ports:
      - 43210:43210/udp
    networks:
      - ros

  rosmaster:
    container_name: master
    hostname: rosmaster
    image: ros:melodic
    command: roscore
    networks:
      - ros

  controller:
    container_name: controller
    hostname: controller
    build: ./ros-commander
    environment:
      - ROS_HOSTNAME=controller
      - ROS_MASTER_URI=http://rosmaster:11311
    command: sleep infinity
    volumes:
      - ./code:/root/code
    networks:
      - ros

networks:
  ros:
    driver: bridge

Unfortunatly there is no image for the bebop driver on docker hub. So we need to build the image ourselves. The docker compose file is going to build the image from the docker file in the ros-drone folder. The docker file is going to look like this:

FROM ros:melodic

RUN apt-get update && apt-get install build-essential python3-rosdep python3-catkin-tools -y
RUN mkdir -p ~/bebop_ws/src
WORKDIR /root/bebop_ws
RUN git clone https://github.com/AutonomyLab/bebop_autonomy.git src/bebop_autonomy
RUN . /opt/ros/melodic/setup.sh &&\
    catkin_init_workspace
RUN rosdep update
RUN rosdep install --from-paths src -i -y
RUN . /opt/ros/melodic/setup.sh &&\
    catkin build

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

For the rest we are just going to use the unmodified ROS docker image from docker hub. Although if you need to recieve packages in the python script you would have to use the beeop driver image. There the different types are already installed.

To launch the drone now, we just need to run the following command:

docker-compose up -d
sleep 10 # wait till eveything is up and running
docker exec -it controller /bin/bash -c "source /entrypoint.sh; rostopic pub --once /bebop/takeoff std_msgs/Empty"
sleep 10 # wait till drone is in the air
docker exec -it controller /bin/bash -c "source /entrypoint.sh; rostopic pub --once /bebop/land std_msgs/Empty"

Summary

So we can see, it is possible to run applications like that in a Dockercontainer. Unfortunatly it can get a bit messy using the beebop costum ROS messages in the python, but also doable.

Source code

A working demo can be found here: https://github.com/dscso/drone-control/tree/master/docker