Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • danc/MicroCART
  • snawerdt/MicroCART_17-18
  • bbartels/MicroCART_17-18
  • jonahu/MicroCART
4 results
Show changes
Showing
with 641 additions and 0 deletions
---
title: Test - MEM_TYPE_TESTER
page_id: mem_type_tester
---
TBD
---
title: Trajectory - MEM_TYPE_TRAJ
page_id: mem_type_traj
---
TBD
---
title: uSD card - MEM_TYPE_USD
page_id: mem_type_usd
---
TBD
---
title: The memory subsystem
page_id: memory_subsystem
---
The memory subsystem is intended to be used for transfering larger chunks of data
between a Crazyflie and a client where real time characteristics are not important.
The memory subsystem uses the ```CRTP_PORT_MEM``` port for communication and supports basic read and write functionality of raw binary data. One packet on the CRTP level contains data for one read or write operation with information on address, size and type. A larger read or write is split up in multiple operations, where each sub-operation fits into one
CRTP packet. The sub-operations should be done in order (from lower address to higher) and
some read handlers may rely on this to update caches or similar when receiving the last part of a block.
The type can be seen as the highest level of abstraction and indicates which memory
the read/write operation will act on. There are a number of memory types (defined in ```MemoryType_t```) which each implements a read and/or write paradigm of selected parts of a virtual memory space, for a functional area of the system. A read/write
implementation may be mapped directly to a block of RAM in the Crazyflie, but it can
also be connected to other data structures through function calls where the
virtual memory map is simply a means of organaizing data for transfer.
A module in the Crazyflie firmware registeres handlers for read and/or write operations
and the framwork calls the handlers with appropriate values when memory operations are
initiated from a client.
## Memory types and mappings
* [EEPROM - MEM_TYPE_EEPROM](./MEM_TYPE_EEPROM.md)
* [One wire memory - MEM_TYPE_OW](MEM_TYPE_OW.md)
* [LED ring - MEM_TYPE_LED12](MEM_TYPE_LED12.md)
* [Loco Positioning System 1 - MEM_TYPE_LOCO](MEM_TYPE_LOCO.md)
* [Trajectory - MEM_TYPE_TRAJ](MEM_TYPE_TRAJ.md)
* [Loco Positioning System 2 - MEM_TYPE_LOCO2](MEM_TYPE_LOCO2.md)
* [Lighthouse - MEM_TYPE_LH](MEM_TYPE_LH.md)
* [Test - MEM_TYPE_TESTER](MEM_TYPE_TESTER.md)
* [uSD card - MEM_TYPE_USD](MEM_TYPE_USD.md)
* [LED ring timing - MEM_TYPE_LEDMEM](MEM_TYPE_LEDMEM.md)
* [Generic application memory - MEM_TYPE_APP](MEM_TYPE_APP.md)
* [Deck memory - MEM_TYPE_DECK_MEM](MEM_TYPE_DECK_MEM.md)
---
title: Peer to Peer API
page_id: p2p_api
---
## Introduction
Currently peer to peer communication on the crazyflie is **in development**. Now an API is made available to send P2P
messages in broadcast mode, and we are going to extend this to unicast.
P2P packets are sent and received on the same channel as the currently configured CRTP radio link. P2P packets are sent and received independently to regular CRTP packets. In order to allow for multiple appilication to use P2P communication at the same time a port number has been added to each packet, the intend being that independent service will use different P2P port. For the time being this port is not used by the API and keeping it to 0 unless otherwise needed is advised.
Furthermore, P2P packets are only sent and received from the 2.4GHz internal Crazyflie radio independently of where the CRTP link is connect (ex. the CRTP link can be connecte over USB).
The maximum data payload contained in a P2P packet is ```P2P_MAX_DATA_SIZE```. It is currently set to 60Bytes.
## Using the P2P API
Functions and structures are defined in the header file [src/hal/interface/radiolink.h](https://github.com/bitcraze/crazyflie-firmware/blob/master/src/hal/interface/radiolink.h). There is also an [app layer example](https://github.com/bitcraze/crazyflie-firmware/tree/master/examples/app_peer_to_peer) available in the example folder of the repository.
## Peer to Peer broadcast
#### Sending P2P broadcast
From the STM, a packet can be sent using the ```radiolinkSendP2PPacketBroadcast``` function. For example:
```c
static P2PPacket pk;
pk.port = 0;
pk.size = 11;
memcpy(pk.data, "Hello World", 11);
radiolinkSendP2PPacketBroadcast(&pk);
```
This function will trigger a single P2P packet to be transmitted by the radio.
#### Receiving P2P broadcast
If you want to receive packet in your function, you can register a callback with:
```c
p2pRegisterCB(p2pcallbackHandler);
```
with a function of the form of:
```c
void p2pcallbackHandler(P2PPacket *p)
{
// p->port: P2P Port
// p->size: Payload size
// p->data: Payload data
// p->rssi: RSSI of the packet. 40 means -40dBm.
}
```
The callback will be called by the task handling radio communication, it should then execute quickly (for example pushing data in a queue).
---
title: Persistent storage
page_id: persistent_storage
---
# Persistent storage
The crazyflie has a persistent storage subsystem that is intended to be used for configuration and other rarely written data.
The 7kB of the internal EEPROM is used for storage.
Fetching data should be fairly fast, storing data can be very slow if the storage space needs to be defragmented/garbage collected.
The API is documented in the [storage.h](https://github.com/bitcraze/crazyflie-firmware/blob/master/src/hal/interface/storage.h).
It currently only implements basic store/fetch/delete functions.
The data stored are buffers and are stored and fetched using a key string.
Care must be taken to not use generic keys in order to avoid collision.
## Embedded KV format
This is low level information about the format used to store data in the EEPROM.
These information are not needed to use the storage api but can be useful if one want to modify or port the memory storage.
The stored binary format is based on TLV (Type Length Value) but modified for the need of a dynamic storage.
The format assumes it is working on a EEPROM since it does not implement a proper wear leveling.
However, it can be noted that the format is already prepared to be used in flash allowing to append and discard entries without erasing the page: entries can be added and holes created by only writing zeros to a all-one memory. So, if modification are implemented using copy-on-write, this is effectively becoming a log-format and would fit a flash.
### Basic format
Each KV couple is written as:
- **Length** uint16_t: Length of the item, includes length, keylength, key and value.
- **KeyLength** uint8_t: Length of the key
- **Key** char*: Key
- **Value** void*: Data buffer
KV couples are writen one after each other. If one KV is at memory position *n*, the next one will be at memory position *n + length*.
If the key has a length of 0, it indicates a hole and the length indicates
the offset to the next entry.
A lenght of 0xffff means the end of the table.
Holes are created when an entry is deleted or modified entries.
New entries can be added either at the end of the table or in a hole that can fit the new buffer.
When there is no more space for new entries, the memory should be defragmented by moving all items into the holes, packing all the items at the begining of the table.
---
title: The Commander Framework
page_id: commanders_setpoints
---
This section will go into the commander framework, which handles the setpoint of the desired states, which the controllers will try to steer the estimated state to.
* [The Commander Module](#the-commander-module)
* [Setpoint Structure](#setpoint-structure)
* [High Level Commander](#high-level-commander)
## The Commander Module
![commander framework](/docs/images/commander_framework.png){:width="700"}
The commander module handles the incoming setpoints from several sources (src/modules/src/commander.c in the [firmware](https://github.com/bitcraze/crazyflie-firmware)). A setpoint can be set directly, either through a python script using the [cflib](https://github.com/bitcraze/crazyflie-lib-python)/ [cfclient](https://github.com/bitcraze/crazyflie-clients-python) or [the app layer](/docs/userguides/app_layer.md) (blue pathways in the figure), or by the high-level commander module (purple pathway). The High-level commander in turn, can be controlled remotely from the python library or from inside the Crazyflie.
It is important to realize that the commander module also checks how long ago a setpoint has been received. If it has been a little while (defined by threshold `COMMANDER_WDT_TIMEOUT_STABILIZE` in commander.c), it will set the attitude angles to 0 on order to keep the Crazyflie stabilized. If this takes longer than `COMMANDER_WDT_TIMEOUT_SHUTDOWN`, a null setpoint will be given which will result in the Crazyflie shutting down its motors and fall from the sky. This won’t happen if you are using the high level commander.
[go back to top](#)
## Setpoint Structure
In order to understand the commander module, you must be able to comprehend the setpoint structure. The specific implementation can be found in src/modules/interface/stabilizer_types.h as setpoint_t in the Crazyflie firmware.
There are 2 levels to control, which is:
Position (X, Y, Z)
Attitude (pitch, roll, yaw or in quaternions)
These can be controlled in different modes, namely:
Absolute mode (modeAbs)
Velocity mode (modeVelocity)
Disabled (modeDisable)
![commander framework](/docs/images/setpoint_structure.png){:width="700"}
So if absolute position control is desired (go to point (1,0,1) in x,y,z), the controller will obey values given setpoint.position.xyz if setpoint.mode.xyz is set to modeAbs. If you rather want to control velocity (go 0.5 m/s in the x-direction), the controller will listen to the values given in setpoint.velocity.xyz if setpoint.mode.xyz is set to modeVel. All the attitude setpoint modes will be set then to disabled (modeDisabled). If only the attitude should be controlled, then all the position modes are set to modeDisabled. This happens for instance when you are controlling the crazyflie with a controller through the cfclient in attitude mode.
[go back to top](#)
## High Level Commander
![high level commander](/docs/images/high_level_commander.png){:width="700"}
As already explained before: The high level commander handles the setpoints from within the firmware based on a predefined trajectory. This was merged as part of the [Crazyswarm](https://crazyswarm.readthedocs.io/en/latest/) project of the [USC ACT lab](https://act.usc.edu/). The high-level commander uses a planner to generate smooth trajectories based on actions like ‘take off’, ‘go to’ or ‘land’ with 7th order polynomials. The planner generates a group of setpoints, which will be handled by the High level commander and send one by one to the commander framework.
[go back to top](#)
## Support in the python lib (CFLib)
There are four main ways to interact with the commander framework from the [python library](https://github.com/bitcraze/crazyflie-lib-python)/.
* **autonomousSequence.py**: Send setpoints directly using the Commander class from the Crazyflie object.
* **motion_commander_demo.py**: The MotionCommander class exposes a simplified API and sends velocity setpoints continuously based on the methods called.
* **autonomous_sequence_high_level.py**: Use the high level commander directly using the HighLevelCommander class on the Crazyflie object.
* **position_commander_demo.py**: Use the PositionHlCommander class for a simplified API to send commands to the high level commander.
[go back to top](#)
---
title: Configure estimator and controller
page_id: config_est_ctrl
---
All the estimators and controllers are part of the standard firmware build and the active estimator and controller can be configured in runtime or compile time.
## Estimators
The available estimators are defined in the `StateEstimatorType` enum in `src/modules/interface/estimator.h`.
### Setting in runtime
To activate a specific estimator, set the `stabilizer.estimator` parameter to the appropriate value based on the `StateEstimatorType`.
The parameter can be set from the python client, the python lib or from an app in the Crazyflie.
### Default estimator
The complementary estimator is the default estimator.
Some decks require the kalman estimator and it is automatically activated when one of these decks are detected. The activated estimator is based on the .requiredEstimator member of the DeckDriver API.
### Setting default estimator at compile time
It is possible to force the use of a specific estimator at compile time by setting `ESTIMATOR`, see [Configure the build](/docs/building-and-flashing/build.md/#configmk).
Example:
`ESTIMATOR=kalman`
## Controller
The available controllers are defined in the `ControllerType` enum in `src/modules/interface/controller.h`.
### Setting in runtime
To activate a specific controller, set the `stabilizer.controller` parameter to the appropriate value based on the `ControllerType`.
The parameter can be set from the python client, the python lib or from an app in the Crazyflie.
### Default controller
The PID controller is the default controller.
### Setting at compile time
It is possible to force the use of a specific controller at compile time by setting `CONTROLLER`, see [Configure the build](/docs/building-and-flashing/build.md/#configmk).
Example:
`CONTROLLER=Mellinger`
---
title: Controllers in the Crazyflie
page_id: controllers
---
Once the [state estimator](/docs/functional-areas/sensor-to-control/state_estimators.md) have outputed the current (estimated) situation of the crazyflie in position velocity and attitude, it is time for the controllers to keep it that way or to move the crazyflie into a new position based on a setpoint. This is an important part of the stabilization system in the crazyflie.
* [Overview of Control](#overview-of-control)
* [Cascaded PID controller](#cascaded-pid-controller)
* Mellinger Controller (TO DO)
* INDI Controller (TO DO)
## Overview of control
There are three levels to control in the crazyflie:
* Attitude rate
* Attitude absoluut
* Position or velocity
Here is an overview of the types of controllers there are per level:
![controller overview](/docs/images/controller_overview.png){:width="500"}
We will now explain per controller how exactly they are being implemented in the [crazyflie-firmware](https://github.com/bitcraze/crazyflie-firmware/).
[go back to top](#)
## Cascaded PID controller
So the default settings in the Crazyflie firmware is the [proportional integral derivative (PID)](https://en.wikipedia.org/wiki/PID_controller) control for all desired state aspects. So the High Level Commander (HLC) or position will send desired position set-points to the PID position controller. These result in desired pitch and roll angles, which are sent directly to the attitude PID controller. These determine the desired angle rates which is send to the angle rate controller. This is also called Cascaded PID controller. That results in the desired thrusts for the roll pitch yaw and height that will be handled by the power distribution by the motors.
Here is a block schematics of how the PID controllers are implemented.
![cascaded pid controller](/docs/images/cascaded_pid_controller.png){:width="700"}
Here are the different loops of the cascaded PID explained in more detail.
### Attitude Rate PID controller
The attitude rate PID controller is the one that directly controls the attitude rate. It resieves almost directly the gyroscope rates (through a bit of filtering first) takes the error between the desired attitude rate as input. This output the commands that is send directly to the power distribution ([power_distribution_stock.c](https://github.com/bitcraze/crazyflie-firmware/blob/master/src/modules/src/power_distribution_stock.c)). The control loop runs at 500 Hz.
Check the implementation details in [attitude_pid_controller.c](https://github.com/bitcraze/crazyflie-firmware/blob/master/src/modules/src/attitude_pid_controller.c) in `attitudeControllerCorrectRatePID()`.
### Attitude PID controller
The absolute attitude PID controller is the outerloop of the attitude controller. This takes in the estimated attitude of the [state estimator](/docs/functional-areas/sensor-to-control/state_estimators.md), and takes the error of the desired attitude setpoint to control the attitude of the Crazyflie. The output is desired attitude rate which is send to the attitude rate controller. The control loop runs at 500 Hz.
Check the implementation details in [attitude_pid_controller.c](https://github.com/bitcraze/crazyflie-firmware/blob/master/src/modules/src/attitude_pid_controller.c) in `attitudeControllerCorrectAttitudePID()`.
### Position and Velocity Controller
The most outerloop of the cascaded PID controller is the position and velocity controller. It receives position or velcoityinput from a commander which are handled, since it is possible to set in the variable `setpoint_t` which stabilization mode to use `stab_mode_t` (either position: `modeAbs` or `modeVelocity`). These can be found in [stabilizer_types.h](https://github.com/bitcraze/crazyflie-firmware/blob/master/src/modules/interface/stabilizer_types.h). The control loop runs at 100 Hz.
Check the implementation details in Check the implementation details in [position_controller_pid.c](https://github.com/bitcraze/crazyflie-firmware/blob/master/src/modules/src/position_controller_pid.c) in `positionController()` and `velocityController()`.
[go back to top](#)
---
title: Stabilizer Module
page_id: stabilizer_index
---
This page is meant as an introduction and overview of the path from
sensor acquisition to motor control,also called the stabilizer module. It will not go into detail but it mostly give a general outline of how the sensor measurements go to the
state estimators to the controllers and finally distributed to the motors
by power distribution. Ofcourse, the motors have an affect on how the
crazyflie flies and that inderectly has an effect on what the sensors
detect in the next time step.
* [Sensors](#sensors)
* [State Estimation](#state-estimation)
* [State Controller](#state-controller)
* [Configure estimators and control](#configuring-controllers-and-estimators)
* [Commander Framework](#commander-framework)
* [Power Distribution](#power-distribution)
### Overview
![sensor](/docs/images/sensors_to_motors.png){:width="700"}
## Modules
### Sensors
Sensors are essential for the flight of a crazyflie. Here is selection of the sensors
listed that the crazyflie eventually uses for state estimation:
* [On-board Sensors](https://store.bitcraze.io/products/crazyflie-2-1)
* Accelerometer: acceleration in body fixed coordinates in m/s2
* Gyroscope: angle rate in roll pitch and yaw (rad/s)
* Pressure Sensor: Airpressure in mBar
* [Flowdeck v2](https://store.bitcraze.io/products/flow-deck-v2)
* ToF sensor*: Distance to a surface in milimeters
* Optical flow sensor: The detection movement of pixels in px per timesample
* [Loco positioning deck](https://store.bitcraze.io//products/loco-positioning-deck):
* Ultra Wide band module: The distance between two UWB modules or TDOA*** in meters.
* [Lighthouse deck](https://store.bitcraze.io/products/lighthouse-positioning-deck):
* IR receivers: Sweep angle of htc vive basestations in radians.
<sub><sup>_*Time-of-Flight_</sup></sub>
<sub><sup>_**[Zranger v2](https://store.bitcraze.io/collections/decks/products/z-ranger-deck-v2) also contains a laser-ranger_</sup></sub>
<sub><sup>_***Time-difference of Arrival_</sup></sub>
[go back to top](#)
### State Estimation
There are 2 state estimators in the crazyflie:
* Complementary Filter
* Extended Kalman Filter
Go to the [state estimation page](state_estimators.md) for more indepth information about how the state estimation is implemented in the crazyflie firmware.
[go back to top](#)
### State Controller
There are 3 controllers in the crazyflie
* PID controller
* INDI controller
* Mellinger controller
Go to the [controllers page](controllers.md), for more indepth information about how the controllers are implemented in the crazyflie firmware.
[go back to top](#)
### Configuring Controllers and Estimators
Go to this [configuration page](configure_estimator_controller.md), if you would like to configure different controllers and estmators,
[go back to top](#)
### Commander Framework
An desired state can be handled by the setpoint structure in position or atitude, which can be set by the cflib or the highlevel commander.
Go to the [commander page](commanders_setpoints.md), for more indepth information about how the commander framework are implemented in the crazyflie firmware, please go
[go back to top](#)
### Power Distribution
After the state controller has send out its commands, this is not the end of the line yet.
The controllers send out their commands relating to their yaw, roll and pitch angles.
How the motors should respond in order to adhere these attitude based commands depends on a few factors:
* Quadrotor configuration (found in: [power_distribution_stock.c](https://github.com/bitcraze/crazyflie-firmware/blob/master/src/modules/src/power_distribution_stock.c)):
* x-configuration: The body fixed coordinate system's x-axis is pointed in between two propellors (Default)
* +-configuration: The body fixed coordinate system's x-axis is pointed in one propellor
* Motors:
* **Explaination about this will come soon**
[go back to top](#)
---
title: State estimation
page_id: state_estimators
---
A state estimator turns sensor signals into an estimate of the state that the crazyflie is in. This is an essential part of crazyflie's stabilizing system, as explained in the [overview page](/docs/functional-areas/sensor-to-control/index.md). State estimation is really important in quadrotors (and robotics in general). The Crazyflie needs to first of all know in which angles it is at (roll, pitch, yaw). If it would be flying at a few degrees slanted in roll, the crazyflie would accelerate into that direction. Therefore the controller need to know an good estimate of current angles’ state and compensate for it. For a step higher in autonomy, a good position estimate becomes important too, since you would like it to move reliably from A to B.
* [Complementary filter](#complementary-filter)
* [Extended Kalman filter](#extended-kalman-filter)
* [References](#references)
## Complementary filter
![complementary filter](/docs/images/complementary_filter.png){:width="500"}
The complementary filter is consider a very lightweight and efficient filter which in general only uses the IMU input of the gyroscope (angle rate) and the accelerator. The estimator has been extended to also include input of the ToF distance measurement of the [Zranger deck](https://store.bitcraze.io/collections/decks/products/z-ranger-deck-v2). The estimated output is the Crazyflie’s attitude (roll, pitch, yaw) and its altitude (in the z direction). These values can be used by the controller and are meant to be used for manual control.
To checkout the implementation details, please checkout the firmware in [estimator_complementary.c](https://github.com/bitcraze/crazyflie-firmware/blob/master/src/modules/src/estimator_complementary.c) and [sensfusion6.c](https://github.com/bitcraze/crazyflie-firmware/blob/master/src/modules/src/sensfusion6.c). The complementary filter is set as the default state estimator on the Crazyflie firmware, unless a deck is mounted that requires the kalman filter.
[go back to top](#)
## Extended Kalman filter
![extended kalman filter](/docs/images/extended_kalman_filter.png){:width="500"}
The (extended) Kalman filter (EKF) is an step up in complexity compared to the complementary filter, as it accepts more sensor inputs of both internal and external sensors. It is an recursive filter that estimates the current state of the Crazyflie based on incoming measurements (in combination with a predicted standard deviation of the noise), the measurement model and the model of the system itself.
We will not go into detail on this but we encourage people to learn more about EKFs by reading up some material like [this](https://idsc.ethz.ch/education/lectures/recursive-estimation.html).
Because of more state estimation possibilities, we prefer the EKF for certain decks that can provide information for **full pose estimation** (position/velocity + attitude). These are the:
* [Flowdeck v2](https://store.bitcraze.io/collections/decks/products/flow-deck-v2)
* [Loco positioning deck](https://store.bitcraze.io/collections/positioning/products/loco-positioning-deck)
* [Lighthouse deck](https://store.bitcraze.io/products/lighthouse-positioning-deck).
* Mocap deck [passive](https://store.bitcraze.io/products/motion-capture-marker-deck) or [active](https://store.bitcraze.io/products/active-marker-deck)
When the `DeckDriver` is initialized in the [crazyflie-firmware](https://github.com/bitcraze/crazyflie-firmware/), for these decks the variable `.requiredEstimator` is set to `kalmanEstimator`. This says that the firmware should not use the default complementary filter but the EKF instead.
Here we will explain a couple of important elements that are essential to the implementation, however we do encourage people to also look into the code [estimator_kalman.c](https://github.com/bitcraze/crazyflie-firmware/blob/master/src/modules/src/estimator_kalman.c) and [kalman_core.c](https://github.com/bitcraze/crazyflie-firmware/blob/master/src/modules/src/kalman_core.c). Also read the papers of [1] and [2] for implementation details.
### Kalman supervisor
The Kalman filter has an supervisor that resets the state estimation if the values get out of bounds. This can be found here in [kalman_supervisor.c](https://github.com/bitcraze/crazyflie-firmware/blob/master/src/modules/src/kalman_supervisor.c).
### Measurement Models
This section will explain how the signals of the sensors are transformed to state estimates. These equations are the base of the measurement models of the EKF.
* [Flowdeck Measurement Model](#flowdeck-measurement-model)
* Locodeck Measurement Model (TODO)
* [Lighthouse Measurement Model](/docs/functional-areas/lighthouse/kalman_measurement_model.md)
#### Flowdeck Measurement Model
This illustration explains how the height from the VL53L1x sensor and flow from the PMW3901 sensor are combined to calculate velocity. This has been implemented by the work of [3] and can be found in [kalman_core.c](https://github.com/bitcraze/crazyflie-firmware/blob/master/src/modules/src/kalman_core.c) in the function `kalmanCoreUpdateWithFlow()`.
![flowdeck velocity](/docs/images/flowdeck_velocity.png){:width="500"}
[go back to top](#)
## References
[1] Mueller, Mark W., Michael Hamer, and Raffaello D'Andrea. "Fusing ultra-wideband range measurements with accelerometers and rate gyroscopes for quadrocopter state estimation." 2015 IEEE International Conference on Robotics and Automation (ICRA). IEEE, 2015.
[2] Mueller, Mark W., Markus Hehn, and Raffaello D’Andrea. "Covariance correction step for kalman filtering with an attitude." Journal of Guidance, Control, and Dynamics 40.9 (2017): 2301-2306.
[3] M. Greiff, Modelling and Control of the Crazyflie Quadrotor for Aggressive and Autonomous Flight by Optical Flow Driven State Estimation, Master’s thesis, Lund University, 2017
---
title: Trajectory formats
page_id: trajectory_formats
---
This document describes how the Crazyflie high-level commander stores
trajectories in the internal trajectory memory.
Trajectories for the high-level commander may be stored in one of two formats.
either as a sequence of raw 7th degree polynomials, or as a more space-efficient
representation using the same polynomials in Bernstein form. In both cases, a
single segment stores a duration and one polynomial for each of the X, Y, Z and
yaw coordinates of the trajectory.
Raw representation
------------------
The raw representation stores the coefficients of the polynomial describing
the X coordinate of the trajectory first, starting with the constant term and
ending with the 7th degree term, followed by the terms of the polynomials
describing the Y, Z and yaw coordinates, and the duration of the segment itself
in seconds. Each term and the duration is encoded as standard IEEE
single-precision floats, meaning that a single segment requires 132 bytes:
8x4 floats for the X, Y, Z and yaw components per trajectory segment, plus one
additional float per segment to store its duration. Given that the default
size of the trajectory memory is 4 Kbytes, you can only store 31 segments.
Compressed representation
-------------------------
The compressed representation was designed to be more space-efficient than the
raw representation while still trying to maintain almost the same degree of
accuracy as the raw representation.
The general guidelines of this representation are as follows:
* Durations are represented as milliseconds and are stored as signed 2-byte
integers.
* Spatial coordinates (X, Y and Z) are represented as millimeters and are stored
as signed 2-byte integers, meaning that the maximum spatial volume that this
representation can cover is roughly 64m x 64m x 64m, assuming that the origin
is at the center.
* Angles (for the yaw coordinate) are represented as 1/10th of degrees and are
stored as signed 2-byte integers.
* Trajectory segments are described with varying degrees of Bézier curves,
ranging from degree 0 (constant) to degree 7 (full 7D polynomial, as in the
raw representation).
The compressed representation starts with the description of the starting point
of the trajectory:
```
+--------------+--------------+--------------+--------------+
| X coordinate | Y coordinate | Z coordinate | Initial yaw |
+--------------+--------------+--------------+--------------+
```
This is then followed by data blocks describing the individual segments - one
data block per segment:
```
+------------------+----------------+------------------+----------------+-----+
| Segment 1 header | Segment 1 body | Segment 2 header | Segment 2 body | ... |
+------------------+----------------+------------------+----------------+-----+
```
The header of a segment is three bytes long. The first byte describes how the
X, Y, Z and yaw coordinates will be encoded in the body of the data block. The
remaining two bytes contain the duration of the segment:
```
Bits 6-7 Bits 4-5 Bits 2-3 Bits 0-1 Byte 2 Byte 3
+------------+----------+----------+----------+ +--------------+--------------+
| Yaw format | Z format | Y format | X format | | Duration LSB | Duration MSB |
+------------+----------+----------+----------+ +--------------+--------------+
```
For each of the X, Y, Z and yaw coordiates, there are two bits in the first byte
of the header. `00` means that the coordinate is constant throughout the
section (i.e. it is a zero-order Bézier curve). `01` means that the coordinate
changes linearly (it is a Bézier curve of order 1). `10` means that the
coordinate changes according to a cubic Bézier curve. `11` means that the
coordinate changes according to a full 7th degree polynomial, expressed again
as a 7th degree Bézier curve.
For instance, a header containing `0x0a 0xd0 0x07` means that the segment is
2000 milliseconds long (because `0x07d0` = 2000), and it will have a constant
yaw and Z coordinate. Cubic Bézier curves will be used to describe the X and
Y coordinates of the segment. (This is because `0x0a` = `00 00 10 10` in
binary).
Note that the choice of Bézier curves means that we need to store not the raw
coefficients of the corresponding polynomials (which may be anywhere in the full
4-byte float range), but the coordinates of the _control points_ of the Bézier
curves, whose range is much more predictable and easier to represent with a
fixed millimeter-scale quantization.
The body of the segment is then simply a concatenation of the control points
for the X, Y, Z and yaw coordinates, _omitting the first control point_
because it is always the same as the last control point of the previous
segment. (That's why we needed to store the starting point of the trajectory
separately).
```
+----------------------+----------------------+----------------------+------------------------+
| Control points for X | Control points for Y | Control points for Z | Control points for yaw |
+----------------------+----------------------+----------------------+------------------------+
```
Obviously, when the header specifies that a coordinate is constant, it means
that we do not need to store the control points for that coordinate at all
(there would be only a single control point, but we already know that it is
the same as the last control point of the previous segment). For linear
segments, we only need to store the end of the segment. For cubic Bézier
segments, we need to store the first and second control point and the end
of the segment. This can result in significant space savings if the trajectory
consists mostly of linear segments and cubic Bézier curves, especially if the
yaw does not change, or if the movement mostly occurs in the X-Y, X-Z or Y-Z
plane. Note that cubic Bézier curves are enough to ensure C0, C1 and C2
continuity (inposition, velocity and acceleration) for the trajectories.
Internally, whenever the high-level commander starts processing a trajectory
segment that is encoded using the compressed representation, it converts the
Bézier curve back into its raw polynomial representation. It means that most of
the codebase only needs to work with raw 7th degree polynomials.
A downside of the compressed representation is that it is hard to play the
trajectory backwards. The current implementation does not support reverse
traversal at all.
FlyPi/crazyflie-firmware-2021.06/docs/images/cascaded_pid_controller.png

95.8 KiB

FlyPi/crazyflie-firmware-2021.06/docs/images/commander_framework.png

125 KiB

FlyPi/crazyflie-firmware-2021.06/docs/images/complementary_filter.png

29.2 KiB

FlyPi/crazyflie-firmware-2021.06/docs/images/controller_overview.png

357 KiB

FlyPi/crazyflie-firmware-2021.06/docs/images/crtp_log.png

5.5 KiB

FlyPi/crazyflie-firmware-2021.06/docs/images/crtp_mem.png

5.91 KiB

FlyPi/crazyflie-firmware-2021.06/docs/images/deckhelloconsole.png

141 KiB

FlyPi/crazyflie-firmware-2021.06/docs/images/extended_kalman_filter.png

57.9 KiB