BlueCopter - Arduino Quadcopter

Hey,

I spent the summer working with a new hobby of mine, Quadcopters =D! The quadcopter board is homemade (atmega32u4). Because my board has the same pinout as a leonardo, I decided to go with the multiwii firmware. So I etched a shield for my board containing headers for the receiver, motors and the IMU (cheap chinese found on ebay, ADXL345, L3G4200D, HMC5883 and BMP085).

I was happy with the quadcopter, it flew very nicely (after some PID changes of course).. But in the end I'm the type that likes to write my own code.. Trying to look at multiwii's code to see how they made it work (just to get a hunch), I directly noticed that the code isn't very, hmm how do I put it, reader friendly... So I trashed Multiwii, and there my summer began learning the dynamics and physics of quadcopters.

Three days later, I got a working code.. Three weeks after that I finally managed to find the optimal PID values for my quadcopter =P (yes it took three weeks of tweaking)..

Anyhow I'm not going to bore you out with my story. Instead I'm going to share my code with the arduino community and a video of the quadcopters first flight with my code..

If there is a big demand for a code explanation/theory about quadcopters and how everything works, shout out here, and I'll come up with something for you...

Here is the code: GitHub - baselsw/BlueCopter: Arduino Quadcopter firmware

See attachment for pinout..

And here is the video:

Edit: I've updated the code.. Made the sketch run more efficiently and reduced code size.. With this change I managed to find better PID values and thus get better/faster stabilization.. For those interested I've added pictures of the main board and hardware setup..

//Basel

1 Like

Very nice, but I think I'll move it to Exhibition / Gallery.

Thanks for sharing the video and the code.

Hey, thanks Nick =).. Couldn't figure out where to start the topic.. Good thing you moved it..

//Basel

Tweeking takes time. Very good job I would say. Though the drawings are not clear to me at all.
Thats probably cause by my lack of knowledge
Jantje

Jantje:
Tweeking takes time. Very good job I would say. Though the drawings are not clear to me at all.
Thats probably cause by my lack of knowledge
Jantje

Thx =).. By drawing I assume you mean the pinout? Well, it's simple.. I used the X-configuration (meaning the quad is flying in a X shape).. If you look at the pinout the motor pins should be,

Left upper motor: Pin 6
Left bottom motor: Pin 5
Right upper motor: Pin 10
Right bottom motor: Pin 9

For RX (receiver), PPM signal (Pulse-position modulation), The pins are as follows:
Roll: Pin 16
Pitch: Pin 14
Yaw: Pin 15
Throttle: Pin 7
AUX1: Pin 8
AUX2: Pin 0

I've also got a LED on pin 13, that indicates if the quad is in rate or level/angle mode..

And of course SDA/SCL for the sensors...

Currently the code only uses the accelerometer and gyrometer to make the quad stable during rate- and angle mode..

In the future I may implement heading hold (magnetometer) and altitude hold (barometer).. Not sure yet, cause I didn't have any need for them...

Awesome project! How much did it cost to build it?

Arvis:
Awesome project! How much did it cost to build it?

Thanks bro =)..! Well, for the quadcopter parts without the main board (home made btw), around 150 USD. I bought all the parts (frame, ESC, motors, propellers...etc) from hobbyking.

//Basel

Well done,

many questions pop up

  • how high can it fly?
  • how long can it stay in the air?
  • what does it do when it looses contact with remote?
  • ...

robtillaart:
Well done,

many questions pop up

  • how high can it fly?
  • how long can it stay in the air?
  • what does it do when it looses contact with remote?
  • ...

-- Pretty high.. I didn't measure the distance yet.. But it's so high that it starts to look like a small fly in the sky (cant see the orientation of the quad, nothing)..
-- I'm using a double 2200mAh (3 cells, LiPo, coupled in parallell).. It gave me approx. 15min of flight..
-- Well I lost contact with it when I pushed the throttle to the max! (meaning it flew very high).. Nothing special happens.. It will stay leveled in the air until battery begins to run out, and it will descend (depending on the ESC ur using, it can descend slowly(ESC cutting power slowly) or it will suddenly stop (ESC cuts the power alltogether)).

And here's my parts list (all from hobbyking.com):

Item/Part Pcs
20CM Male to Male Servo Lead (JR) 26AWG (10pcs/set)
1
Hobby King 2.4Ghz 6Ch Tx & Rx V2 (Mode 2)
1
Turnigy 2200mAh 3S 25C Lipo Pack
2
NTM Prop Drive 28 Series Accessory Pack
4
Hobby King Quadcopter Power Distribution Board
1
NTM Prop Drive 28-26 1350KV / 310W
4
HobbyKing 30A BlueSeries Brushless Speed Controller
4
Hobbyking X666 Glass Fiber Quadcopter Frame 666mm
1
8045 SF Props 2pc Standard Rotation/2 pc RH Rotation (Blue)
1

And consider buying spares of ex. propellers and such (if you're a beginner you'll need it)..

//Basel

Do you need an additional device to "bind" or "register" the receiver to the transmitter, or does the one you listed do that?

The packages comes with a transmitter and receiver..

No, you get a 'special' wire that shorts the signal line on the PWR-input to ground (on the receiver).. This will put it in binding mode (Led will start to blink once per second)... In the transmitter all you have to do is hold the bind button and turn it on.. One second later the connection is accomplished, and the led on the receiver will stop blinking =D!

//Basel

i have made quadcopter with arduino uno and gy_80 sensor i have ppm 4channel radio controller and it is not sum every single channel is ppm . i tried to use your program for this but receiver dont work when i want it to fly .....
" when i connect my ppm receiver to single motor with esc radio control work perfectly but when i use it as quadcopter with code does not work
.........
help me plz . help :frowning:
faramarz.zareian@gmail.com

sk8amazing:
i have made quadcopter with arduino uno and gy_80 sensor i have ppm 4channel radio controller and it is not sum every single channel is ppm . i tried to use your program for this but receiver dont work when i want it to fly .....
" when i connect my ppm receiver to single motor with esc radio control work perfectly but when i use it as quadcopter with code does not work
.........
help me plz . help :frowning:
faramarz.zareian@gmail.com

Well, it won't work, I'd be surprised if it did.. This sketch is written for the arduino leonardo (atmega32u4), meaning it won't work on the UNO directly, specially the receiver part. The receiver is using the PCINT (pin change interrupts), and because there is no built-in library for arduino I had to address the registers directly, the atmega32u4 registers (which is not the same for the UNO atmega328p)..

For a beginner I recommend the use of MultiWii's code (Software « MultiWii), my code is "kind of" for people that wants to write their own code and needs some starting ground..

Edit: Another thing I would like to add.. If you decide to modify my code to work with your quadcopter, you'd have to make sure that your ESC supports PWM at a frequency of ~480-500Hz... Most ESC are made to only support PPM.. PPM isn't the same as PWM, the signal looks different and in most ESC is made to run on a frequency of 50Hz...

Here is a whole discussion about the difference: http://forum.arduino.cc/index.php/topic,14146.0.html

And if you decide to replace the 480Hz PWM with 50Hz PPM, you'll have a lot of trouble getting the quadcopter to be stable... With a little luck, you'll maybe be able to fly it in rate mode.. Angle/Level mode needs a faster update rate...

1 Like

baselsw:

Jantje:
Tweeking takes time. Very good job I would say. Though the drawings are not clear to me at all.
Thats probably cause by my lack of knowledge
Jantje

Thx =).. By drawing I assume you mean the pinout? Well, it's simple.. I used the X-configuration (meaning the quad is flying in a X shape).. If you look at the pinout the motor pins should be,

Left upper motor: Pin 6
Left bottom motor: Pin 5
Right upper motor: Pin 10
Right bottom motor: Pin 9

For RX (receiver), PPM signal (Pulse-position modulation), The pins are as follows:
Roll: Pin 16
Pitch: Pin 14
Yaw: Pin 15
Throttle: Pin 7
AUX1: Pin 8
AUX2: Pin 0

I've also got a LED on pin 13, that indicates if the quad is in rate or level/angle mode..

And of course SDA/SCL for the sensors...

Currently the code only uses the accelerometer and gyrometer to make the quad stable during rate- and angle mode..

In the future I may implement heading hold (magnetometer) and altitude hold (barometer).. Not sure yet, cause I didn't have any need for them...

For RX (receiver), PPM signal (Pulse-position modulation), The pins are as follows:
you mean ppm receiver work with your code ?

sk8amazing:
For RX (receiver), PPM signal (Pulse-position modulation), The pins are as follows:
you mean ppm receiver work with your code ?

Yes, the receiver sends ordinary servo pulses/PPM to the arduino (one signal per axis/control-rod, a total of 6 pins/signals). And because the signals are ordinary servo signals (50Hz update rate), I used interrupts in order to read these when they change and thus avoid getting my loop rate (~800Hz) draged down by these signals..

Here is a example of how these signals looks like:

Edit: I just read your other post about needing a code that reads PPM. I'll try to explain how I did it code-wise:

Let me begin by stating the problem ahead.. If we take the throttle-rod as an example, when the throttle-rod is in the (0% position) the receiver will send a signal that's ~21ms long (a high pulse for 1ms and a low pulse for 20ms).. And when its in the (100% position) the receiver will send a signal that's ~22ms long (a high pulse for 2ms and a low pulse for 20ms).. As you noticed the 20ms part is just a "synchronization part" and doesn't provide anything useful in our case..

What we need is to measure how long the "high pulses" are. And to do that we need to know when a pulse starts and when it ends. The simplest way of doing this is using External interrupts (very few pins on arduino!!)..

Here is a example code:

#define RX_INT_PIN_THROTTLE 0
volatile int rxPrev = 0; //variable that will contain the previous time
volatile int rxVal = 0; //variable that will contain the current throttle pulse length

void rxGoesHigh(){
/* As soon as we get into this function we measure the current time (with micros) 
and put that value in our variable rxPrev. After that we re-attach the same interrupt 
but this time we want it to fire when the pin goes low "FALLING". When that happens it 
will call the function rxGoesLow */
  rxPrev=micros();
  attachInterrupt(RX_INT_PIN_THROTTLE,rxGoesLow,FALLING);
}
void rxGoesLow(){
/* As soon as we get into this function we measure the current time (with micros) and 
subtract the previous time (rxPrev). By doing that we will get the length of the pulse,
from start to the end. We end this process by re-attaching the throttle pin to a RISING 
interrupt, which will repeat the process again... */
  rxVal=micros()-rxPrev;  
  attachInterrupt(RX_INT_PIN_THROTTLE,rxGoesHigh,RISING);
}

void setup(){
attachInterrupt(RX_INT_PIN_THROTTLE,rxGoesHigh,RISING); /*We begin by attaching a interrupt
to the throttle pin. the interrupt will fire when the pin goes high "RISING" (meaning the 
start of the pulse). When that happens it will call the function rxGoesHigh.*/
}
void loop(){
//Nothing to do here!
}

Begin by reading the comments in setup, then go to the function rxGoesHigh and continue to the function rxGoesLow. Because interrupts are handling your pulse-length changes, all you have to do to get the latest pulse-length is read the variable rxVal.

If you need to read a lot of pins I can write something similar to explain how you can use PIN-CHANGE-INTERRUPTS instead..

tnx . i will be great because this code is just for one channel and im sure i f go to edit this i will screw the code and everything go wrong :smiley: .

and some another question in this code we dont have any output pin ?

tnx . i will be great because this code is just for one channel and im sure i f go to edit this i will screw the code and everything go wrong smiley-grin .

Sure I can write the pin-change-interrupt explanation, but I'm going to use my quadcopter code as an example (Arduino Leonardo).. Meaning it won't work on the UNO... If you only got 4 channels you can go with a Arduino Leonardo (it has 5 external interrupts) or Arduino Mega (has 6 external interrupts) and reuse my example code that I posted above... if you don't want to buy another board you can use this library which makes PC-Interrupts look like a walk in the park..The library for the pin-change-interrupts will simplify a lot and make the code look like the example I posted..
Here is the library: Google Code Archive - Long-term storage for Google Code Project Hosting.

sk8amazing:
and some another question in this code we dont have any output pin ?

Well, no, because it's too simple really.. Here is a example of how to output PWM (combine this code with the previous example and give it a go)..

#define YOUR_OUTPUT_PIN 11
void setup(){
pinMode(YOUR_OUTPUT_PIN,OUTPUT);
}
void loop(){
int out = map(rxVal,1000,2000,0,255);
analogWrite(YOUR_OUTPUT_PIN,out);
}

But seriously, you clearly need to read and look at the different examples/tutorials in this forum and out there(internet of things).. I wouldn't mind writing the whole thing for you, but that won't teach you anything!

If you'd like, write your sketch and try it out and in-case it doesn't work and you've tried everything you can, post it here.. We would be more than happy to help you out..

//Basel

tnx . i mean it !!!! im working on it . and if goes wrong i will come and bothering you again . tnx

#define RX_INT_PIN_THROTTLE 3
#define YOUR_OUTPUT_PIN 11

volatile int rxPrev = 0; //variable that will contain the previous time
volatile int rxVal = 0; //variable that will contain the current throttle pulse length

void rxGoesHigh(){
pinMode (YOUR_OUTPUT_PIN, OUTPUT);
/* As soon as we get into this function we measure the current time (with micros)
and put that value in our variable rxPrev. After that we re-attach the same interrupt
but this time we want it to fire when the pin goes low "FALLING". When that happens it
will call the function rxGoesLow */
rxPrev=micros();

attachInterrupt(RX_INT_PIN_THROTTLE,rxGoesLow,FALLING);
}
void rxGoesLow(){
/* As soon as we get into this function we measure the current time (with micros) and
subtract the previous time (rxPrev). By doing that we will get the length of the pulse,
from start to the end. We end this process by re-attaching the throttle pin to a RISING
interrupt, which will repeat the process again... */
rxVal=micros()-rxPrev;
attachInterrupt(RX_INT_PIN_THROTTLE,rxGoesHigh,RISING);

}

void setup(){
attachInterrupt(RX_INT_PIN_THROTTLE,rxGoesHigh,RISING); /We begin by attaching a interrupt
to the throttle pin. the interrupt will fire when the pin goes high "RISING" (meaning the
start of the pulse). When that happens it will call the function rxGoesHigh.
/
}
void loop(){
//Nothing to do here!
int out = map(rxVal,1000,2000,0,255);
analogWrite(YOUR_OUTPUT_PIN,out);
}

i done this and i got some signals on pin 11
it is my ppm signal from receiver

and it is what i got after your code combination

is this pwm or i did edit the code wrong ?