Quadrotor
This summer's Edgerton Center Engineering Design class produced four awesome projects in four weeks. One of the projects was a functional RC quadrotor built with commonly-available RC equipment and an Arduino microcontroller board. Here is the instructions on how to make the quadrotor. The video of the four projects can be found here.
Parts List:
- 1/32” aluminum sheet
- 2 of 8 x 3.8 slow flyer propeller
- 2 of 8 x 3.8 slow flyer pusher propeller
- 4 of Turnigy C2028 Micro brushless outrunner 1400kV motor
- 4 of Turnigy Plush 18 amp speed controller
- Turnigy nano-tech 1800mah 4S 35-70C Lipo Pack
- 1/2” 4-40 plastic machine screws
- 4-40 plastic nuts
- 1/2” 4-40 aluminum machine screws
- 5/8” 4-40 aluminum machine screws
- 3/8” 4-40 aluminum machine screws
- 2” threaded 4-40 plastic spacers
- Accelerometer + Gyros chip: Sparkfun 6DOF razor IMU
- Microcontroller: arduino mini
- Hobbyking 2.4 GHz transmitter and receiver + Controller
- 1.5” hex threaded 4-40 aluminum spacers
- 2 of Carbon Fiber square tube .25” x .25” (.180 ID) x 48”
- Strings
- Zip-ties
- Super glue
- Velcro
- Protoboard
- Female header pins
- 3.3 volt regulator
- Jumper Wires
Where to get parts:
Propellers- http://www.apcprop.com/pindex.asp?Page=2
http://hobbyking.com/hobbyking/store/uh_index.asp
Carbon Fiber square tube - http://www.dragonplate.com/
http://www.mcmaster.com/
http://www.sparkfun.com/commerce/categories.php
Parts List:
- 1/32” aluminum sheet
- 2 of 8 x 3.8 slow flyer propeller
- 2 of 8 x 3.8 slow flyer pusher propeller
- 4 of Turnigy C2028 Micro brushless outrunner 1400kV motor
- 4 of Turnigy Plush 18 amp speed controller
- Turnigy nano-tech 1800mah 4S 35-70C Lipo Pack
- 1/2” 4-40 plastic machine screws
- 4-40 plastic nuts
- 1/2” 4-40 aluminum machine screws
- 5/8” 4-40 aluminum machine screws
- 3/8” 4-40 aluminum machine screws
- 2” threaded 4-40 plastic spacers
- Accelerometer + Gyros chip: Sparkfun 6DOF razor IMU
- Microcontroller: arduino mini
- Hobbyking 2.4 GHz transmitter and receiver + Controller
- 1.5” hex threaded 4-40 aluminum spacers
- 2 of Carbon Fiber square tube .25” x .25” (.180 ID) x 48”
- Strings
- Zip-ties
- Super glue
- Velcro
- Protoboard
- Female header pins
- 3.3 volt regulator
- Jumper Wires
Where to get parts:
Propellers- http://www.apcprop.com/pindex.asp?Page=2
http://hobbyking.com/hobbyking/store/uh_index.asp
Carbon Fiber square tube - http://www.dragonplate.com/
http://www.mcmaster.com/
http://www.sparkfun.com/commerce/categories.php
Cut 2 of 14”, 4 of 6.125”, 4 of 8” carbon fiber square tubes
Drill 7/64” holes 3/8” away from each ends of the cut carbon fiber tubes.
Drill 7/64” holes 1 and 5/8” from both ends of 14” long carbon fiber tubes. Drill 7/64” holes 1 and 5/8” from only one end of 6.125” and 8” long carbon fiber tubes.
When drilling through the carbon fiber tubes, drill very slowly with caution. Carbon fiber tubes can split if you don't pay attention. Also use a drill press instead of a hand drill.
Drill 7/64” holes 3/8” away from each ends of the cut carbon fiber tubes.
Drill 7/64” holes 1 and 5/8” from both ends of 14” long carbon fiber tubes. Drill 7/64” holes 1 and 5/8” from only one end of 6.125” and 8” long carbon fiber tubes.
When drilling through the carbon fiber tubes, drill very slowly with caution. Carbon fiber tubes can split if you don't pay attention. Also use a drill press instead of a hand drill.
Cut 4 of 2”x2” square from 1/32” aluminum sheet. File the sides and corners of the square
Mark the center lines of the square so that it forms a cross. Drill a 1/8” hole on the center of the aluminum square. Place the center of the motor on the 1/8” hole and mark the motor leg holes on the aluminum square. Line one of the motor leg holes on one of the center lines.
Drill 9/64” holes on the aluminum for the motor legs.
Mark the center lines of the square so that it forms a cross. Drill a 1/8” hole on the center of the aluminum square. Place the center of the motor on the 1/8” hole and mark the motor leg holes on the aluminum square. Line one of the motor leg holes on one of the center lines.
Drill 9/64” holes on the aluminum for the motor legs.
Place 2 of the 6.125” carbon tubes on each end of a 2x2 square aluminum sheet. The carbon tube should be parallel to each other. The two carbon fiber tubes should be parallel to the center line drawn on the 2x2 aluminum sheet where one of the motor leg holes are.
On the 2x2 aluminum sheet, mark where the holes on the carbon tubes are by placing a center punch through the holes on the tube.
Repeat this step for the other two 6.125" carbon tubes and 2x2 square aluminum sheet.
On the 2x2 aluminum sheet, mark where the holes on the carbon tubes are by placing a center punch through the holes on the tube.
Repeat this step for the other two 6.125" carbon tubes and 2x2 square aluminum sheet.
Repeat the previous step for the 14” carbon tubes. The 2x2 aluminum sheets should be on both ends of the 14” carbon tubes.
Place one end of the 8” tubes with two holes along the center line drawn on the 2x2 aluminum sheet with the motor leg hole. One of the holes on the 8” carbon tube should line up with the motor leg hole. Place the 8” carbon tube so that the longer side points the opposite direction from the other carbon tubes. Mark the remaining hole on the 8” carbon tube on the aluminum sheet with a center punch.
Drill 7/64” holes on the 2x2 aluminum sheets where the center punch left marks.
Drill 7/64” holes on the 2x2 aluminum sheets where the center punch left marks.
Attach the carbon tubes using 4-40 plastic machine screws and nuts. Do not place any screws through the hole on the 8” carbon tube that is lined up with the motor leg hole.
Super glue .188” locating ring into the propellers
When the super glue is dry, use a 1/4” drill bit to slightly enlarge the locating ring hole until the motor shaft slips on.
Drill holes on the side of the propellers corresponding to the holes on the motor shaft and attach the propellers to the motor using the screws that were on the motor shaft.
When the super glue is dry, use a 1/4” drill bit to slightly enlarge the locating ring hole until the motor shaft slips on.
Drill holes on the side of the propellers corresponding to the holes on the motor shaft and attach the propellers to the motor using the screws that were on the motor shaft.
Attach the motors on the 2x2 aluminum sheets by placing a nut between the motor leg and the aluminum sheet so that the motor is not flush against the aluminum sheet. Same pitched propellers should be across to each other, so attach the slow flyer propellers on the 2x2 aluminum sheets with 6.125” carbon tubes. Use 5/8” aluminum machine screws for the holes that are lined up with the 8” carbon tubes.
Cut two sheets of 5”x5” aluminum sheets. Mark 2” on the center of each sides of the 5x5 aluminum sheets. Connect the ends of 2” sides so that the drawn lines form an octagon.
Cut out the corners of the 5x5 aluminum sheets along the drawn line to make octagons.
File the corners and the edges of the octagon.
Cut out the corners of the 5x5 aluminum sheets along the drawn line to make octagons.
File the corners and the edges of the octagon.
Draw center lines of the 2” sides on one of the octagons. Define x and y axis. With a center punch, mark at points (.875,2.125), (1.375,.875), (2.125,.875), (2.125,0), (1.5, 1.5) from the origin or the point where the center lines intersect. Reflect the marked points over the center lines so that each quadrant has the same points.
Drill 7/64” holes on the marked spots on the octagon.
Drill 7/64” holes on the marked spots on the octagon.
Place the octagon on the center of the 14” carbon tube assembly. The holes on the points (.875,2.125) and (.875, -2.125) have to lie on one of the 14” carbon tubes. The holes on the points (-.875, 2.125) and (-.875, -2.125) have to lie on the other 14” carbon tubes. Make sure the aluminum octagon is on top of the carbon tubes. Mark the holes on the carbon tubes through the holes on the aluminum octagon using a center punch. DO NOT use a spring loaded center punch on the carbon tube. GENTLY tap the center punch with a rubber mallet.
Place the 6.125” carbon tube assemblies on the other two sides to create a cross like shape with the carbon tubes. The holes on the points (2.125, .875) and (1.375, .875) on one of the carbon tubes of one of the 6.125” assemblies. The holes on the points (1.375, -.875) and (2.125, -.875) should lie on the other carbon tube. Make sure the motors are facing the same direction. The holes on the points (-2.125, .875) and (-1.375, .875) on one of the carbon tubes of the other 6.125” assemblies. The holes on the points (-1.375, -.875) and (-2.125, -.875) should lie on the other carbon tube. Mark the holes using a center punch.
Drill 7/64” holes on the marked spots on the carbon tubes. The carbon tubes break easily when drilling, so drill very slowly.
Attach the carbon tube assemblies to the corresponding spots on the aluminum octagon.
Attach the carbon tube assemblies to the corresponding spots on the aluminum octagon.
On the second aluminum octagon, draw center lines from the 2” sides. Define x and y axis. On the protoboard, there are four holes in each corner. Aline the long side of the protoboard along the y axis and mark the four corner holes on the octagon. Drill using 7/64” drill bit for the four holes.
Duct tape top of the octagon where the protoboard is being attached to prevent short circuiting.
Duct tape top of the octagon where the protoboard is being attached to prevent short circuiting.
With a center punch, mark points at (1.5,1.5), (2.125, 0) and (1.7, .86). Reflect the point over the center lines so that each quadrant have the same points.
Drill 7/64” holes on the marked spots.
Drill 7/64” holes on the marked spots.
Attach the protoboard on to the second octagon using plastic machine screws with nuts between the board and the octagon so that the bottom of the protoboard does not touch the octagon.
Cut 2”x4” rectangle from the 1/32” aluminum sheet. File down the corners and sides.
Draw center lines on the rectangle and define the center line from the 4” side as the y axis so that when the y axises from the octagons and the rectangle are lined up, the long sides of the protoboard and the aluminum rectangle would be perpendicular to each other.
With a center punch, mark points at (1.7, .86) and the reflected points over the center lines in each quadrant.
Drill 7/64” holes on the marked spots
Draw center lines on the rectangle and define the center line from the 4” side as the y axis so that when the y axises from the octagons and the rectangle are lined up, the long sides of the protoboard and the aluminum rectangle would be perpendicular to each other.
With a center punch, mark points at (1.7, .86) and the reflected points over the center lines in each quadrant.
Drill 7/64” holes on the marked spots
Place a strip of Velcro on the aluminum rectangle and the on one of the 123mm x 29mm sides of the battery. Attach the battery and the aluminum rectangle.
Place the 1.5” aluminum hex spacers on (1.7,.86) and the corresponding points between the aluminum rectangle with the battery and the octagon with the protoboard. The battery should be under the protoboard. Bolt the rectangle, octagon and hex spacers using 4-40 plastic machine screws.
Place the 1.5” aluminum hex spacers on (1.7,.86) and the corresponding points between the aluminum rectangle with the battery and the octagon with the protoboard. The battery should be under the protoboard. Bolt the rectangle, octagon and hex spacers using 4-40 plastic machine screws.
Solder the speed controllers to the motors so that the propellers spin the right direction.
Refer to the wiring diagram for electrical connections.
Notes on diagram wiring :
-We used additional header pins to all connected to VCC to create additional 5V pins. We did the same for ground.
-1 speed controller’s 5V power from the 3-wire-connector must go to VCC on the Arduino. This connection supplies the power for the entire board.
-All 4 speed controllers’ ground wires must connect to the Arduino’s ground pin(s).
Refer to the wiring diagram for electrical connections.
Notes on diagram wiring :
-We used additional header pins to all connected to VCC to create additional 5V pins. We did the same for ground.
-1 speed controller’s 5V power from the 3-wire-connector must go to VCC on the Arduino. This connection supplies the power for the entire board.
-All 4 speed controllers’ ground wires must connect to the Arduino’s ground pin(s).
Cut the 2” plastic spacers in half. Place the 1” spacers between the two octagons on the holes at points (1.5,1.5) and (2.125,0) and the corresponding points in the other quadrants. The center line axis on both octagons should line up. Also the protoboard should lie between the 14” carbon tubes
Bolt the two octagons with the 1” plastic spacers with 4-40 plastic screws.
Bolt the two octagons with the 1” plastic spacers with 4-40 plastic screws.
Use 1/2” aluminum machine screws to attach 2” plastic spacers at the end of the 8” carbon tubes. Tie a string around the frame by placing the string between the plastic spacers and the carbon tubes.
Screw on 3/8” aluminum machine screws on top of the 2” plastic spacers. Tie a string around the frame similar to step 41, except the second string has to go between the plastic spacers and the 3/8” aluminum machine screws so that the string is tied on top.
Code
Our code was written in a modified form of C++ that is described on the Arduino website.
Our code represents a feedback control system known as PID (proportional integral derivative). Currently, it only employs use of the proportional and derivative components. With our current code, the quadrotor self-stabilizes quite well in the air, but is a little unstable on takeoff. However, this instability can be mitigated by taking off quickly.
To find the current amounts of tilt on the X and Y axis from accelerometer and gyro data, we used an algorithm that would average previous accelerometer data and combine it with gyro data to reach an angle measurement that was fairly resilient to linear acceleration.
We only do 2 Pulsin commands per loop (instead of 4) to cut the loop time in half, which makes the quadrotor control system much more responsive.
//neutral accelerometer/gyro positions
#define X_ZERO 332
#define Y_ZERO 324
#define Z_ZERO 396
#define PITCH_ZERO 249
#define ROLL_ZERO 249
#define YAW_ZERO 248
#define GYRO_CON 1.47
#define ACCEL_CON 0.93
#define TIME_CON 0.02
#define SEN_CON 0.95
//motor speed vars
int speeds[4];
//gyro inputs - current tilt vars
float pitch, roll, yaw;
int pitchzero, rollzero;
//accelerometer inputs - current acceleration vars
float xin, yin, zin;
//human inputs - control info vars
float pitchin, rollin, yawin, zhuman;
//random other vars
float xaverage=0, yaverage=0;
int y=0;
int blah;
//proportionality constants
float p=2.5; // P proportionality constant
float d=0.5; // D proportionality constant
void setup() {
zhuman=0;
rollin=0;
Serial.begin(9600);
for(int x=6; x<10; x++) {
pinMode(x, OUTPUT);
}
//send upper bound for human inputs to the motor speed controllers
for(int x=6; x<10; x++) {
pulsout(x,2000);
}
delay(5000);
//get zeros for pitch and roll human inputs
for(int x=0; x<10; x++) {
y=y+analogRead(3);
}
pitchzero=y/10;
y=0;
for(int x=0; x<10; x++) {
y=y+analogRead(4);
}
rollzero=y/10;
}
void loop () {
//accelerometer and gyro inputs ranged -232 to 232?
xin=(analogRead(0)-X_ZERO)*ACCEL_CON;
yin=(analogRead(1)-Y_ZERO)*ACCEL_CON;
zin=(analogRead(2)-Z_ZERO)*ACCEL_CON;
pitch=(pitchzero-analogRead(3))*GYRO_CON;
roll=(rollzero-analogRead(4))*GYRO_CON;
yaw=(analogRead(5)-YAW_ZERO)*GYRO_CON;
//get human inputs through radio here range of -30 to 30 except for zhuman which has an ideal range of 1000-2000, only 2 pulses per loop
if(blah==0) {
yawin=0.06*((signed int) pulseIn(2,HIGH)-1500);
pitchin=0.06*((signed int) pulseIn(3,HIGH)-1500);
blah=1;
}
else {
zhuman=(signed int) pulseIn(4,HIGH);
rollin=0.06*((signed int) pulseIn(5,HIGH)-1400); //1400 instead of 1500 is to correct for the underpowered motor #4 by trimming it in code
blah=0;
}
//averaging, etc.
xaverage= SEN_CON *( xaverage + TIME_CON * pitch) + ( 1 - SEN_CON ) * xin;
yaverage= SEN_CON *( yaverage + TIME_CON * roll) + ( 1 - SEN_CON ) * yin;
//calculate the motor speeds
if(zhuman<1150) {
for(int x=0; x<4; x++) {
speeds[x]=zhuman;
}
}
else {
if(zhuman > 1450) {
zhuman = 1450;
}
speeds[0] = zhuman - p*(xaverage - pitchin) - p*(yawin) - d*pitch;
speeds[1] = zhuman - p*(pitchin - xaverage) - p*(yawin) + d*pitch;
speeds[2] = zhuman - p*(yaverage - rollin) + p*(yawin) - d*roll;
speeds[3] = zhuman - p*(rollin - yaverage) + p*(yawin) + d*roll;
}
//set the upper and lower bounds for motor speeds (1000=no speed, 1600=upper speed limit, 2000=maximum possible speed)
for(int x=0; x<4; x++) {
//speed limit between 1000 and 1600
if(speeds[x]<1000) {
speeds[x]=1000;
}
if(speeds[x]>1600) {
speeds[x]=1600;
}
}
//pulsouts to motor speed controllers
for(int x=0; x<4; x++) {
pulsout(x+6,speeds[x]);
}
}
void pulsout (int pin, int duration) {
digitalWrite(pin, HIGH);
delayMicroseconds(duration);
digitalWrite(pin, LOW);
}
Our code represents a feedback control system known as PID (proportional integral derivative). Currently, it only employs use of the proportional and derivative components. With our current code, the quadrotor self-stabilizes quite well in the air, but is a little unstable on takeoff. However, this instability can be mitigated by taking off quickly.
To find the current amounts of tilt on the X and Y axis from accelerometer and gyro data, we used an algorithm that would average previous accelerometer data and combine it with gyro data to reach an angle measurement that was fairly resilient to linear acceleration.
We only do 2 Pulsin commands per loop (instead of 4) to cut the loop time in half, which makes the quadrotor control system much more responsive.
//neutral accelerometer/gyro positions
#define X_ZERO 332
#define Y_ZERO 324
#define Z_ZERO 396
#define PITCH_ZERO 249
#define ROLL_ZERO 249
#define YAW_ZERO 248
#define GYRO_CON 1.47
#define ACCEL_CON 0.93
#define TIME_CON 0.02
#define SEN_CON 0.95
//motor speed vars
int speeds[4];
//gyro inputs - current tilt vars
float pitch, roll, yaw;
int pitchzero, rollzero;
//accelerometer inputs - current acceleration vars
float xin, yin, zin;
//human inputs - control info vars
float pitchin, rollin, yawin, zhuman;
//random other vars
float xaverage=0, yaverage=0;
int y=0;
int blah;
//proportionality constants
float p=2.5; // P proportionality constant
float d=0.5; // D proportionality constant
void setup() {
zhuman=0;
rollin=0;
Serial.begin(9600);
for(int x=6; x<10; x++) {
pinMode(x, OUTPUT);
}
//send upper bound for human inputs to the motor speed controllers
for(int x=6; x<10; x++) {
pulsout(x,2000);
}
delay(5000);
//get zeros for pitch and roll human inputs
for(int x=0; x<10; x++) {
y=y+analogRead(3);
}
pitchzero=y/10;
y=0;
for(int x=0; x<10; x++) {
y=y+analogRead(4);
}
rollzero=y/10;
}
void loop () {
//accelerometer and gyro inputs ranged -232 to 232?
xin=(analogRead(0)-X_ZERO)*ACCEL_CON;
yin=(analogRead(1)-Y_ZERO)*ACCEL_CON;
zin=(analogRead(2)-Z_ZERO)*ACCEL_CON;
pitch=(pitchzero-analogRead(3))*GYRO_CON;
roll=(rollzero-analogRead(4))*GYRO_CON;
yaw=(analogRead(5)-YAW_ZERO)*GYRO_CON;
//get human inputs through radio here range of -30 to 30 except for zhuman which has an ideal range of 1000-2000, only 2 pulses per loop
if(blah==0) {
yawin=0.06*((signed int) pulseIn(2,HIGH)-1500);
pitchin=0.06*((signed int) pulseIn(3,HIGH)-1500);
blah=1;
}
else {
zhuman=(signed int) pulseIn(4,HIGH);
rollin=0.06*((signed int) pulseIn(5,HIGH)-1400); //1400 instead of 1500 is to correct for the underpowered motor #4 by trimming it in code
blah=0;
}
//averaging, etc.
xaverage= SEN_CON *( xaverage + TIME_CON * pitch) + ( 1 - SEN_CON ) * xin;
yaverage= SEN_CON *( yaverage + TIME_CON * roll) + ( 1 - SEN_CON ) * yin;
//calculate the motor speeds
if(zhuman<1150) {
for(int x=0; x<4; x++) {
speeds[x]=zhuman;
}
}
else {
if(zhuman > 1450) {
zhuman = 1450;
}
speeds[0] = zhuman - p*(xaverage - pitchin) - p*(yawin) - d*pitch;
speeds[1] = zhuman - p*(pitchin - xaverage) - p*(yawin) + d*pitch;
speeds[2] = zhuman - p*(yaverage - rollin) + p*(yawin) - d*roll;
speeds[3] = zhuman - p*(rollin - yaverage) + p*(yawin) + d*roll;
}
//set the upper and lower bounds for motor speeds (1000=no speed, 1600=upper speed limit, 2000=maximum possible speed)
for(int x=0; x<4; x++) {
//speed limit between 1000 and 1600
if(speeds[x]<1000) {
speeds[x]=1000;
}
if(speeds[x]>1600) {
speeds[x]=1600;
}
}
//pulsouts to motor speed controllers
for(int x=0; x<4; x++) {
pulsout(x+6,speeds[x]);
}
}
void pulsout (int pin, int duration) {
digitalWrite(pin, HIGH);
delayMicroseconds(duration);
digitalWrite(pin, LOW);
}
Tuning
Due to variance in the individual motors / frame, you may need to alter the p and d values in the code above. The variable p controls how much the quadrotor will alter motor speeds to correct for an offset from the desired tilt. The variable d controls how much the quadrotor will resist sudden rotation. An incorrect ratio of p to d could cause the quadrotor to be unstable either by being less responsive than desired or by causing oscillations of increasing magnitude. Scaling up both p and d by the same value would increase the magnitude of the current effects.
Our tuning method involved a lot of trial and error. We would support 2 opposite corners of the quadrotor leaving the other 2 free to rotate. Then we would check for stability by first observing if the quadrotor was keeping itself level, then secondly by injecting disturbances to observe if it would return to a level position. If the p and d values permitted the quadrotor to pass both of these tests, we would repeat the procedure and on the other axis. When the quadrotor was stable on both axis, we then were ready to fly!
Our tuning method involved a lot of trial and error. We would support 2 opposite corners of the quadrotor leaving the other 2 free to rotate. Then we would check for stability by first observing if the quadrotor was keeping itself level, then secondly by injecting disturbances to observe if it would return to a level position. If the p and d values permitted the quadrotor to pass both of these tests, we would repeat the procedure and on the other axis. When the quadrotor was stable on both axis, we then were ready to fly!