This is the mammoth in the project: the code. To be able to correctly power the motors from sensor and user inputs requires a several layers of algorithms and then there are all the trivial things like mode control, LED output, etc.
N.B. From now on I’ll refer to the sensor board (gyro, accelerometer, magnetometer, barometer) as the IMU (Inertial Measurement Unit).
Arduino Uno Pin Map
First I’ve started by drafting a pin map for the Arduino Uno. This is where, I expect, everything will connect, but I will of course keep pin numbers as constants in the program to make it easy to change.
Here’s what I’ve come up with:
- 0 (RX): Empty
- 1 (TX): Empty
- 2 (Ext. Ints): Empty
- 3 (PWM 490Hz, Ext. Ints): Motor 1 (PWM Out)
- 4: RC Throttle (PWM In)
- 5 (PWM 980Hz): RC Aux1 (PWM In)
- 6 (PWM 980Hz): RC Aux2 (PWM In)
- 7: RC Pitch (PWM In)
- 8: RC Roll (PWM In)
- 9 (PWM 480Hz): Motor 2 (PWM Out)
- 10 (PWM 480Hz): Motor 3 (PWM Out)
- 11 (PWM 480Hz): Motor 4 (PWM Out)
- 12: RC Yaw (PWM In)
- 13 (LED): Empty
- A0: LED1 (Digital Out)
- A1: LED2 (Digital Out)
- A2: Buzzer (Digital Out)
- A3: Empty
- A4 (SCL): Empty
- A5 (SDA): Empty
- SCL: Serial clock line from the IMU
- SDA: Serial data line from the IMU
Ext. Ints = external interrupts. This is relevant for reading PWM inputs, but I’m not using them. I’ll explain why later.
That’s a first draft of what’s going to be where.
Read RC Inputs
This is the process of reading the PWM (pulse width modulation) signals from the RC receiver, and converting it into in-program variables that can be used in calculations. I’ll also need to map the values to a reasonable range – this could depend on angles etc. in the PID loops later on.
Here I have to work out exactly what orientation we want the quad to be in based on the RC inputs. This may well be adjusted based on control mode, velocity and so on but tells us roughly where we want it to be pointing, how fast each motor should be spinning, etc.
This is where I read the raw data output from the IMU board. Since it communicated over the 12C protocol, I’ll need to implement a library to read that.
This is arguably one of the most complex parts of the program. Here I need to combine the raw data from the accelerometer, gyroscope, magnetometer and barometer to get accurate estimates of the drone’s X, Y and Z Euler angles and its relative altitude. There are some very complex predictive algorithms out there (e.g. the Kalman filter…) but I will have to either find a library to do the dirty work for me, or use a more simple algorithm.
Here we take the desired orientation (from the RC inputs) and the actual orientation (from the sensors), calculate the error and turn it into motor outputs that will try to correct this error. There are likely to be several steps to this, and several subloops, but the principle is fairly simple.
This is the very simple phase of actually outputting the calculated values to the motors. I may or may not have to do some more converting between orientations and motor values.
Control Modes and Program Phases
This is the code that will actually choose when to run everything else. There are subtleties to be added everywhere, from arming/disarming the motors to special landing modes. I’ll get the main loops done first.
LED and Buzzer Outputs
This is for user feedback: the LEDs will light up different colours at different times to signify the status of the drone, and the buzzer will sound in certain situations to give audible feedback.
As can be seen, there are quite a lot of aspects to the programming, but I will work on each one separately and eventually piece it all together to create a comprehensive program. It will be very important for me to separate everything into distinct functions, and to add comments to it all – it is imperative that I can follow exactly what I’m doing.
However, I think I’m going to try and get a physical product working first so that I don’t have to worry about that when doing the programming.