UAV, reading sensor data Part II

In our previous adventure, Matt and I defeated the dragon and rescued a fake princess who turned into a giant spider  managed to get some meaningful data from both the gyrometer and the accelerometer. We also made some pretty graphs.

The next step is for us to compare the outputs from the Gyro and the Accelerometer. This is currently impossible, given that the Accelerometer is transformed into meaningul readings (degrees) already, and the gyro is just a load of “rate of change” readings.

We can get the orientation readings from the Gyro like this:

  //Create variables for outputs
  float xGyroRate, yGyroRate, zGyroRate, xGyroRate2, yGyroRate2, zGyroRate2;
  long Time;
  //Read the x,y and z output rates from the gyroscope & correct for some innacuracy; convert to seconds
  xGyroRate = (gyroReadX())/57.5;
  yGyroRate = (gyroReadY())/57.5;
  zGyroRate = (gyroReadZ())/57.5;
  //Determine how long it's been moving at this 'rate', in seconds
  Time = (millis()-previousMillis);
  //Multiply rates by duration
  xGyroRate2 = -(xGyroRate/Time)/4;
  yGyroRate2 = -(yGyroRate/Time)/4;
  zGyroRate2 = -(zGyroRate/Time)/4;
  //Add to cumulative figure
  if (((xGyroRate2)>(gyroLPF))||((xGyroRate2)<(-gyroLPF)))   CumulatGyroX += (xGyroRate2);   if (yGyroRate2>gyroLPF||yGyroRate2<-gyroLPF)   CumulatGyroY += (yGyroRate2);   if (zGyroRate2>gyroLPF||zGyroRate2<-gyroLPF)
  CumulatGyroZ += (zGyroRate2);

Now that we’ve done this, we can measure an axis from both the Gyro and the Accelerometer at the same time, and overlay them on top of one another in gnu plot.

Like so:

Yeah, that didn't really work.

Yeah, that didn’t really work.

Ok, so there was something wrong with that. We tweaked the code some more, and got something a bit better:

No, that's worse.

Much worse.

Finally, we figure out where we went wrong with the code. We don’t have the old versions, so we can’t show you our idiotic mistakes. After fixing it, we get something much closer to what we were expecting:

Roll measurement from Gyro and Accelerometer

Roll measurement from Gyro and Accelerometer

We can see from this graph that both sensors are outputting more or less the same thing. However the gyro measurements are actually off by a bit at the start, and are slowly producing a more noticeably incorrect orientation. If we used just the gyro, we’d end up with the plane downside up. There are also “spikes” in the accelerometer readings, at 700 and 1300 – these are probably noisy readings from the sensor.

To get an idea of how much the gyro readings drift, we turned on all the gyro sensors and then left the board still for a few seconds:

Gyro drift in three axes.

Gyro drift in three axes.

This is obviously not going to work long term – we can’t be certain of either sensor. We need a way to combine the readings from both sensors, or face the consequences.

UAV, reading sensor data

A long time before we did our session where we controlled some servos, we had a session where we were reading sensor data.

We’ve tried this a number of times, but this instance was where we actually started to get worthwhile data, and we could interpret it correctly.

We are currently reading two sensors to find orientation data: the 3 axis gyroscope and the 3 axis accelerometer.

I’ll cover the accelerometer first.

Reading Accelerometer Data

We’re using a 3 axis accelerometer  which if read correctly can tell us the pitch and roll of the aircraft (actually, just the pitch and roll of the sensor, but the sensor will be built into the aircraft).

Each axis in the accelerometer (we’ll call them accX, accY and accZ) tells us how pull that sensor is experiencing (at rest, this is due to gravity). We only need 1 axis to start with, to measure Pitch.

PitchIn this crappy diagram, the rectangle represents our accelerometer. It’s measuring apparent gravity. As the acceleromter has its pitch increased (rotated clockwise, in this case), the apparent gravity being measured in that axis will decrease.

Theta represents the angle between the apparent gravity and actual gravity.

The trigonometery to calculate pitch is pretty easy:

apparent gravity = cos (theta) * g

or:

acc = cos (theta) * g

The relationship between theta and pitch is very simple: simply add 90 degrees to theta to get pitch.

So, rewrite

apparent gravity = cos (theta) * g 

as

theta = acos (acc / g)

And then to get the actual pitch:

pitch = asin (acc / g)

/*------------------------------------------------------------------------*/
//Accellerometer Read and Output Section
 
  float xAccRate, yAccRate, zAccRate;
  double pitch, roll;
 
  xAccRate = (accReadX());
  yAccRate = (accReadY());
  zAccRate = (accReadZ());
 
  double measured_g = sqrt((xAccRate*xAccRate)+(yAccRate*yAccRate)+(zAccRate*zAccRate));
 
  roll = (atan2(xAccRate/128,zAccRate/128))*(180/3.141);
  pitch = (atan2(yAccRate/128,zAccRate/128))*(180/3.141);

Reading Gyro Data

Gyro data is actually a lot easier to read, in some ways. All a the gyrometer is doing is measuring rate of change since the last reading.

Therefore, all we need to do is integrate over a period of time to get the rotation in a certain axis.

Code:

/*-----------------------------------------------------------------------------*/
//Gyro Read & Output Section
 
  //Create variables for outputs
  float xGyroRate, yGyroRate, zGyroRate, xGyroRate2, yGyroRate2, zGyroRate2;
  long Time;
  //Read the x,y and z output rates from the gyroscope & correct for some innacuracy; convert to seconds
  xGyroRate = (gyroReadX())/57.5;
  yGyroRate = (gyroReadY())/57.5;
  zGyroRate = (gyroReadZ())/57.5;
  //Determine how long it's been moving at this 'rate', in seconds
  Time = (millis()-previousMillis);
  //Multiply rates by duration
  xGyroRate2 = -(xGyroRate/Time)/4;
  yGyroRate2 = -(yGyroRate/Time)/4;
  zGyroRate2 = -(zGyroRate/Time)/4;
  //Add to cumulative figure
  if (((xGyroRate2)>(gyroLPF))||((xGyroRate2)<(-gyroLPF)))   CumulatGyroX += (xGyroRate2);   if (yGyroRate2>gyroLPF||yGyroRate2<-gyroLPF)   CumulatGyroY += (yGyroRate2);   if (zGyroRate2>gyroLPF||zGyroRate2<-gyroLPF)
  CumulatGyroZ += (zGyroRate2);

Pretty simple 🙂

Some pretty graphs

Of course, that code took us a long time to actually write. And we may have borrowed some from elsewhere, I can’t for the life of me remember. Once we’d got it working, we plumbed the serial output into GNUPlot, so that we could get a visual representation of what was going on.

The general idea was to tilt the board by 90 degrees in once axis, then return it to it’s original position. This would produce a sine wave, eg:

output2

After mucking about for a bit with minicom, I used this command to capture the serial output:

sudo minicom --capture mincap

The serial output just looks something like this:

ID: 69
2 0 0
-32 -4 -27
-1 -1 1
0 -1 1
0 0 1
0 -1 0
0 1 0
0 1 0
1 -1 0
1 -1 0
0 -2 0
0 -1 0

Once we’d got that, I spend yet more time mucking around in gnuplot. Actually, I jest. It was pretty easy to plot a graph.

The first graph we got was this:

We'd done something very obvious and simple wrong.

We’d done something very obvious and simple wrong.

Spot the deliberate mistake.

Upon seeing this, we retired to the pub. Over a pint or three, we realised what it was we’d done wrong.

The Arduino board has an integer size of 16 bit, meaning it has a max size of 32,767. If you try to do

int i = 32767 + 1;

then i would have the value -32767.

And that’s exactly what was happening. We’d used an Integer, because occasionally I’m as thick as a brick sandwich.

We weren’t doing anything with the data yet to convert it to degrees, and we weren’t even sure how big the numbers would be, and we were just adding it all up.

Here’s another graph showing the same thing, but with the dots joined up:

temp2

After we started using the (entirely more sensible) long data type instead, we got what we’d originally expected:

temp6

So, as predicted, we got ourselves half a sine wave. If we tilt it by 90 degrees in one direction, then back to flat, then 90 degrees in the other direction, we get the full sine wave:

If the graph is a bit lumpy, it's because Matt had the shakes.

If the graph is a bit lumpy, it’s because Matt had the shakes.

In the next post, I’ll talk about working out the actual orientation, and sensor drift.  We’re also going to compare the output from the accelerometer and gyro.

Arduino: Controlling Servos

Last Sunday, Matt came to visit. He brought his MAN TIN along, which is filled with micro controllers and breadboards and miscellaneous wires and a machine that goes “Ping”.

We’ve not done any UAV work for a very long time, in fact the last time we did any was last Autumn. This has actually been my favourite session to date, because we made things move!

We’re going to be using servos to drive our control surfaces on the UAV, and this was a sort of Proof of Concept in making the things work.

We built the board, and hooked up the servos. The arduino program actually has some sample code for servos built in, so, not knowing how they work, we just hooked up that sample code.

All it does is make the servo rotate 180 degrees in one direction, then 180 degrees in the other direction, over and over again.

Here’s the code from the Arduino website. It’s not identical to ours, because we changed the pins, and then experimented with the speeds a bit. The speed was easy enough to alter: just change the delay between moves.

 
// Sweep
// by BARRAGAN <http://barraganstudio.com>
// This example code is in the public domain.
 
 
#include <Servo.h>
 
Servo myservo;  // create servo object to control a servo
// a maximum of eight servo objects can be created
 
int pos = 0;    // variable to store the servo position
 
void setup()
{
myservo.attach(9);  // attaches the servo on pin 9 to the servo object
}
 
 
void loop()
{
for(pos = 0; pos < 180; pos += 1)  // goes from 0 degrees to 180 degrees
{                                  // in steps of 1 degree
myservo.write(pos);              // tell servo to go to position in variable 'pos'
delay(15);                       // waits 15ms for the servo to reach the position
}
for(pos = 180; pos>=1; pos-=1)     // goes from 180 degrees to 0 degrees
{
myservo.write(pos);              // tell servo to go to position in variable 'pos'
delay(15);                       // waits 15ms for the servo to reach the position
}
}

Here’s a video of it actually working:

And the winner is…

Despite a 14-day top end for delivery, the Hobbyking parcel arrived this morning. Only been unboxed so far- here are a few pics:

The postcard is for scale. That’s a 12-inch diameter, 3 bladed prop. The prop fitting kit is very nicely machined and the spinner is a nice finishing touch; not bad for an extra $3 on top of the cost of the motor.

Sadly, batteries don’t have a connector compatible with the charger (despite being the same brand), and I forgot to order the connectors for the speed controller, so more than just a little assembly will have to wait.

Signing off.

… And then 3 come along at once!

Gentlemen, start your engines!

It’s a race between Germany and Hong Kong!
The flight electronics for the Bormatec have now been ordered from HK-based stockists, Hobbyking.

http://www.hobbyking.com/hobbyking/store/index.rc

2x 4000 mAh, 14.8 volt, 4S1P (4 series, 1 parallel) Lithium-Polymer cells, for main power.
An NTM Prop Drive Series 42-38 brushless motor, rated at 750kv*
Along with a 70 Amp ESC and the servos required to operate the aircraft.
Oh, and a LiPo charger. ‘Cos I was lacking one.

The combination of these, using one battery at a time (for better at-the-field testing times), should allow flight times of approximately half an hour. For propeller choice, I have gone for a scale-ish 3-bladed unit from Master Airscrew; 12 x 6 inch.

Running cost at this point, is now c. £350, including the original Arduino electronics and sensor modules. Significantly less, it’s worth noting, than any comparable equipment you could buy… Let’s say a comfortable factor of 10. At the minimum.

And now the waiting begins…

* KV in the sense of brushless RC motors, means RPM per Volt. (so max RPM 11,100)

Introducing… the Bormatec Vamp

Right!


After careful consideration, I’ve decided to invest in a Bormatec Vamp as a flying UAV-Testbed. It’s got a 1.8m wingspan, and an all-up maximum weight of 2.5kg; plenty of room for around a kilogram of payload. After doing a little math, it’d cost me about 3x as much as this to purchase the equipment to manufacture an airframe to the standards that I’d like.

At a cost of about £130 delivered to the UK from it’s German manufacturers, it’ll arrive as a kit of parts; assembly will be documented herein.

 

More pictures and information as soon as it arrives!

For more information on the Vamp, please refer to it’s manufacturer website, listed below- also the source of the included image.

http://bormatec.com/index.php?option=com_content&view=article&id=88&Itemid=91&lang=de

UAV, Finally

Above are a few pictures of things as they stand at present.

This project, as previously stated, is largely an experiment to improve skills, and produce something tangible. The aim is to produce an autonomous aerial vehicle; capable of flying to a destination co-ordinate, performing a task, and returning to base. (Likely, taking a picture or dropping a tennis ball to wind up Iain’s dogs).

The arduino control board was knocked together quickly to make it more robust than having a proto-board with all the components plugged into it.

In essence, the small red stick visible on the board to the right of the picture is a 9-DOF (Degrees of Freedom) sensor stick, incorporating an accelerometer, a  gyro, and a magnetometer. They communicate with the control board (the blue Arduino Pro Mini) via a two-wire protocol known as I2C; these in turn communicate with a base computer using two XRF modules.

http://shop.ciseco.co.uk/xrf-wireless-rf-radio-uart-rs232-serial-data-module-xbee-shape-arduino-pic-etc/

Left to it’s own devices, at present the little ‘Duino will talk to the Accelerometer and, working with a little clever 3-D math, ascertains the direction ‘down’. From this, it then outputs ‘pitch’ and ‘roll’ calculated values over a serial data bus, which is transmitted through the XRF daughterboard, up to a range of 2km, back to the PC via the second XRF, to the left of the picture. Note the little yellow and green LED’s; these flash to show data transmission and reception on each of the boards- Though I have forgotten which is which… it’s in the schematic somewhere if it becomes an issue.

It’s yet to be seen how well this responds to the G-forces generated during flight- Some thought as to an appropriate solution is required. Ideas, on a postcard…

The magnetometer and gyro are currently unused. The magnetometer will eventually determine the direction of the board relative to magnetic north; ‘yaw’. It will also use the gyro to increase the accuracy of the calculated P, Y, R angles.

I have also been working on a fuselage mould; Having discovered that none of the filler types I have access to will adhere reliably to expanded polystyrene, I have decided to change contsruction method for the fuselage of this drone; Likely at this point I will make use of vacuum moulding of ABS plastic, or a moulding made of fibreglass. Wings are to be made of extruded polystyrene- think foam fast food containers, but denser. A CNC machine will be made to produce wing sections.

 

That’s all for now; More as soon as my student loan allows!
-Matt

(Please ignore the deliberate PCB error of filed down LED’s; I made the footprint wrong, and was too impatient to wait for more to be cut!)

We’re going to build a UAV

My friend and I want to build an unmanned aerial vehicle. Unlike the predator drones, it will not be armed with missiles.

This is an educational project for us; I’ve never done any proper “bare metal” coding before, or even very much hardware based stuff. Matt, however, is great at the hands on, practical side, but his coding is lacking.

Between us, we should have enough knowledge to fuck up in new and interesting ways.

I’m going to let Matt explain what kit we’ve got, what each bit of it is for, and how he’s fitting it together. I’m going to cover the coding side, and the maths, and how we’re going to get it to fly itself. Or Matt will probably cover that last part; he is doing an engineering degree. I’ll be taking the theory he gives me, and implementing it :).

To start with, we’ll be doing some “basic” stabilisation stuff. We’ll get the plane to try and stay as level as possible, automatically correcting itself except when recieving input from the remote.

Oh – and we don’t have a plane yet.