This repository contains a python model of the control layer of the Crazyflie 2.x quadcopter. The considered setup is of autonomous flight with the Flowdeck V2. The model includes the physics, the state estimator (the extended kalman filter), and the PID controller implemented in the firmware. The implementation of the state estimator and of the controllers is made as adherent as possible with the actual firmware implementation.
- cfSimulator : this is the directory containing the python classes belonging to the simulator. More details on the implementation of the different classes can be found in the readme in the directory.
- flightdata : in this directory are saved the data generated by the tests.
- testCases : this directory contains the classes that can generate different reference trajectories for the different test flights.
The repository comes with two main scripts: main.py for running a test flight and plot.py to plot the flight data. Call the scripts from the command line with:
python main.py
python plot.py
This simulation model has been written with readability in mind. As a result different choices made the execution of the model fairly slow (e.g., the extensive use of classes). If you need speed, please refer to the cython-speedup branch that allows to compile the simulator to much more efficient C code (and still run it as if it was python). To achive this it leverages the Cython library. The speed-up is approximately 5 fold. The code however is much less readable.
To use the faster version of the simulator execute the following in the command line (from the main repo directory). The first line checks out to the cython-speedup branch. The second line compiles (part of) the python code to C. The rest executes the code as normal.
git checkout
./BuildCython.zsh
python main.py
python plot.py
To run a test flight it is sufficient to create a cfSimulation
object and call its run()
method.
The run method takes as input the duration of the test flight and a reference generator object.
A minimal example is:
from cfSimulator import cfSimulation
from testCases.referenceGen import Reference
duration = 10
trajecoryType = "step" # step sequence reference
sim = cfSimulation()
ref = Reference(trajecoryType)
storeObj = sim.run(ref, duration)
storeObj.save()
INPUTS: The duration
input is an integer representing the duration in seconds of the test.
A valid reference generator object is any object with a refGen()
method and a trajectoryType
field.
refGen()
should take as input the current time and return a 3 dimensional array containing the position reference in the three Cartesian axes.
trajectoryType
is a string stored also in the output flight data returned by the simulation.
OUTPUT: The call to run()
returns a FlightDataHandler
object (defined in cfSimulator/utils/FlightDataHandler.py) that can be saved to file by calling its method save()
.
If save()
is called without arguments it will store the data in a file named by the current date and time in the flightdata directory.
If a string is passed to save("file_name")
the flight data will be stored in a file named file_name in the flightdata directory.
The FlightDataHandler
class can be used to open the files containing the test results and it provides some methods to analyse the results and plot the data.
A minimal example to show all the plots available is:
from cfSimulator.utils.FlightDataHandler import FlightDataHandler as fdh
data_storage = fdh()
data_storage.open(file_location)
data_storage.show_all()
Otherwise the different available plots are:
trajectoryPlot()
: 3D plot of the flightpositionSpeedPlot()
: time plots of position and speed along the three directionssensorReadingsPlot()
: plots of the sensor readings (and some Kalman errors)controlActionPlot()
: plots of the commands to the 4 motorsz_loop_frequency_plot()
: plot of the frequency spectrum of the reference and position along the z axis
Call the desired functions to generate the figure objects and show them by calling show()
.
For example:
data_storage = fdh()
data_storage.open(file_location)
data_storage.trajectoryPlot()
data_storage.show() # this will show only the 3D trajectory plot