CprE 488 - Embedded Systems Design
MP-4: UAV Control
Assigned: Monday of Week 10
Due: Monday of Week 12
Points: 100 + bonus points
Note: the goal of this Machine Problem is for you to work with your group to increase your exposure to three different aspects of embedded system design:
A MAN HAS FALLEN INTO THE RIVER IN LEGO CITY! Start the new rescue quadcopter! HEY! Program and tune the quadcopter, and off to the rescue! Prepare the lifeline, lower the stretcher, and make the rescue! The Crazyflie collection from MicroCART!
Say hello to your Crazyflie drone! The goal at the end of this lab is to be able to smoothly control the Crazyflie with the algorithms that you will write and test. First, we will give you a brief overview of the Crazyflie system and how to set up the development environment for this lab.
This lab has been developed over the course of several years by the MicroCart Senior Design project. The MicroCart Youtube Channel has many videos you may find helpful in case you get stuck during this lab, or for ideas you can do for extra credit.
There is only one physical button on the Crazyflie, the power button. To start the Crazyflie:
Figure 1. Crazyflie top down diagram
LED Lights | Diagnostic |
flashing red LED | Calibrating |
Slow flashing LED | Sensors have not been calibrated |
Red LED flashing 5 times quickly | Failed to pass self checkup. Talk to TA if this happens |
This is the complete Crazyflie control system. You will only be modifying a small portion of it, but it will be helpful to understand the full scope of the system you are interfacing with.
Figure 2. Crazyflie control diagram
The control process starts with the state estimator module receiving sensor data and using it to calculate the drone's current attitude (its rotation, i.e. roll, pitch, and yaw). The state estimator then sends the calculated attitude to the state controller module, which also receives a setpoint from the commander module (in our case, this is user input specifying the desired attitude or attitude rate and thrust). The state controller module contains a cascading PID controller that uses the inputs from the state estimator to calculate the actuation force needed. That is then sent to the power distribution module where the actuation force is converted to motor power then the loop starts over again.
You will be implementing the State Controller’s cascading PID in part 2 of this lab.
Figure 3. Cascading PID diagram
The Crazyflie runs off of a cascaded PID system where the output of the first PID controller is then used as an input for a second PID controller. This layout can be seen in figure 3, the output from the attitude PID controller, the desired attitude rate, becomes the input of the attitude rate PID controller. In part 2, you will be implementing the attitude and attitude rate PID controllers for roll, pitch, and yaw. In part 1, you will be determining the PID values that should be present in the controllers by using a working PID controller before implementing it yourself.
The tools needed to flash, interact with, and fly the crazyflie have been packaged into a virtual image for your convenience.
The virtual machine has been configured to have the necessary utilities to develop the Crazyflie firmware. Below are detailed instructions for completing different tasks within the virtual machine. Login username is bitcraze and password is crazyflie. Add the VM Image from the C:/Temp/MP4Image/BaseFolder folder. To do this you click the big green plus button to add VM Image and not the “Import” button. If you would like more information about the VM or to download the VM on your personal computer see Appendix B. The virtual machine is immutable, which means that if you do not save any files you change elsewhere they will be reset on startup. For this reason it is recommended that you use git or Google Drive or a shared folder to save work. This is more important for Part 2 but is still worth mentioning now.
It is possible that another version of the quad software is currently flashed onto the crazyflie. In order to ensure that the Lab_Part_1 version of the software is installed, follow these steps.
Note: You can also add the USB by going to:
With the drone flashed, we are almost ready to begin tuning the PID values, however we first want to ensure that the drone is secured about whatever axis we will be tuning the rotation for. The test stand is used to secure the drone about an axis of rotation and to also measure the rate of rotation and exact position of the drone.
The test stand for MP-4 is a bit more complex than the ones used in MP-1, and consists of three major components, plus a couple wires to connect them. The test stand base holds the rotary encoder used to measure position, and can be used in two different configurations depending on the drone orientation needed.
The test stand mount attaches to the encoder shaft, and holds the Crazyflie drone in place through friction. There are two different mounts, which can hold the drone in either a horizontal or vertical position.
Figure 4: Drone Holders
Before starting the ground station, secure the drone to a mount. If you would like more information about the test stand see Appendix C.
The ground station software is what you will mainly be using to communicate with the Crazyflie. It has been pre installed and set up on the virtual machine for this lab.
You need to know the channel that a Crazyflie is connected to. Here is a sheet that lists the channels of each drone. Crazyflie Radio Map.
To connect to a Crazyflie and open the GUI, make sure the Crazyflie is powered on and the crazyradio is available in the vm, then run the command crazycart <radio_channel>. If everything connects successfully, the GUI will open. Below are some details on how to perform tasks in the GUI.
You will need to verify that the GUI connected to the backend every time
Figure 5. Connect Backend
Lets you view and set parameters of the Crazyflie
Figure 6: Parameters Tab
Sends setpoints to the drone
Figure 7: Manual Setpoints
Log variables are the main form of feedback and debugging used in this lab. They will be used to tune PID values and debug code.
Figure 8. Logging variables
PID control utilizes a measurement of state of a system, and the comparison of that measurement with a setpoint to determine an error value. By multiplying, integrating or observing the slope of this error a PID controller can be developed. The drone uses a series of nested PID controllers to control yaw, pitch and roll, both as attitude rates and attitude. Each rate, or attitude axis requires Kp, Ki and Kd values to act as the coefficients for the PID controller. Your goal for part 1 of the lab is to find Kp, Ki and Kd values for each of these controllers that enable robust control of the quadcopter. The values you choose will be driven by: 1) your observations of the quadcopter's response to changing setpoints, and 2) your intuitive understanding for how each coefficient should mathematically impact the quadcopter's response. It may be helpful to read Using the Test Stand for background information on how to utilize it while tuning.
Tip: Begin with Kp, and then move to Kd values before Ki. When adjusting values, try first to adjust by an order of magnitude (multiply or divide by 10) before making smaller adjustments. Many Ki values can stay as very small or zero. Not all PID’s require all or even two coefficients to be non zero. In general Ki values are used to improve the disturbance within the system. Since we are tuning the system with a low disturbance factor the Ki values do not need to be large.
We will begin by tuning the attitude rate controller. This controls the rate of rotation of the yaw pitch and roll.
Tip: When tuning your rate controller, allow for a “looser” control. In other terms, the percent overshoot and settling time can be a bit larger than typically desired. This allows us to tune the attitude controller “tighter” later. As the attitude PIDs and rate PIDs have somewhat competing goals, there is a limit to how tightly both can be simultaneously tuned.
Figure 9: Roll, Yaw and Pitch Diagram (source)
First you will learn how to measure yaw rate with the test stand. Put the test stand so that it is standing with the three legs on the ground with the attachment that will hold the drone parallel to the ground, as figure 10 shows.
Figure 10: Yaw rate test stand setup
Now, connect to the Crazyflie and open the groundstation GUI. We will be graphing the test stand rotation rate and the yaw attitude rate setpoint. Details on how to use the test stand and how to set up plotting can be found in Appendix C.
You can now send yaw rate setpoints and thrust setpoints via the ground station which will tell the Crazyflie to rotate at a certain speed, the test stand sensor will then measure the actual rate and display that on the GUI. However, with no PID constants set, the Crazyflie will not respond to setpoints. Your task is to change these constants through the GUI by setting parameters.
Relevant logging variables:
Be sure to write down the PID values you find while tuning! They will be used in the second half of the lab and are required for submission. Also, the PID values are reset when the Crazyflie reboots, so be sure to write them down frequently! Additionally, there is a option to save your values through the use of a .json file. This is especially helpful to keep your PID value.
Relevant parameters:
Group: s_pid_rate
Tip: If the ground station becomes unresponsive or stops sending setpoints to the crazyflie, stop it by pressing ctrl + c in the terminal you launched it and restart it. The PID constants are stored in the crazyflie’s memory so they should be unchanged, unless the quadcopter is power cycled.
Your goal for this part of the lab is to demonstrate that you can send a yaw rate setpoint to the Crazyflie and then verify through the GUI ground station that the Crazyflie follows that setpoint closely.
Now change the mount attachment so that the Crazyflie will be held vertically and the left or right side of the drone is facing the table, as shown in figure 11.
Figure 11: Pitch rate test stand setup
You will now be tuning pitch rate, this is how fast the Crazyflie tilts up or down. Repeat the process you did for tuning the yaw rate, but with the appropriate pitch rate parameters and logging values.
Note: The e_stop parameter under the sys group should be set to 0. The e_stop, electronic stop, is a safety feature which turns off the quadcopter if it flips. Setting the e_stop to 0 will prevent the crazyflie from automatically rebooting when it detects tumbling.
Relevant logging variables:
Relevant parameters:
Group: s_pid_rate
Change the orientation of the drone so that the front or back is facing the table.
Figure 12: Roll rate test stand setup
You will now be tuning roll rate, which is how fast the Crazyflie tilts to the side. Repeat the process you did for tuning the yaw rate and pitch rate, but with the appropriate roll rate parameters and logging values.
Remember to set the e_stop parameter under the sys group to 0
Relevant logging variables:
Relevant parameters:
Group: s_pid_rate
We will now tune how the Crazyflie holds a specific attitude angle. Recall from Figure 3 that the attitude PID controller provides the input setpoint to the attitude rate controller. Therefore, it is important that the rate controller works well and all attitude rate PID values are set before continuing.
Change the test stand setup to how you measured yaw rate. You will now be tuning yaw, which is the angle that the Crazyflie is oriented. This is done similarly to yaw rate except you will be sending degrees rather than degrees per second setpoints. Note, there is a button built into the test stand for setting the 0 point of rotation, this can be used to approximately sync up the test stand angle measurement with the Crazyflie’s built-in measurement. In the end you will demonstrate that you can make the Crazyflie rotate to and hold a specific yaw angle, confirming it through the GUI ground station.
Relevant logging variables:
Relevant parameters:
Group: s_pid_attitude
For this part of the lab we will turn the test stand on its side and attach the other mount that will hold the Crazyflie parallel to the floor. Ensure the left or right side of the drone is facing the test stand, as shown in figure 13.
Figure 13: Pitch test stand setup
Repeat the process you did for tuning the yaw, but with the appropriate pitch parameters and logging values. You will demonstrate that you can make the Crazyflie rotate to and hold a specific pitch angle, confirming it through the GUI ground station.
Remember to set the e_stop parameter under the sys group to 0
Relevant logging variables:
- MicroCART.Test_stand
- This is test stand data
- ctrlStdnt.pitch
- This is the pitch setpoint
- Optional - stateEstimate.pitch
- This is the crazyflie’s state estimator for pitch angle
Relevant parameters:
Group: s_pid_attitude
To measure the roll you will turn the drone 90 degrees such that the back or front of the drone is facing the test stand, as figure 14 shows.
Figure 14: Roll test stand setup
Repeat the process you did for tuning the yaw and pitch, but with the appropriate roll parameters and logging values. You will demonstrate that you can make the Crazyflie rotate to and hold a specific roll angle, confirming it through the GUI ground station.
Remember to set the e_stop parameter under the sys group to 0
Relevant logging variables:
- MicroCART.Test_stand - This is test stand data
- ctrlStdnt.roll - This is the roll setpoint
- Optional - stateEstimate.roll - This is the crazyflie’s state estimator for roll angle
Relevant parameters:
Group: s_pid_attitude
Now you are ready to test how well your PID values work in flight. You will be fine tuning your values through test flights!
At this point you should be able to fully control all axes of the drone through a gamepad. Before you take off for real, it's always a good idea to check that your inputs do what you think they do while on the test stand. Gamepad control uses a mixed setpoint setup where pitch and roll are given as absolute angles, and yaw is given as a rate. Once everything looks ok on the test stand, carefully try to take off and get a feel for how she handles. Enable estop by setting the parameter to “1” before flying off the test stand. Be aware of others in the lab and try not to crash it too hard.
Control Crazyflie with gamepad: This video can also be used as an example.
Tip: It may be useful to add a negative to the scales of the axes in order to invert joystick controls.
Figure 15: Gamepad Menu
4. Navigate to the control tab and select the gamepad control button after you have plugged in your controller. The ground station will immediately start sending setpoints to the crazyflie. The thrust joystick should be held to zero when switching to gamepad control to avoid unexpected takeoffs.
Figure 16: Gamepad Selection
For this part of the lab you will be writing your own control algorithms. Be sure to set up code exporting from the VM so you don’t lose your work. The virtual machines are all immutable, which means that if you do not save your work elsewhere it will be deleted at reboot. All locations where you will need to write new code have been commented with 488 TODO. You can use VS code’s built-in search function to find all occurrences to make sure you haven’t missed anything.
*Make sure to flash the drone with lab part2’s firmware.* Flashing the drone
Before beginning, it is recommended to read through the files you will be changing and the corresponding data structures.
The high level student controller, defined in controller_student.c, manages setting up setpoints and forwarding them to the attitude controller, whose output gets fed into the attitude rate controller. Both the attitude and attitude rate controller are defined in student_attitude_controller.c. The attitude and attitude rate controller utilize the base pid algorithms defined in student_pid.c. The output from the attitude rate controller gets passed back to the high level student controller where it then gets forwarded to other modules outside the scope of this lab.
Figure 17: Student Controller Sequence Diagram
As a part of writing your own algorithms, it is important to understand the data structures used in the firmware. Additionally, it can be useful to specify what logging information to send to the ground station. Below are details on both subjects which will help in the development of your algorithms. Additionally there are some further details on compiling the Crazyflie firmware below.
There are four main structs that you will have to be familiar with that the state controller uses to communicate with other modules defined in the /src/modules/interface/stabilizer_types.h file. A small but important struct is the attitude struct, containing roll, pitch, and yaw values as floats and has a timestamp. Depending on the control context (viewable in the setpoint.mode struct) the values in this struct can represent degrees, or degrees per second for each axis.
Figure 18: Attitude struct
The first main struct is the state struct: it contains Crazyflie's current attitude and other parameters not relevant to this lab. Note that the current attitude rate is not available in the state struct. For this value you will need to read directly from the gyroscope described in the sensorData struct.
Figure 19: State struct
The sensor data struct contains raw data from several sensors, including the gyroscope. You will need to access information contained in this struct for some of your rate PID calculations.
Figure 20: Sensor data struct
The next major struct that you will interact with is the setpoint struct. The struct contains the setpoint information from the commander module which received setpoints from the ground station. Similar to other structs, it contains many fields of information you do not have to worry about. The important fields are attitude, attitude rate, and thrust. The others like velocity and acceleration are not used because you will be implementing an attitude controller, not a position or velocity controller.
Additionally, the mode struct controls how the data in the setpoint struct is interpreted. The modes are set automatically by the ground station based on the control method. For this lab, we are concerned with only two or three control modes, attitude control, attitude rate control, and mixed attitude control.
Attitude control If:
Then, the controller will use the values given by setpoint.attitude.
Attitude rate control If:
The controller will use the values given by setpoint.attitudeRate. This mode ignores most of the control algorithm and only uses the attitude rate controller to stabilize and control the quad. This mode is useful if you want to hold a steady rotation speed of the quad body, this is what some other quads call “acro mode”.
Mixed Attitude control If
This allows the roll and pitch to be specified as a rate and the yaw to be an angle. This is the method used when a gamepad controller is used.
Figure 21: Setpoint Struct
The last struct is the control struct. This is the output of your control algorithm and represents the force to apply to the drone’s body. It is sent to the power distribution module which converts it into motor commands. Note that these are 16 bit int values, so a conversion must take place from a float.
Figure 22: Control struct
Figure 23: Sample Log Group
Figure 24: Sample Log Add
The crazyflie firmware can be compiled from the firmware root folder, /Lab_Part_2/crazyflie_software/crazyflie-firmware-2021.06/ by running make CONTROLLER=”Student”. After successful compilation, the binary files will be placed in the root of the firmware folder and can then be flashed to the crazyflie by following the instructions above.
make unit can also be used to run unit tests on the firmware, the unit tests are defined in /Lab_Part_2/crazyflie_software/crazyflie-firmware-2021.06/test/. You are free to add additional unit tests to debug, however it is not required.
Now that you understand the structure of the firmware, it's time to start writing your own algorithms. You may want to review Flashing the Crazyflie, when you’re ready to compile run make CONTROLLER="Student" from the root of the Crazyflie firmware.
Below is the suggested order of additions to make to the firmware.
Note, for this section you should use the PID constants you found in part 1 for known good values. You can set the default values in the student_pid.h file. However the constants you discovered earlier may have some assumptions built in so it may be necessary to re-tune the controller if a significantly different algorithm is used.
The attitude controller and attitude rate controller have their main functions in student_attitude_controller.c, this is where you should begin working.
Now we need to bring everything together in the controller_student.c file.
At this point, you should have filled out everything in all files, make sure all of the “488 TODO” comments have been fulfilled.
Before you go flying your Crazyflie for real, it's a good idea to verify everything works as intended on the test stand. Attach the drone to the test stand and briefly check that all axes respond how you expect. For this step you can use manual setpoints or a gamepad connected to the ground station, see here for details on using a gamepad with the ground station.
If all looks good, take her for a spin and see how she handles! Be careful of others in the lab and try not to crash it too hard!
The Crazyflie is a versatile, open source quadcopter platform by Bitcraze. The platform has been specially adapted to meet the needs of this lab but has far more capabilities. If interested in exploring the platform further, check out their website here.
The current status of quadcopters and their radio channel can be found at Crazyflie Radio Map.
One of the main ways the Crazyflie communicates its status is with the four LEDs mounted to the surface.
LED code | Meaning |
2 solid BLUE | All normal, indicates the back of the Crazyflie |
2 Slow flashing BLUE (1 hz) | Crazyflie is in bootloader mode and is ready to be flashed by radio |
1 Fast flashing BLUE (2 hz) | Crazyflie is in DFU mode and is ready to be flashed by USB |
Back left BLUE flashing | Charging while plugged into USB. Percentage of time LED is on indicates battery level. |
1 slow flashing RED (0.5 hz) | Crazyflie is on but sensors are not calibrated. Place on a flat surface and keep still to calibrate |
1 fast flashing RED (2 hz) | Sensors are calibrated and ready to fly |
5 short RED pulses followed by a gap | Self test failed, hardware may be damaged, notify a TA or the instructor |
1 solid RED | Low battery |
5 short GREEN pulses | Self test passed, all normal |
The virtual machine has been configured to have the necessary utilities to develop the Crazyflie firmware. Below are detailed instructions for completing different tasks within the virtual machine. Login username is bitcraze and password is crazyflie
The virtual machine is installed on the lab computers as an immutable virtual machine. In order to access it you may need to add it to virtual box. Click “Add” and navigate to C:/Temp/MP4Image/BaseFolder and click the vbox file. The virtual machine should now be available.
The file is stored as a .txt on the course website but must be renamed to a .ova. If you are a windows user you can use the ren original_filename.txt new_filename.ova command.
New users will not be able to see the VM instance until it is imported.
Due to the read only VM image, you must export your work from the VM before shutting down. The VM will be reset on reboot and all changes will be reverted.
There are two options to maintain and export your changes from the virtual machine. The first is to use a local git repository stored on your x drive or a usb flash drive. This minimizes network usage. The second option is to use a standard GitHub or GitLab repository. This option is best for working with other people in your group at the same time. If you do use the second option we ask you make your repo private.
With a bare git repository on the host machine[a]
Final export will copy all files that have been modified since the original state of the Microcart repo.
The test stand control board reads the rotary encoder value, and transmits either positional or rotation rate data to the computer.
Figure 25: Test Stand Control Board
Figure 26: Test Stand Connection
The test stand has two modes, where it reports either positional data or the rotation rate (in deg/sec). The LED labeled “L” on the Arduino Nano is used as a mode indicator, and is on when the control board is in position mode, and off when in rate mode. You can switch between modes by pressing and holding the black pushbutton mounted to the control board PCB. Additionally, the black pushbutton is used in positional mode to zero the reported reading (sort of like “tare” on a digital scale). Short pressing the button while in positional mode will reset the reading to treat the drone’s current position as zero. While you will be able to see the reported data in the GUI, you can read the data reported by the controller by connecting to its COM port with PuTTY (or similar) at a baud rate of 9600.
The Ground Station can be opened using the command crazycart <radio number> using the radio number corresponding to your quadcopter.
The crazyflie uses what are called “Log Blocks” to define what variables are logged and sent to the ground station. A log block specifies what values to send and at what rate. Log blocks can be paused and resumed after initial setup. Note the crazyflie communication has a limited bandwidth, only enabling around 10 logging variables at a time.
Figure 27: Log Blocks Tab
Figure 28: Logging Blocks File
Figure 29: Log Block Commands
The CLI is the base of the communication with the Crazyflie drone. It can optionally be used for basic tasks. You shouldn’t need to interact with the CLI during the course of the lab, but it can be useful for debugging if something goes wrong. It can be opened by adding a “nogui” flag to the end of the crazyCART script. crazycart nogui Run commands with ./Cli ... Further usage details can be found by appending --help to the end of a command. The following commands are currently implemented.
Command | Description |
./Cli outputoverride <enable> <Time> <Throttle> <Pitch> <Roll> <Yaw> | output override will send a setpoint that lasts a set amount of time with the specified throttle, roll pitch and yaw. With enable set to 1 it will send the setpoint as a rate and 2 will send the setpoint as an angle |
./Cli getparam <block_id|’block_name’> <param_id|’param_name’> | Get param will get the value of specified param. Note only the param id is used for this command. The param id is found in the logging TOC, use getlogfile 1 command to find this file |
./Cli setparam <block_id|’block_name’> <param_id|’param_name’> <value> | Set param will set the value of the specified param |
./Cli getlogfile <id> | Get log file will get a certain log specified by the id of 0: data log 1: param id 2: logging toc |
./Cli logblockcommand <id> | The log block command performs specific tasks on log files for the specified id of 0: delete all log blocks 1: refresh all log blocks 2: load log blocks 3: delete log block 4: resumelog block 5: pause log block |
Document Version Changelog
[a]This would be another nice place to include a walk through video