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.

And again with the coding…

Here’s a little Arduino code I’ve cooked up for the purposes of providing a nice crank signal to the FPGA-based ECU, for the purposes of bench testing the output. It’s a simulation of a nicely cleaned up, digital signal generated by a 36-1 toothed crank wheel on your typical Ford engine.

Essentially, a little throttle position sensor (read, potentiometer) is hooked up to adc pin 5. This is purely to give me something to twiddle to see if the FPGA is reacting quickly enough to the change in frequency (Not that I have any fear of this, really- damn thing is pretty fast- but alas, I must have something to fiddle with while testing, or it’s no fun!).

The LED flashing part is purely for visual effect; an ‘is it working’ before I had chance to hook it up to an oscilloscope for testing.

The code is simple enough, my written code is starting to look more user-friendly, and- importantly- it works. Onward with the FPGA testing, then?

Maybe after my exams; this was put together in my ‘evening off’. (Oh, ninjaedit- it only ‘works’ when debug = 1)

//-------------------------------------------------------------------------------
 
#include <Wire.h>
 
//-----------------------------------
// Calibration Values for TPS
float minimumReading = 48;
float maximumReading = 919;
//-----------------------------------
 
//Setttings for TPS
int analogPin = 5; // Throttle Position Sensor Wiper Pin
int throttleRead= 0; // variable to store the value read
int throttleCorrected= 0; // variable to store the corrected value
 
//LED flashy bit setup
const int ledPin = 13; // The number of the onboard LED pin
int ledState = LOW; // Used to store the LED state
 
//Variables for Pulse Generator
long pulseLength = 0; // Variable to store the generated pulse length
long gapLength = 0;
int toggle = 1; // Variable to act as a toggle
long lastMicros = 0; // Variable to act as timer function
int count = 1; // Variable to store the current tooth count
int calibrate = 92.59259259259; // Calibration for top speed = appx. 9k rpm
 
int rpm1 = 1; // Variable to store the RPM number
int debug = 1; // Debug setting- changes output from RPM & pulse length to counter & gap indicator
 
void setup()
{
Serial.begin(9600); // Setup serial
pinMode(ledPin, OUTPUT);
}
 
void loop()
{
tpsRead(); // Run TPS Read loop
pulseGenerate();
}
 
void tpsRead()
{
throttleRead = analogRead(analogPin); // Read the input pin
throttleCorrected = ((throttleRead-minimumReading)/maximumReading)*100; // Subtract minimum from TPS. Calculate percentage of max
 
if (throttleCorrected<1)
{
throttleCorrected=1;
}
if (debug == 0)
{
rpm1 = 60000000/(pulseLength*36);
Serial.print("Simulated RPM :");
Serial.print(rpm1);
Serial.print("RPM; Pulse Width :");
Serial.print(pulseLength);
Serial.println("uS");
}
}
void pulseGenerate()
{
pulseLength = (throttleCorrected*calibrate); // Calculate length of 'high' pulse (in microseconds)
gapLength = pulseLength*3;
 
if ( (micros() > (lastMicros + pulseLength)) && (toggle==HIGH) && (count <= 35) )
{
lastMicros = micros();
toggle = LOW;
}
if ( (micros() > (lastMicros + pulseLength)) && (toggle==LOW) && (count < 35) )
{
lastMicros = micros();
toggle = HIGH;
count += 1;
if (debug == 1)
{
Serial.print (count);
Serial.print (",");
}
}
if ( (micros() > (lastMicros + gapLength)) && (toggle==LOW) && (count == 35) )
{
lastMicros = micros();
toggle = HIGH;
count = 1;
if (debug == 1)
{
Serial.println ("GAP");
Serial.print(count);
Serial.print (",");
}
}
digitalWrite(ledPin,toggle);
}

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!)