Getting Started with cf.PyControl

cf.PyControl is a high-level controller for Crazyflie drones with a web-based API.

At its core, drone behavior is governed by an internal state machine, which defines how the Crazyflie should act under various conditions. These state transitions and actions can be triggered externally via HTTP web endpoints, making the controller easy to integrate with other tools or platforms.

This page will guide you through installing and using cf.PyControl, which is provided in a portable way using Docker containers.


Note: This page assumes that you know the radio URI of your Crazyflie drone.

  • The default radio URI for real Crazyflie probably is radio://0/80/2M/E7E7E7E7E7 or radio://0/80/2M/E7E7E7E7E1.
  • If you are using a virtual Crazyflie, the default radio URI is radio://0/80/2M/e7e7e7e701.

Note: Make sure you have at least the flow deck installed if you use a real Crazyflie drone.


Start the Docker Container

A standalone cf.PyControl web and terminal interface is provided via a Docker container. The cfclient tool to configure and control the Crazyflie is also included in the container.

First, the container only needs to be built once:

$ cd ~/uniagent_ws/cps-asset/crazyflie2.x/controller/cf.PyControl
$ sudo docker build -t cf-pyctrl -f .devcontainer/Dockerfile .

The build process can take up to 2 min.

After, you can start the cf.PyControl Docker container as follows.

(Linux)

$ sudo docker run --rm -it \
--device-cgroup-rule='c 189:* rmw' -v /run/udev:/run/udev:ro -v /dev:/dev \
--net=host --ipc=host --pid=host \
--env="DISPLAY" \
--env ROS_DOMAIN_ID=30 \
--env="XAUTHORITY=$XAUTHORITY" \
--volume="$XAUTHORITY:$XAUTHORITY" \
--gpus all -e NVIDIA_DRIVER_CAPABILITIES=all \
--volume="/tmp/.X11-unix:/tmp/.X11-unix:rw" \
cf-pyctrl

Note: In --device-cgroup-rule, replace the 189 with the major device number you obtained in the initial setup.

(Windows) Run this from a WSL2 shell (not PowerShell):

$ sudo docker run --rm -it \
  --net=host \
  --ipc=host \
  --env ROS_DOMAIN_ID=30 \
  --env DISPLAY=host.docker.internal:0.0 \
  --env NVIDIA_VISIBLE_DEVICES=all \
  --env NVIDIA_DRIVER_CAPABILITIES=all \
  --gpus all \
  cf-pyctrl

The container is started with:

  • Access to USB devices for Crazyflie operation
  • GPU-accelerated Container (Nvidia)

Unpack the Crazyflie

Unpack the Crazyflie and complete the standard setup by following the official Bitcraze guide: https://www.bitcraze.io/documentation/start/.

Plug in the Crazyradio USB and ensure the drone batteries are fully charged.

unpack the crazyflie

Place the Crazyflie on the Ground

Place the Crazyflie securely on the ground and switch on the Crazyflie:

crazyflie on a orange landing pad

(Optional) cfclient

Configure the drone using cfclient:

:# cfclient
INFO:cfclient.gui:Disabling STL printouts
INFO:cfclient.utils.input.inputreaders:Input readers: ['linuxjsdev', 'pysdl2']
INFO:cfclient.utils.input.inputreaders:Successfully initialized [linuxjsdev]
...

Start the Python Controller

Inside the Docker container execute the following command to start the Crazyflie controller.

First, change to the correct directory:

:# cd /home/user/dev_ws/libs/crazyflie-controller/bin

For a real drone:

:# ./cfpyctrl.sh --uri radio://0/80/2M/E7E7E7E7E1 --port 5000 --wsendpoint --wsport 8765

Console Output

Parameters

  • Adjust the radio address with --uri as needed or configure it with the tool cfclient.
  • Adjust the webservice port with --port [PORT_NUMBER] when running multiple instances of the controller.
  • Adjust the websocket port with --wsendpoint --wsport [PORT_NUMBER] when running multiple instances of the controller.

More parameters are explained here.

Overview of the Actions of the Crazyflie

After opening the URL http://0.0.0.0:5000/routes in the browser, you will see all available commands of the Crazyflies internal state machine:

crazyflie actions as webservice

You can also use curl to inspect the available routes:

$ curl http://0.0.0.0:5000/routes

Note: As indicated by the $ sign in front of the curl command, we can communicate with the controller from the host system since the Docker container is connected to the host system via the --net=host flag.


State machine

A picture of the state machine governing the Crazyflie behavior is depicted below:

State machine of the Crazyflie drone

Basic Commands

A detailed list of all commands is available in the respective README of the cf.PyControl repository.

First, activate the drone to release the software-based security lock:

$ curl -d {} http://127.0.0.1:5000/activate_idle

Execute the following command to take off. The drone take offs to a height of 0.5 meters (default internal value).

$ curl -d {} http://127.0.0.1:5000/begin_takeoff

The next command will navigate the drone to the position (1.0, 1.0, 0.5)

$ curl -d {} http://localhost:5000/navigate/1.0/1.0/0.5

Sequential Commands

The following commands will take off the drone and then land it again. The commands are executed sequentially:

$ curl -d {} http://127.0.0.1:5000/activate_idle && \
  curl -d {} http://127.0.0.1:5000/begin_takeoff && \
  curl -d {} http://127.0.0.1:5000/begin_landing

The internal state machine will take care of the transition between the states. If one request fails, the state machine will remain in the last working state.

The ground effect is visible when landing the tiny drone.

Monitoring the Crazyflie

  • View the output of the controller in the terminal
  • Connect to the websocket server to receive the output of the Crazyflie status such as position, velocity, and battery level.

Websocket Server

You need to install websocat before.

The websocket server is started with the --wsendpoint --wsport flag. Therefore, open a new Docker container and connect to the websocket server. Change the address to the port of the cf.PyControl websocket server if necessary:

$ chmod +x ./websocat
$ ./websocat ws://localhost:8765

The output will be similar to the following:

{"message": "crazyflie_position", "value": "[19.37225914001465, 2.3541359901428223, 0.016074998304247856]"}
{"message": "crazyflie_position", "value": "[19.378889083862305, 2.3584070205688477, 0.01522907055914402]"}
{"message": "crazyflie_position", "value": "[19.37879180908203, 2.3618288040161133, 0.014867031946778297]"}
{"message": "crazyflie_position", "value": "[19.381799697875977, 2.3585495948791504, 0.015445047058165073]"}

Troubleshooting

If you get connection errors such as "Too many packets lost":

--[starting] Connecting to drone now ...
Traceback (most recent call last):
  File "/home/user/dev_ws/libs/crazyflie-controller/src/cf-ctrl-service.py", line 281, in <module>
    with SyncCrazyflie(URI, cf=Crazyflie(rw_cache='./cache')) as scf:
  File "/usr/local/lib/python3.10/dist-packages/cflib/crazyflie/syncCrazyflie.py", line 119, in __enter__
    self.open_link()
  File "/usr/local/lib/python3.10/dist-packages/cflib/crazyflie/syncCrazyflie.py", line 95, in open_link
    raise Exception(self._error_message)
Exception: Too many packets lost

Try to:

  • Restart the Crazyflie
  • Unplug the Crazyradio PA from the USB port and plug it in again, then restart the Crazyflie
  • Check the battery status with cfclient and recharge if necessary.
  • When executed curl commands to communicate with the controller inside the Docker container, make sure to use the --net=host flag to connect to the host system.
Previous Next