Hi All!

I have been working on creating my first drone. I began this project by testing my own arduino based PID controller. Then I moved on to actually installing the PID and accelerometer/gyroscope into an RC glider to test for level flight (http://www.instructables.com/id/Intro-to-Model-Airplane-Autopilot/). I am moving on to a powered plane(I am starting with an E-flite UltraStick, and moving on to a water plane I have built once I have successful beta testing). I want to use cascading PIDs and a GPS to set the attitude my plane needs to reach desired waypoints. 

The problem is: my accelerometer and gyroscope refresh at about 20Hz while my GPS only refreshes at about 1Hz- I am using a parallax PMB 648, a cheapy, I know. In my loop function I tell the controller to get the accelerometer/gyroscope data (which comes in almost instantly), and then I have to wait a full second for the GPS data. So the plane would be unable to monitor and control its attitude while the GPS is refreshing. Is there a way to solve this problem without buying a faster GPS??

I tried setting up an interrupt function last night, but I couldjnot get it to work. In addition, the GPS communicates with the arduino serially, and from what I have heard this is not ideal for setting up interrupts. 

Any help would be much appreciated!!!

Thanks

Views: 561

Reply to This

Replies to This Discussion

Your best bet is to set up a serial interrupt handler but there's a simple, easy way to do this too until you become more familiar with interrupts on the AVR.

First, you'll use Serial.available() to determine if serial data is available to be read using Serial.read()

To run specific tasks at specific times, but avoid wasting time using delay(), you set up in your loop() function a series of if-then-else which check the current time to see if it's time to run each task.

Let's say your gyro updates at 100hz, your compass at 20hz, and your gps at 1hz. It'll look something like this.

http://pastebin.com/Kxvq5wbG

Thank you! I will try this when I get home tonight and I'll let you know how it works. If the GPS dumps the data without demanding an input from the arduino (which should be the case because I am only using 3 wires- power grnd and  tx from gps) then I believe this should work.

I am using the newsoftserial library, which allows me to set up a serial communication on any of the arduino's pins. Hopefully the "Serial.available" function works with this kind of communication.

I'd be wary of using a soft serial solution on such a slow processor.  There's a reason they build hardware peripherals into chips instead of emulating them in software.

You also want a faster GPS.  There are several modules for around $30, so there's really no reason not to upgrade.  You should consider 5hz to be a minimum for GPS updates. 

So if I buy a 5hz GPS, will I only be able to read my accelerometer/gyroscope at 5Hz?

Well, if you look at my code, you can read any sensor at any arbitrary interval... 

Gyro/accel/mag usually use I2C.  I'm not aware that any of them even have a serial interface.  Some have I2C and SPI.

If you can avoid NSS that'd be best. I've used it successfully, though. If you can get away with one serial comm at a time and no hardware comm it's ok. Also speed will have to be < 115200; it appeared to crap itself when I recently tried to read a continuous stream of data at 115200.

I'm about 97% sure NSS implements an available() member function. So say you have obj gps declared as NewSoftSerial class. Just do gps.available()

GPS modules tend to default to sending NMEA data over serial without further interaction.Typically there are command sequences to change baud rate, or the sentences being sent or not sent, intervals, etc.

Whatever the update rate of the GPS or any other sensor, you can just 'schedule' activities based on the current millisecond counter.

I'd recommend using TinyGPS -- it has a parse routine that you can use to parse character by character. But then it has a process() routine that you can call once a second (or however often) to read the parsed data from the nmea stream. I haven't looked at the latest code but the version I was using from a couple years ago has a bug that truncates lat and/or lon resulting in reduced precision. Easily fixed if it hasn't been already.

LMK if I can help further with any of this stuff. Just post up here and I'll do what I can.

This has been a huge help! I will try this first thing when I get home from work and will try to post before I go to bed. 

I do have the TinyGPS library as well as the NSS. When I was looking at the sample code off of the parallax website it said both were needed to run the gps. 

I'll also bust out Ubunto to crack open the TinyGPS library to see if I can make heads or tails of this parse routine.

Check the tinygps site for usage example. http://arduiniana.org/libraries/tinygps/ -- look under the Usage subheading. It actually uses NewSoftSerial and TinyGPS together.

So, if serial data is available, you call the encode() member function of TinyGPS to parse a single character at a time each time through the loop.

My code example isn't exactly right because I didn't remember everything perfectly and I haven't compiled it or anything, but hopefully it gives you the gist of things.

Thanks again! I used the nss.available() & encode() functions like you said and it drastically improved my response rate. Basically my code looks like this:

void loop(){

   getAccel();

   getGyro();

   while(nss.available()){

           int c = nss.read();

           if (gps.encode(c)){

           print Longitude;

           print Latitude;

           print Altitude;

           print Satellites; 

           etc.

         }

    }

}

with this setup I constantly receiving accelerometer and gyroscope data. Every second or so the GPS will interupt the process and dump its data. It does not slow down the refresh rate of my other sensors, and takes considerably less time & space compared to the parallax code.

Ok good. Let's take it a step further towards the code I had.

The big thing that's missing is that you're not scheduling tasks down to the millisecond. It's all just running as fast as it can.

When gps serial data is available, your code delays as long as it takes to read a character, encode it, and print stuff. I'm guessing that will probably be on the order of a few to tens of milliseconds.

When gps data isn't available, there's no delay and you read accel/gyro as fast as you can. So the time between accelerometer and gyro reads varies.

If you compute heading, you have to take heading rate x time. At the very least you need to measure that time. But it's much better to use the modulus operation I posted to ensure that sensors are read on a relatively strict schedule so that gps data read/encode doesn't throw off the timing of the rest of it.

So, what are you going to do with the data now that you have it?

So the refresh rate was excellent last night! I am still a little shaky on scheduling tasks. The GPS was refreshing faster than once per second(which is impossible according to the product specs) so I assume that it was just pulling old data? I am at work, so I can only show the pseudo code:

void loop(){

int now = millis();

if ((now%10)==0){

   getAccel();

   getGyro();

}

if((now%100)<11){                                 //I actually had this as (now%100)>0 but i realize now that has to be the same as constantly running it

   while(nss.available()){

           int c = nss.read();

           if (gps.encode(c)){

           print Longitude;

           print Latitude;

           print Altitude;

           print Satellites;

           print Speed_in_mps;

           print Course

           etc.

         }

    }

}

}

As far as interpreting data, I am still fumbling through it. i was trying to avoid buying  a compass in the hopes that I can use the course function of the GPS or use the last two coordinates to find the bearing. So thats more data I need to recover. 

I figured that programming the climb rate should be relatively easy. Just use the change in elevation and the distance between the plane and the waypoint. Something like pitch_angle = arctan(change in elevation/change in distance)?? It seems like there would have to be a max climb/dive angle.

As for lining up the plane with the waypoint, this seems much trickier. Suppose the plane is flying in the complete wrong direction(and suppose I can already detect this from the GPS). How should I determine how gentle/sharp of a turn to make?? Maybe I'll have to buy a compass during lunch...

RSS

Social Networking

Contests

Season Two of the Trust Time Trial (T3) Contest has now begun. The fourth round is an accuracy round for multicopters, which requires contestants to fly a cube. The deadline is April 14th.

A list of all T3 contests is here

Groups

Advertisement

© 2013   Created by Chris Anderson.   Powered by

Badges  |  Report an Issue  |  Terms of Service