Paparazzi STM32f3 Discovery

By Daniel García Vaglio and Esteban Zamora Alvarado.

This tutorial is part of Programación Bajo Plataformas Abiertas project documentation.

Before getting started, your computer needs some tools to put in action the code. That is why we made the guide for the installation tools and prerequisites required by Paparazzi.

These are some important links:

This tutorial part is based on tutorial for installing paparazzi. The steps presented in this tutorial are implemented for Debian. If you are using another Linux distribution, some instructions might change.


Follow this tutorial Summon-Arm-Toolchain. Do not forget to export to the user PATH using bashrc and then reload the bashrc.

Download all the paparazzi dependencies. Then,write in your terminal the next command:

apt-get install ocaml-findlib libxml-light-ocaml-dev liblablgtk2-ocaml-dev liblablgtk2-gnome-ocaml-dev libocamlnet-ocaml-dev libsdl-ocaml-dev libpcre-ocaml-dev gtk2-engines-pixbuf make gcc g++ libgsl0-dev libgnomecanvas2-dev bzip2 git libusb-dev speech-dispatcher glade libpcre3-dev python-lxml python-wxgtk3.0 python-usb python-yaml libxml2-dev ocaml-native-compilers python-scipy python-matplotlib python-pygame lpc21isp openocd gpsd libgps-dev meld gitk gnuplot imagemagick libipc-run-perl astyle subversion

NOTE: If you have some troubles installing the dependencies, try to use aptitude instead apt-get. If you get some problems with gcc and g++ , do not install python-scipy.

The last three dependencies

  • ivy-python
  • ivy-c
  • ivy-ocaml


we will create a directory. Copy the code and compile it creating a debian package.

mkdir local/src/ivy-python
cd local/src/ivy-python 
svn co
cd trunk 
apt-get install python-stdeb
python --command-packages=stdeb.command bdist_deb
cd deb_dist/
sudo dpkg -i python-ivy-python_2.3-pre-2-1_all.deb


We proceed the same way as in ivy-python.

cd ~/local/src
mkdir ivy-c
cd ivy-c
svn co
cd trunk

For new versions of dpkg in order to build ivy-c properly, changelog format must be changed:

nano debian/changelog

Every month in the file must be written with only its first three letters.

July => Jul
apt-get install tcl-dev tcl8.4-dev
dpkg-buildpackage -rfakeroot -us -uc
cd ..
sudo dpkg -i ivy-c-dev_3.X.X_amd64.deb ivy-c_3.X.X_amd64.deb


We proceed the same way as in ivy-python and ivy-c.

cd ~/local/src
mkdir ivy-ocaml
cd ivy-ocaml
svn co
cd trunk
sudo apt-get install dh-ocaml tk-dev
dpkg-buildpackage -rfakeroot -us -uc -b
cd ..
sudo dpkg -i ivy-ocaml_1.X.X_amd64.deb

Now we are ready with the dependencies of paparazzi!

Compiling and installing Paparazzi

We need the Paparazzi source code, which is hosted in Github. First, you have to make a directory where the repository is going to be stored,

cd local/src/
mkdir paparazzi

Then access the new directory

cd paparazzi

The Paparazzi code is in Github. To be able to use paparazzi with the STM32F3 DISCOVERY, we need to clone it from the ARCOS-lab repository.

git clone -b stm32f3discovery-fede

After cloning the repository, you need to launch the software, but before you must do the following:

sudo apt-get install libsdl1.2-dev
git submodule init
git submodule update

Before we can make paparazzi, it is necessary to fix a line of code:

nano /HOME/local/src/paparazzi/paparazzi/sw/ext/luftboot/src/luftboot.c

Where you find the line “systick_set_clocksource(STK_CTRL_CLKSOURCE_AHB_DIV8);”, replace it with:


Now, you are ready to make paparazzi


At this point, Paparazzi is be running, and you should be able to see the GUI (Paparazzi Center).

Now you can see Paparazzi's Center (GUI), the next step is to flash the STM32f3 DISCOVERY with paparazzi. Be sure that the STM32f3 Discovery is connected via ST-Link!

Go to A/C and select stm32f3_discovery, then be sure to have set the Target option to ap. After this, click on build, and when finished click in the upload button to flash the program to the STM32f3…

Done, Paparazzi is running in the STM32f3!

USB-UART adapter

Now we need to be able to read(Rx) and transmit (Tx) information between the STM32f3 and the computer> For this procedure, connect the USB-UART adapter to the right pins in the f3 as described in the following lines. We need this adapter because libopencm3 does not support usb communication. Here you have a simple table to make the connection:

STM32f3 pin Adapter pin
3V P2
PC5 P7
PC4 P9

Next, close paparazzi and run

sudo adduser <user> dialout
newgrp dialout

This is necessary to access the USB port (to whom the adapter is connected). Execute paparazzi. Then go to session (up right corner) and select “Flight USB-serial@57600”. Then click Execute.

A new window will open (GCS) (Paparazzi GCS), go back to Paparazzi main window, and in tools select messages. In this window, you can see the information Paparazzi is reading from the STM32f3. Note that if the stm32f3 you are using is not calibrated, you will get a lot of non-sense readings.


To use the Xbee Modems XBee-PRO® XSC RF Module datasheet, which allow wireless UART communication, you need to connect it to the UART1 pins the same way you connected the UART-USB adapter, to the STM32f3. If you are using the adaptation board designed for the paparazzi copter, you just need to connect it to the Xbee board adapter.

To make this devices communicate correctly with Paparazzi, it is necessary to configure the baud rate of both modules. That is because paparazzi uses 57600 BPS by default for telemetry communication. This can done, by using the XCTU softwareXCTU software by Digi developed by the manufacturer. You can use the program Wine to run this application from Debian.

Note: To communicate with the Xbees properly, it is necessary to have set the session to Flight USB-serial@57600 and not to Flight USB-Xbee-API which does not work for this modules.

First we need to understand the basic configuration.

To transform the p quad into X quad. Go to ~PAPARAZZI/conf/airframes/examples/quadrotor_stm32f3_discovery_pwm_ppm.xml

In <servos driver=“Pwm”> change the names from FRONT, BACK, RIGHT, LEFT to NE, SE, SW, NW. Set commands to

 <define name="ROLL_COEF"   value="{ -256, -256,  256,  256 }"/>
 <define name="PITCH_COEF"  value="{  256, -256, -256,  256 }"/>
 <define name="YAW_COEF"    value="{ -256,  256, -256,  256 }"/>
 <define name="THRUST_COEF" value="{  256,  256,  256,  256 }"/>

Edit command laws to

  <call fun="motor_mixing_run(autopilot_motors_on,FALSE,values)"/>
  <set servo="NE"   value="motor_mixing.commands[0]"/>
  <set servo="SE"   value="motor_mixing.commands[1]"/>
  <set servo="SW"   value="motor_mixing.commands[2]"/>
  <set servo="NW"   value="motor_mixing.commands[3]"/>

In section simulation change the actuator names

 <section name="SIMULATOR" prefix="NPS_">
  <define name="ACTUATOR_NAMES"  value="{&quot;ne_motor&quot;, &quot;se_motor&quot;, &quot;sw_motor&quot;, &quot;nw_motor&quot;}"/>

From Quads to Octos

Paparazzi assumes that motors are moving in specific directions. The first motor that is declared (in <servos driver=“Pwm”> the one with no=“0”), moves clockwise (CW), the second (in <servos driver=“Pwm”> the one with no=“1”) moves counterclockwise (CCW), and so on. So for paparazzi, motors with no=“2k” move CW, and motors with no=“2k+1” position move CCW.

Paparazzi also define the positive value for every command.

  • positive value for THRUST is moving up.
  • positive value for YAW is rotating CCW.
  • positive value for ROLL is moving the left part up.
  • positive value for PITCH is moving front up.

If you want to configure a copter with more than 4 actuators, first you add the motors in <servos driver=“Pwm”>. And define their no. Then add in <section name=“MIXING” prefix=“MOTOR_MIXING_”> the values that every motor will take for every command, also set NB_MOTOR to number of motors you want. Then add the new values to <command_laws>. And finally add the new motors to <section name=“SIMULATOR” prefix=“NPS_”>.

In every step the only thing you have to do is to add the new motors and change the previous names if necessary, but you have to be very careful what values to add in <section name=“MIXING” prefix=“MOTOR_MIXING_”>. One way to do this correctly is the following (change 256 to the scale you are using):

1.for THRUST, all motors use 256 2.for YAW, motors that move CW use -256, and motors that move CCW use 256 3.for ROLL, all motors in left side use positive values (the exact values you have to use are in the next section), motors in right side use negative values, and motors in the center use 0. 4. for PITCH, all motors in front use positive, motors in back use negative and the rest use 0.

Values for commands

This is for “normal” configurations, where the net torque is zero. Note this are the most common configurations. This method can be used for all copters in ARCOS-lab, and can be reduced to one single equation.

This is to set the values for ROLL and PITCH commands, but only one general method is going to be explained, because the two are mathematically equivalent. We need to determine the v value to be written for every motor in every command.

Let a to be the number of motors at one side of the copter (front of back OR left or right), and b the number of motors at the other side.

Note that the copter is going to rotate, so to have a stable rotation we need every motor, in the same side, to produce the same angular speed. The values that are going to be calculated can be understood as the thrust every motor will produce to complete the command. So, motors far from the rotation axis must apply more thrust than those near the axis. Also, in order to have an stable rotation we need to have the same torque in each side (magnitude).

We are going to calculate the MAX thrust to be applied by one motor (in x side). Let M be the position vector (form copter's center) of the motor with the greatest distance from the axis. Let C be the angle between M and the axis. The maximum value of v, that is 256, is taken by the motor that is at the longest distance and in the side with least motors. Then, because every motor in one side must move at the same rotational speed, we have the following expressions:

For the side with x motors, for motor i:

$$v_i=\frac{min[a,b]}{x}\times \frac{256}{sin(C_x)} \times sin(c_i)$$

where ci is the angle of every motor.

Then for side a:

$$v_i=\frac{min[a,b]}{a}\times \frac{256}{sin(C_a)} \times sin(c_i)$$

for side b:

$$v_i=\frac{min[a,b]}{b}\times \frac{256}{sin(C_b)} \times sin(c_i)$$

Some useful configurations

P quadcopter


 <define name="ROLL_COEF"   value="{    0,    0,  256, -256 }"/>
 <define name="PITCH_COEF"  value="{  256, -256,    0,    0 }"/>
 <define name="YAW_COEF"    value="{ -256, -256,  256,  256 }"/>
 <define name="THRUST_COEF" value="{  256,  256,  256,  256 }"/>
X quadcopter


  <define name="ROLL_COEF"   value="{ -256, -256,  256,  256 }"/>
  <define name="PITCH_COEF"  value="{  256, -256, -256,  256 }"/>
  <define name="YAW_COEF"    value="{ -256,  256, -256,  256 }"/>
  <define name="THRUST_COEF" value="{  256,  256,  256,  256 }"/>
Y hexacopter


<define name="ROLL_COEF" value="{256, -256, 0, 256, -256, 0}"/>
<define name="PITCH_COEF" value="{128, 128, -256, 128, 128, -256}"/>
<define name="YAW_COEF" value="{-256, 256, -256, 256, -259, 256}"/>
<define name="THRUST_COEF" value="{256, 256, 256, 256, 256, 256}"/>

From the front left counting CW.

<define name="ROLL_COEF"   value="{  106, -106, -256, -256, -106,  106,  256,  256 }"/>
  <define name="PITCH_COEF"  value="{  256,  256,  106, -106, -256, -256, -106,  106 }"/>
  <define name="YAW_COEF"    value="{ -256,  256, -256,  256, -256,  256, -256,  256 }"/>
  <define name="THRUST_COEF" value="{  256,  256,  256,  256,  256,  256,  256,  256 }"/>
X octacopter


<define name="ROLL_COEF" value="{-256, -256, 256, 256, 256, -256, -256, 256}"/>
<define name="PITCH_COEF" value="{256, -256, -256, 256, 256, 256, -256, -256}"/>
<define name="YAW_COEF" value="{-256, 256, -256, 256, -256, 256, -256, 256}"/>
<define name="THRUST_COEF" value="{256, 256, 256, 256, 256, 256, 256, 256, 256, 256}"/>

For ANY configuration

More advanced mathematical tools are required for understanding more complex systems. Here is a Brief explanation for obtaining the General Equation for the values v.


To create a NEW airframe, go to A/C and select new. After this, go to airframe and select the airframe configuration file you want to use, in this case the one corresponding to the STM32f3 ,quadrotor_stm32f3_discovery_pwm_ppm.xml Paparazzi Airframe Configuration. Then, go to flight plan and select the flight plan you want to use. If you don't have any special flight plan, then use flight_plan/rotorcraft_basic.xml Next, go to settings section and select the settings that you wantPaparazzi Settings. We recomend:





Then, go to Telemetry section and choose default_rotorcraft.xml If you edited correctly your airframe configuration file, you shouldn't have any problems compiling the new AC. The radio option depends on a the control you have. To learn more on what to choose, go to the Radio control section.

When you create a new airframe configuration you need to take in to account the pin mapping of the STM32f3 inside Paparazzi. This are some of the pins that Paparazzi uses and will expect you to leave them as they are.

PIN Paparazzi in STM32f3
* PA13 SWDIO (FREE?), pp: TIM4 CH3
* PA14 SWCLK (FREE?), pp: UART2 TX, pp: I2C1 SDA, pp: TIM8 CH2
* PB3 SWO (FREE?), pp: UART2 TX, pp: SPI1 SCK, SPI3 SCK, pp:TIM2 CH2
PE8 LD4/BLUE, pp: LED_4
PE9 LD3/RED, pp: LED_3, pp: TIM1 CH1
PE10 LD5/ORANGE, pp: LED_5
PE11 LD7/GREEN, pp: LED_7, pp: TIM1 CH2
PE12 LD9/BLUE, pp: LED_9
PE13 LD10/RED, pp: LED_10, pp: TIM1 CH3
PE14 LD8/ORANGE, pp: LED_8, pp: TIM1 CH4
PE15 LD6/GREEN, pp: LED_6, pp: UART3 RX

Note: The other pin configurations and definitions are located in the file:


Default configurations

When you want to change the default configurations for an specific airframe, you can do it from conf/conf.xml. You just search for the AC you want to change, and make the changes. For example, changing the default settings, or the radio file…

To calibrate the main sensors inside Paparazzi, which basically are the accelerometer, the gyroscope and the magnetometer you have to follow the procedure described in the Paparazzi Wiki in the page:

For calibrating this sensors, yo should use the calibration script located in /PAPARAZZI/sw/tools/calibration/ First clear /PAPARAZZI/var/logs and then install the following packages:

 $ sudo apt-get install python-scipy
 $ sudo apt-get install python-matplotlib

After this, flash the STM32f3 with Paparazzi and then switch to the “raw sensors” telemetry mode to record the sensors data.

In order to be easier to determine the correct axis configuration and signs for each sensor, after switching to “raw sensors” telemetry mode in the GCS window, open the messages in the Paparazzi Center tools, the Real Time Plotter under the same section (tools) and drag the sensor data messages you are interested to the Plotter, which will help you to graphically study the sensors behavior.

AHRS frequency

In order to optimize the updating speed of the pitch, roll and yaw angles of the airframe,which is fundamental to get the proper stabilization, it is critical to adjust the AHRS frecuencies. In order to do this you need to add the following lines to your airframe configuration file and tune the values looking at thePFD in the GCS

  <configure name="AHRS_PROPAGATE_FREQUENCY" value="20"/>
  <configure name="AHRS_CORRECT_FREQUENCY" value="20"/>

The whole section should be like the following:

  <target name="ap" board="stm32f3_discovery">
    <subsystem name="radio_control" type="ppm">
      <!--define name="RADIO_MODE" value="RADIO_AUX1"/-->
<define name="AUTOPILOT_DISABLE_AHRS_KILL" value="1"/>
    <define name="STM32F3_DISCOVERY_I2C1_FOR_LSM303DLHC"/>
    <define name="STM32F3_DISCOVERY_SPI1_FOR_L3GD20"/>
    <configure name="FLASH_MODE" value="STLINK" />
    <configure name="STLINK" value="y" />
    <configure name="NO_LUFTBOOT" value="1" />
    <define name="LUFTBOOT" value="0" />
    <configure name="AHRS_PROPAGATE_FREQUENCY" value="20"/>
    <configure name="AHRS_CORRECT_FREQUENCY" value="20"/>
    <configure name="RADIO_CONTROL_LED" value="9" />

Using the GPS

In this project we used NEO-6 u-blox 6 GPS. The first to do is to verify that the GPS is working properly. To achieve that, we need to connect it to the computer and read the data it is sending. Note that the GPS uses UART, so we are going to use the same USB-UART adapter we used to connect the f3 to the computer. Here you have a simple table to connect the GPS:

GPS pin Adapter pin
Vcc P2
Rx P7
Tx P9

Before connecting the adapter to the computer,it is necessary to get some software. This part of he tutorial was based on Social GPS. To be able to read useful data from the gps, first we need to:

sudo apt-get install gpsd python-qt4 pyqt4-dev-tools gpsd­clients python­gps

Now, connect the GPS to the computer. Then execute dmesg to know where the GPS is attached. In this tutorial we are going to use USB0, but if when you ran dmesg you got another device, be sure of using that one instead. It is vey difficult that the GPS gets signal if it is inside a building, so we recommend to take your computer and the GPS outside.

      stty ­F /dev/ttyAMA0 38400
      sudo gpsd /dev/ttyAMA0 ­F /var/run/gpsd.sock

Now you should see something like this.

The GPS in Paparazzi

Now that we know that the GPS is working properly, we can proceed to configure and use the GPS in paparazzi. First, connect the GPS to the f3, for this you can use the adaptation board or connect it to the pins that correspond to UART2.

Now, we are going to change the Airframe configuration file so that this specific GPS can work. Edit “PAPARAZZI”conf/airframes/<your airframe>.

search for:

    <subsystem name="gps"           type="ublox"/>

Set this subsystem as follow:

  <subsystem name="gps"           type="ublox">
  	<configure name="GPS_BAUD" value="B38400"/>

This is necessary because Paparazzi default baud rate for GPS is 9600, but this GPS works by default at 38400.

Software modification

Depending on what version of Paparazzi you have, this step is necessary or not.

in paparazzi/sw/airborne/boards/stm32f3_discovery


  #define PWM_SERVO_0_AF GPIO_AF6


  #define PWM_SERVO_0_AF GPIO_AF2

then change from PWM0 to PWM 3 from AF6 to AF2

NOTE: This error was present in older versions of the ARCOS-lab Github. The alternate function of these pins were set incorrectly.

Testing actuators

To test the actuators go to your airframe configuration file and add the following lines.

  <firmware name="test_progs">
  <target name="test_actuators_pwm"       board="stm32f3_discovery">
      <define name="SERVO_HZ" value="400"/>
  <target name="test_actuators_pwm_sin"   board="stm32f3_discovery">

This will add the “test_progs” to your compilation options. When you want to flash the test actuators, you have to select it form the target menu.

Original selection:

Tester selected:

To compile the test_actuators_pwm program, which allows the user to send an specific PWM signal to each motor by sliders in the GCS, it is necessary to have the Paparazzi configuration files as follow:

NOTE: What really matters here is the settings file

After compiling the test_actuators_pwm and flashing it to the controller board, just execute the a normal session (Flight USB-serial@57600) and in the GCS window go to Settings/Actuators.

Here you can set the PWM duty cycle of each PWM channel, which are physically located in the STM32f3 as configured in: paparazzi/sw/airborne/boards/stm32f3_discovery.h. This program allows to see the response of each motor/ESC for an specific PWM signal time (1000-2000 ms).


The Electronic Speed Controllers, are the ones which determine the speed of the motor for a determined PWM input signal. The PWM signal consists of square pulses of an specific width, this width normally goes from 1ms to 2ms. In order to make all the motors in the multicopter to work synchronously (with the same speed for the same given input signal) it is necessary to do a throttle calibration for all ESCs. Although this calibration is outside Paparazzi, it is fundamental for the proper functionality of the flight controller. The throttle calibration consists in the next steps:

  • First, be sure to have the motor power is disconnected and the signal cable of the ESC directly connected to the channel corresponding to the throttle command in the radio controller.
  • Then, send the throttle channel in controller to its maximum value (stick at highest position).
  • Now connect the cable that powers the ESC while having the throttle at full.
  • After the sound of two beeps, approximately 2s after turning on the ESC, immediately send the throttle stick to its minimum position.
  • While having the throttle at minimum, wait for the sound of a long beep in the ESC.
  • This long beep indicates that the throttle ranges for the ESC have just finished to calibrate.

You have to repeat the same procedure for each one of the ESCs in the multicopter.

This is a very important part of setting up a multicopter in Paparazzi, allowing the user to do tests, attitude control (in certain modes), and configure the controller board(STM32f3) between different stabilization modes.

Setting the Radio Controller

The first part is to configure the radio controller (TX) to be able to communicate with the receiver and the STM32f3. For this, it is fundamental to know the number of channels that the PPM signal from the controller outputs, in the case of the FSTH9x, the one used for this tutorial, it sends 8 PPM pulses (channels), where each one of these correspond to the channel configuration set inside the current profile of the controller firmware. This channel configuration has to correspond with the Paparazzi radio configuration file for the transmitter controller.

Function TX Channel
Pitch 3
Mode 5

Once the channels inside the profile of the controller are set, it is necessary to bind the transmitter (connected to the controller) and receiver (connected to the STM32f3) modules. For this, follow the instructions given by the manufacturer:Fr-Sky Receiver Manual, in the section 2.1 (Binding procedure).

Now you have to set the radio configuration inside Paparazzi as described in the next section.

Setting PPM from Paparazzi

First you have to change the airframe configuration to use PPM. The first part of your AC has to be like this so that you can use a PPM based radio control.

      <firmware name="rotorcraft">
      <target name="ap" board="stm32f3_discovery">
   <subsystem name="radio_control" type="ppm">
      <define name="AUTOPILOT_DISABLE_AHRS_KILL" value="1"/>
         <configure name="RADIO_CONTROL_LED" value="9"/> 

Now in paparazzi/conf/radios/ create a new xml file as the following:

  <?xml version="1.0"?>
  <!DOCTYPE radio SYSTEM "radio.dtd">
  <radio name="FSTH9x" data_min="900" data_max="2500" sync_min ="3500" sync_max ="15000" pulse_type="NEGATIVE">
   <channel ctl="1" function="YAW"        min="1000" neutral="1350" max="2000" average="0"/>
   <channel ctl="2" function="THROTTLE"    min="1000" neutral="1350" max="2000" average="0"/>
   <channel ctl="3" function="PITCH"       min="1000" neutral="1350" max="2000" average="0"/>
   <channel ctl="4" function="ROLL"         min="1000" neutral="1350" max="2000" average="0"/>
   <channel ctl="5" function="MODE"      min="2000" neutral="1400" max="1000" average="1"/>
   <channel ctl="6" function="UNUSED1"        min="1000" neutral="1500" max="2000" average="1"/>
   <channel ctl="7" function="UNUSED2"        min="1000" neutral="1500" max="2000" average="1"/>
   <channel ctl="8" function="UNUSED3"       min="1000" neutral="1500" max="2000" average="1"/>

Here we are defining what Paparazzi will expect to receive from the control. First it defines some general parameters related to the PPM signal. These parameters are necessary need to be tuned so that Paparazzi interprets the channels correctly. Then, the file allows to configure the minimum, neutral and maximum values expected for each channel.

NOTE: This radio file configuration has to be consistent with the controller manual configuration described in the last section.

  • tutorials/stm32f3_discovery_with_paparazzi.txt
  • Last modified 2016/05/12 02:59
  • by dgarcia