Saturday, 22 November 2014

All cleaned up :)

As I mentioned I would do in the last post, I got Raven's wiring all cleaned up. It actually looks more like spagetti in the pictures than what it was before, but it is much tidier and easy to trace and see in real life.
 I mounted the lipo semi-permenately (or at least much more than it was before) to the underside of the plate, sandwhiched between the GPS antenna wire and the roll cage support on the truck. In addition there is some other new stuff on the underside of the brain plate since last update besides the wiring. I added my HC-05 module to the breadboard and wired it up to serial2 on the mega (dang its nice having more than one serial port), haven't detailed the wiring yet when I had taken this picture, but it will be soon. I also added a AA battery for the GPS, it uses it to save the settings, as well as some data about the last fix to make getting a fix faster when it powers back up. I simply soldered some hookup wire to both ends of the battery and taped it to the front there. Also new is the power switch, from a model airplane for the radio reciever. It makes a nice easy switch to interface as it has predone 0.1" standard servo headers and a nice mounting solution. And lastly, I mounted my reset switch nice and accessably. Here is a closer up of the electronics:

To the right is all power and reset circuit wiring, middle is the steering servo connector, and on the right side, GPS, Compass, Bluetooth module and status LED wiring. I currently have the status LED wired to the Mega, with a little rutine in the code that looks for GPS validity and lights the LED if the data is valid, and does not if it is not. I originally had that hooked up to the GPS's fix output but I was having some real problems with the GPS's indicator, sometimes it worked sometimes it didn't. So now I ignore it and watch the light instead.
This is what the top of the brain plate looks like now:
A little cleaner with no LiPo awkwardly strapped to the top and wires coming out everywhere. Here is a closer shot of the front where all the interesting stuff is:
Note power switch on the left, status LED in the middle (back of the compass tower) and reset switch on the right all mounted nicely.

Ive been wondering and plotting how to get some telemitry data back from Raven while he is out on a run for troubleshooting and just interst's sake, but I was stumped for a little while. I don't even own an LCD screen and have little desire for one, my nRF24L01 modules are still wayyy too confusing, one day I will sit down and learn how to use them but not today, and unfortunately my SD card shield does not have assignable pins, so it will only work on an UNO (I have since ordered a microSD reader module from ebay for integration into Raven at some point just to log the lat and long and have a datafile I can plot on google earth) But then I remembered I have a HC-05. Perfect! coupled with either my laptop plus a bluetooth dongle or one of my phones plus an android terminal emulator, I have super easy telemitry data being sent to a nice screen :)
BAM! Its beautiful. Now I can see what he is thinking while he is out running about.

Alright, that's it for hardware at the moment, but I have also conqoured some software. Last post I mentioned that I needed to make the steering code better, and also get the GPS spitting out at 5Hz (I can make it spit out at up to 10Hz, but Adafruit says it only gets position updates every 5Hz anyway) Well those two turned out to be a little interconnected. First I actually did something totally unrelated to those. I was looking at ways to clean my code up a bit and I realized that I had the whole loop inside the if(serial1.avalible) statement, effectively making it so that it would only update the steering angle every time the GPS spat out a sentance, about once per second. So I remidied that and everything started functioning much better. Much much better. Amazing how things work out well when you actually program right. Next up was the rediscovering of the "Mini GPS" tool. Pretty much its something that connects to the GPS module via serial and lets you change a bunch of settings. And its linked in the Adafruit manual. Well I feel stupid :P Anyway, got it up and running, changed my GPS to spit out at 5Hz, only GPGLL (previously I had GPRMC which tells you time, lattitude, longitude, heading, speed, and date. I may use those additional ones at a later date, but for now the only ones I am using are the lat and long. GPGLL gives you only lat, long, and time.) and at 38400 baud. And coupled with that, was the battery backup. Because without the battery everytime power is disconnected to the GPS, it looses its configuration settings and returns to defualt. Awesome! GPS is spitting out what I want, my code is running smooth, and so I moved onto getting the proportional steering. Map() is amazing, I love it :) Here is the result:
Ahh, so much smoother and nicer. Aside from those changes, I did a little optimization, moved the servo pin and LED pin up so as to keep the interrupt pins free, changed to bluetooth debugging, and made some GPGLL related changes. Here is the code Raven is running at the moment (also note the rudimentary distance to waypoint estimation code. Needs work but kinda functions.):

#include <Servo.h> //Steering servo setup
Servo steer;

#include "Wire.h"  //Crap for the compass
#include "I2Cdev.h"
#include "HMC5883L.h"
HMC5883L mag;
int16_t mx, my, mz;

float latdest = 49.0819104;  // Initial destionation waypoint coordiantes.
float londest = -117.5801223;
//=== Variables used===
float heading = 0;  // HMC5883L heading
float tim = 0;  // GPS time
float lat = 0;  // GPS lattituede
float lon = 0;  // GPS longitude
int latd = 0;  // GPS lattitude degrees
float latm = 0;  // GPS lattitude decimal minutes
int lond = 0;  // GPS longitude degrees
float lonm = 0;  // GPS longitude decimal minutes
float deltay = 0;  // Difference in degrees between next waypoint and current location, Y direction
float deltax = 0;  // Difference in degrees between next waypoint and current location, X direction
float deltaym = 0;  // Difference in meters between next waypoint and current location, Y direction
float deltaxm = 0;  // Difference in meters between next waypoint and current location, X direction
double dist = 0;  // Distance in meters between next waypoint and current location
float hdgrad = 0;  // Computed required heading in radians
float hdgdeg = 0;  // Computed required heading in degrees
int err = 0;  // Computed difference between current heading and required heading
int sv = 1500;  // Servo steering value in microseconds

void setup()
{
  Wire.begin();   // More compass crap
  mag.initialize();
  steer.attach(5,1000,2000);  // Steering servo crap
  pinMode(4, OUTPUT); // status LED
  steer.writeMicroseconds(1500); 
  Serial2.begin(9600);  // Debugging over Bluetooth using an HC-05
  Serial1.begin(38400);  // Ultimate GPS is connected to serial 1. I used the tool "Mini GPS" to set the output to 5Hz, GPGLL only, 38400 Baud for this program.
}

void loop()
{
  while(latd != 49)  // This little chunck of code just forces the program into a loop here until valid GPS data is obtained. (Calculated using the lattitude I live at)
  {                  // A feedback LED is used to tell if the GPS has a fix at a glance. The lattitude is also spit out over the serial port when the GPS does not have a fix.
    if (Serial1.available() > 49)
    {
      Serial1.find("$GPGLL");
      lat = Serial1.parseFloat();
      latd= lat/100;
    }
    //Failsafe code if the GPS looses fix can be inserted here
    digitalWrite(4,LOW);
    Serial2.println(lat, DEC);
    delay(10);
  }
  digitalWrite(4,HIGH);
 
  mag.getHeading(&mx, &my, &mz);  // Reading the compass.
    heading = atan2(my, mx);
    if(heading < 0)
      heading += 2 * M_PI;
      heading = heading * 180/M_PI;
 
  if (Serial1.available() > 49)  // Parsing the GPS data
  {
    Serial1.find("$GPGLL");
    lat = Serial1.parseFloat();
    lon = Serial1.parseFloat();
    tim = Serial1.parseFloat();
    latd= lat/100;  // Converting the Degrees, decimal minutes given by the GPS into decimal degrees.
    latm = lat - latd*100;
    latm = latm/60;
    lat = latd + latm;   
    lond= lon/100;
    lonm = lon - lond*100;
    lonm = lonm/60;
    lon = lond + lonm;
    lon = 0 - lon;
  }
  Serial2.print(lat, DEC);  // Debugging the lat and long
  Serial2.print("  ");
  Serial2.print(lon, DEC);
  Serial2.print("  ");
 
  deltay = latdest - lat;  // Determining the change in degrees between next waypoint and current location
  deltax = londest - lon;
 
  deltaym = deltay*111211.71;  // Calculating the distance to next waypoint and debugging. (Calculated based on the lattitude I live on)(needs improvment)
  deltaym = abs(deltaym);
  deltaxm = deltax*73019.76;
  dist = sqrt(sq(deltaym)+sq(deltaxm));
  Serial2.print(dist, DEC);
  Serial2.print("  ");
 
  hdgrad = atan2(deltax,deltay);  // Calculating heading required to travel to next waypoint.
  hdgdeg = hdgrad*180/3.14;
  if (hdgdeg < 0)
    hdgdeg = hdgdeg + 360;
 
  err = heading - hdgdeg;  // Calculating error between current heading and required heading and debugging.
  err = ((((err) % 360) + 540) % 360) - 180;
  Serial2.print(err, DEC);
  Serial2.print("  ");

  err = err/2;  // Driving the steering servo baised on the err value. Reasonably proportional.
  sv = map(err,-90,90,1040,1960);
  Serial2.print(sv, DEC);
  Serial2.print("  ");
  steer.writeMicroseconds(sv);
  
  Serial2.println();  // Houskeeping. Making sure the serial data is formatted nicely for the phone screen, and the delay to keep the code from running too fast.
  delay(5);
}

Well, no nice body shot today cause really nothing has changed on the outside, but perhaps that will change soon. Its late November in Canada, and there is a couple inches of snow on the ground now, so I doubt Ill be running many test runs outside until spring, electronics+snow=not great. Which means that perhaps soon Ill be mounting some sonars on the top and gettting the obstical avoidance code running. Which also means giving raven control of his own throttle... Warning, rogue robot ahead. I may also mount my MPU6060 and see about using the acceleromiter and gyro for tilt compensation and smoothing of the compass data. Gotta keep looking ahead :) Thats all for now tho folks.

Sunday, 16 November 2014

Raven Progress

I have accomplished a fair amount on Raven these last few days. First off, I wired everything up, at the moment a little messily (thats next on the list, clean up the wiring) but functional.


The battery awkwardly zip tied to the top of the brain plate is a 3 cell lipo temporarily there just to power the control electronics and nothing else, even the steering servo is powered by the truck's batteries. I also added a yet to be mounted switch connected to the arduino's reset circut to make reseting it a little easier. As mentioned I will be cleaning up the wiring as I am not happy with it's current state, but thats a little later. In anticipation of having even more wiring added and being uncertain about the breadboard's ability to hold everything together I also ordered a prototyping shield from ebay which has not yet arrived.
I (gasp!) also worked on the software and actually got him up and running. This is a video of my very first test run. The space around my house is severly limited and coupled with the GPS's 30 foot accuracy, well it didn't go stellar. But thats OK! I include the footage because not everything always goes right.
With that success/failure/whatever_at_least_its_driving behind me I input the coordinates of the very center of a park close to me, curtisy of google maps:
And went for a drive over there. Here he is all ready to go:
The code that I am running (which will be attached at the end of the post) is, well frankly, very poorly coded and ultra rudimentary, as I have said before I am a terrible programmer (and not like those people who post and say that they are bad programmers, but their code is great, no, I am a genuinely terrible programmer. But you only get better by doing :)) But it runs and functions and I understand it all which is important. I am not using any proportionality on the steering, just a couple if commands to see if the error between the current heading and the required heading is greater than ten degrees (or in the last video 20) out in either direction and if so turning the wheels full left or right accordingly. At the moment I also have not given Raven control of his throttle either, to avoid a rogue robot running around out of hand:
Yeah, not a good thing :) anyway, for now I just use the transmitter to control the throttle while Raven does the steering. Here is a video showing raven's steering response to being turned around:
And here is a rather long video of him driving around trying to get to the middle of the park from various places around the perimiter. Of course some quirks, but on the whole he seemed to get there pretty well, considering the code he is running. The general area of the orbits seemed to be right in the middle of the park like google maps suggested. The video immediately below this one is the same run but shot from the gopro mounted on the front of Raven (It fell off near the end) Both videos are long, but if you watch the first little, you can see some low speed navigation, and if you go more to the end, I start running it at a higher speed.

This is a much shorter video that I shot after those two were taken and I changed the cut off values to 20 degrees away from the goal instead of 10. As you can see it performs much more poorly, due to that change but also because I was running this test at mostly higher speed. It was fun and interesting to see the change.

This is the code currently running on the Mega. If you would like to use it, in part or whole, feel free.

#include <Servo.h> //Steering servo setup
Servo steer;

#include "Wire.h"  //Crap for the compass
#include "I2Cdev.h"
#include "HMC5883L.h"
HMC5883L mag;
int16_t mx, my, mz;

float latdest = 49.1037056;  // Initial destionation waypoint coordiantes.
float londest = -117.5573271;

float heading = 0;  // HMC5883L heading
float tim = 0;  // GPS time
float lat = 0;  // GPS lattituede
float lon = 0;  // GPS longitude
float spd = 0;  // GPS speed
float hdg = 0;  // GPS heading
int latd = 0;  // GPS lattitude degrees
float latm = 0;  // GPS lattitude decimal minutes
int lond = 0;  // GPS longitude degrees
float lonm = 0;  // GPS longitude decimal minutes
float deltay = 0;  // Difference in degrees between next waypoint and current location, Y direction
float deltax = 0;  // Difference in degrees between next waypoint and current location, X direction
float deltaym = 0;  // Difference in meters between next waypoint and current location, Y direction
float deltaxm = 0;  // Difference in meters between next waypoint and current location, X direction
double dist = 0;  // Distance in meters between next waypoint and current location
float hdgrad = 0;  // Computed required heading in radians
float hdgdeg = 0;  // Computed required heading in degrees
int err = 0;  // Computed difference between current heading and required heading
int sv = 1500;  // Servo steering value in microseconds

void setup()
{
  Wire.begin();   //More compass crap
  mag.initialize();
  steer.attach(3,1000,2000);  //Steering servo crap
  steer.writeMicroseconds(1500); 
  Serial.begin(115200);  // Debugging over USB
  Serial1.begin(9600);  // Ultimate GPS is connected to serial 1
}

void loop()
{
  mag.getHeading(&mx, &my, &mz);  // Reading the compass.
    heading = atan2(my, mx);
    if(heading < 0)
      heading += 2 * M_PI;
      heading = heading * 180/M_PI;
 
  if (Serial1.available() > 62)  // Parsing and debugging the GPS data
  {
    Serial1.find("$GPRMC");
    tim = Serial1.parseFloat();
    lat = Serial1.parseFloat();
    lon = Serial1.parseFloat();
    spd = Serial1.parseFloat();
    hdg = Serial1.parseFloat();
    /*Serial.print("Time: ");
    Serial.print(tim, DEC);
    Serial.print(" Lat: ");
    Serial.print(lat, DEC);
    Serial.print(" Long: ");
    Serial.print(lon, DEC);
    Serial.print(" Speed: ");
    Serial.print(spd, DEC);
    Serial.print(" Heading: ");
    Serial.println(hdg, DEC);*/
   
    latd= lat/100;  // Converting the Degrees, decimal minutes given by the GPS into decimal degrees and also debugging over the serial port.
    latm = lat - latd*100;
    latm = latm/60;
    lat = latd + latm;   
    lond= lon/100;
    lonm = lon - lond*100;
    lonm = lonm/60;
    lon = lond + lonm;
    lon = 0 - lon;
    Serial.print(lat, DEC);
    Serial.print("  ");
    Serial.print(lon, DEC);
    Serial.print("  ");
   
    deltay = latdest - lat;  // Determining the change in degrees between next waypoint and current location
    deltax = londest - lon;
   
    deltaym = deltay*111211.71;  // Calculating the distance to next waypoint and debugging. (Calculated based on the lattitude I live on)(needs improvment)
    deltaym = abs(deltaym);
    deltaxm = deltax*73019.76;
    dist = sqrt(sq(deltaym)+sq(deltaxm));
    Serial.print(dist, DEC);
    Serial.print("  ");
   
    hdgrad = atan2(deltax,deltay);  // Calculating heading required to travel to next waypoint and debugging it.
    hdgdeg = hdgrad*180/3.14;
    if (hdgdeg < 0)
      hdgdeg = hdgdeg + 360;
    Serial.print(hdgdeg, DEC);
    Serial.print("  ");
    Serial.print(heading, DEC);
    Serial.print("\t");
   
    err = heading - hdgdeg;  // Calculating error between current heading and required heading and debugging.
    err = ((((err) % 360) + 540) % 360) - 180;
    Serial.print(err, DEC);
    Serial.print("  ");
  
    if(err > 10)
    {
      Serial.print("Left  ");
      steer.writeMicroseconds(1960);
    }
    else if(err < -10)
    {
      Serial.print("right  ");
      steer.writeMicroseconds(1040);
    }
    else
    {
      Serial.print("center  ");
      steer.writeMicroseconds(1500);
    }
    Serial.println();

    /*sv = map(err,-180,180,1040,1960);
    Serial.print(sv, DEC);
    Serial.print("  ");
    steer.writeMicroseconds(sv);*/
  }
  delay(10);
}

And thats the progress to date, next on my list of things to do is clean up the wiring, make it all tidy and not the rats nest that it is now, plus mount the reset switch. Thats for hardware, on the software side, there is a couple things. I need to make the steering code a little better. I will probably start with just a greater block of steering commands that set the steering less extreme when the error angle is less extreme, and then perhaps get some proportionality going using the map() function. Another big thing that needs to happen is I need to find a way to get my GPS to start spitting out at 5Hz. I don't really want to use Adafruit's library unless absoulutely necessary, but I need to figure that out. Nav side, I will get a distance calculating equation working that determines how far from the waypoint Raven is and trigger it to start driving towards the next waypoint when he reaches a certain distance away. I will worry about sensing and avoiding objects and tilt compensating the compass along with filtering the GPS data better at a later date. But for now not bad! He is driving towards waypoints by himself! Thats further than I have ever gotten with GPS guided vehicles before!

Tuesday, 4 November 2014

Raven

An update of yesterday's post, I have gotten some more work done on my GPS guided vehicle, which I have also decided to name Raven. I got those mounting holes drilled up for the hardware plate that I mentioned yesterday, and also mounted some electronics to it as well. That was a little interesting, I don't have any circuit board standoffs so I had to get creative. As is usually the case, I ended up building the required parts from modified lego, in this case some small 1x1 stud round "light" pieces. with a hole drilled thru the center. Here are two modified pieces next two unmodified ones:
And them on the screws and Mega:
In addition to the Mega, I also screwed down my ultimate GPS (with more lego spacers) and zip tied on a breadboard for connections. I would have screwed the breadboard on too but the mounting holes were in an inconvinent place. I also mounted my external GPS antenna and it's excessively long connector to the mounting plate:
A closeup of the Mega and the lego standoffs. They actually work very very well:
And the Ultimate GPS mount:
Because the GPS only has two mounting screws, I used a 1x4 and a 2x4 lego plate and drilled in the topmost stud of each so that the plate would support the GPS along it's whole length. I drilled two holes and zip tied the other end as well for security. Lastly, I made a hightened mount for the compass module to keep it far away from the motor and related interference. Of course also out of lego.
Note the GPS antenna on the left side of the picture. It is magnetic and the plate is steel of some sort, so it needs no mounting other than what it has built in. Here is a picture of it mounted on the Flux:
Admittedly, it looks a little goofy in this picture, but it does look better in real life, and besides, I am building a GPS guided vehicle, not a show truck. And it kind of reminds me of the look of a lot of the vehicles that competed in the DARPA Grand Challenge. Form follows function in my opinion. Anyway, no more software progress, this was a hardware night, and thats all for now.

Monday, 3 November 2014

Purpose built GPS guided vehicle beginnings. And also hello again :)

Well, it has been a long while since I last posted. In the meantime, I have graduated, worked at a summer camp for the summer, finally got my driver's licence and a car, got a full time job in the HVAC&R trade, moved out from home into my own place, and generally been busy with life :) Due to all of that, I haven't got to work on any robots for quite a while but now I am back. Anyway onto the good stuff :)

With some of the proceeds from the afforementioned job, I recently purchased this beast:
 An HPI Savage Flux 2350. Decent little unit, runs on two 2s LiPo packs wired in series, upgraded with a 2.4 GHz radio, has enough power to do a backflip from a standstill, that kind of thing. Also handily a 4x4 which is exccelent at running over rough terrain. No longer am I bound by cheap RC cars that have no proportional steering and throttle! In preperation for turning the Flux into a GPS guided vehicle, I have elected to mount a metal plate to the four posts that the plastic shells normally mount on, reinforced with some attatchment to the center roll bar. Remember I said that I worked in the HVAC&R trade? Well this little chunk of metal is from a filter rack for a new furnace that we installed and didn't need, so I saved it from the scrap metal pile.
 The black plastic piece is where the plate will mount on the truck. Their height can be adjusted in the mounts on the truck. I have not yet drilled the holes cause my drill is at work, but soon.

Lastly, I have worked on the software side a lot too, thats where I usually procrastonate, but Im getting the jump on this one and doing both at the same time. I broke out my Arduino Mega 2560 clone, Adafruit Ultimate GPS, and HMC5883L compass, wired them all up and started coding.
The compass is wired to the Mega`s I2C port, and the GPS is going to serial1. I have an external antenna wired to the GPS also, and is sitting on one of my windowsills for better reception. Currently I am using Jeff Rowberg`s EXCCELENT i2cdevlib library for the compass but not adafruit`s library for the GPS. I am very unskilled at programming and I could not for the life of me understand what was going on in most of the sketches, and also found that it didn`t like to parse at 5 or 10 Hz which I really need. I like to be able to understand everything in my code so even if it is inefficent, I would rather find a way that I can understand. Last year around this time I had succuss parsing the data from the GPS using the new Serial.parseFloat command and I have just been using that because it seems to work very well, and I can understand it. Here is the code running on my Mega right now, if you would like to try it, it should compile correctly and run provided you have Jeff`s library installed. Drop me a line if it doesn`t and you would like to try.

#include "Wire.h"  //Crap for the compass
#include "I2Cdev.h"
#include "HMC5883L.h"
HMC5883L mag;
int16_t mx, my, mz;

float latdest = 49.1020021;  // Initial destionation waypoint coordiantes.
float londest = -117.5518276;

void setup()
{
  Wire.begin();   //More compass crap
    mag.initialize();
 
  Serial.begin(115200);  // Debugging over USB
  Serial1.begin(9600);  // Ultimate GPS is connected to serial 1
}

void loop()
{
  mag.getHeading(&mx, &my, &mz);  // Reading and debugging the compass reading.
    /*Serial.print("mag:\t");
    Serial.print(mx); Serial.print("\t");
    Serial.print(my); Serial.print("\t");
    Serial.print(mz); Serial.print("\t");*/
    float heading = atan2(my, mx);
    if(heading < 0)
      heading += 2 * M_PI;
      heading = heading * 180/M_PI;
    /*Serial.print("heading:\t");
    Serial.println(heading);*/
 
  if (Serial1.available() > 62)  // This little chunck of code just parses the GPS data and sends it to the USB port for debugging.
  {
    Serial1.find("$GPRMC");
    float tim = Serial1.parseFloat();
    float lat = Serial1.parseFloat();
    float lon = Serial1.parseFloat();
    float spd = Serial1.parseFloat();
    float hdg = Serial1.parseFloat();
    /*Serial.print("Time: ");
    Serial.print(tim, DEC);
    Serial.print(" Lat: ");
    Serial.print(lat, DEC);
    Serial.print(" Long: ");
    Serial.print(lon, DEC);
    Serial.print(" Speed: ");
    Serial.print(spd, DEC);
    Serial.print(" Heading: ");
    Serial.println(hdg, DEC);*/
   
    int latd= lat/100;  // Converting the Degrees, decimal minutes given by the GPS into decimal degrees and also debugging over the serial port.
    float latm = lat - latd*100;
    latm = latm/60;
    lat = latd + latm;   
    int lond= lon/100;
    float lonm = lon - lond*100;
    lonm = lonm/60;
    lon = lond + lonm;
    lon = 0 - lon;
    Serial.print(lat, DEC);
    Serial.print("  ");
    Serial.print(lon, DEC);
    Serial.print("  ");
   
    float deltay = latdest - lat;  // Comparing current location to next waypoint and calculating heading needed to travel there. Also debugging it.
    float deltax = londest - lon;
    /*Serial.print(deltay, DEC);
    Serial.print("  ");
    Serial.print(deltax, DEC);
    Serial.print("  ");*/
    float hdgrad = atan2(deltax,deltay);
    /*Serial.print(hdgrad, DEC);
    Serial.print("  ");*/
    float hdgdeg = hdgrad*180/3.14;
    /*Serial.print(hdgdeg, DEC);
    Serial.print("  ");*/
    if (hdgdeg < 0)
      hdgdeg = hdgdeg + 360;
    Serial.print(hdgdeg, DEC);
    Serial.print("  ");
    Serial.print(heading, DEC);
    Serial.print("\t");
   
    int err = heading - hdgdeg;  // Calculating error between headings and debugging.
    err = ((((err) % 360) + 540) % 360) - 180;
    Serial.print(err, DEC);
    Serial.print("  ");
   
    if(err > 5)
    {
      Serial.print("Left  ");
    }
    else if(err < -5)
    {
      Serial.print("right  ");
    }
    else
    {
      Serial.print("center  ");
    }
   
    Serial.println();
  }
  delay(1);
}

Up near the top are the latitude and longitude of the waypoint you want to go to. I use google maps to find my waypoints. (The waypoint set there is not where I live, by the way) Change those to whatever you like, and this will start spitting out your current latitude, longitude, heading you need to travel to get to your destinaion, current heading given by the compass, difference between the two, and weather you should turn left, right, or stay centered out of the serial port at 115200 baud. If you uncomment out all that other stuff, it will spit a bunch of other data from the intermediate steps too amongst other things. It seems to be running well, and at some point I need to mount my GPS and compass a little more securely and take the assembly with my laptop outside to pretend to be a GPS guided vehicle and see how it does more thouroghly. Anyway its a start! Ill post updates as I make progress.

Tuesday, 10 June 2014

Lego Web Bot

I built this little guy a while ago and just havn't had a chance to post it yet. Its a rover built using Lego mindstorms that has a place for an iPod touch to be put inside, and that iPod touch connects to a web site hosted by my laptop when I want to run this thing, and another iPod, or phone or computer or whatever connects to another webpage served by the laptop that has an input page on it.

The iPod in the robot is a 4th gen iPod touch with a tinkerbrick case put on it (of course I have a lego case on my iPod :))
 Here are a couple pictures of the rover, showing the general structure and how the iPod is mounted inside:
 The rover uses a light sensor to react to the webpage that the iPod is connected to changing colour; you can see the light sensor sitting between the motors in this pic.
 iPod placed inside:
 And locked down. Note the camera is visible for future use :)




 Both the lock button on the iPod and the USB port on the NXT brick are acessable from the top when the cover is lifted:
 And the NXT brick's charge port is avalible from the bottom:
This is a video showing an early version of the webpages that are served by the computer
And the final version of the webpage:
Once you have watched those, it will be a bit easier to explain what goes on, so far as I know anyway. My friend actually built the webpage and javascript that runs this whole thing, but here is how I understand that it works: The laptop uses node.js to serve two webpages over the local network, one an input page that has buttons that can be clicked with a mouse, or a finger on a touchscreen, as well as the wasd and arrow keys on the keyboard, and uses those inputs *insert internet server black magic that I have no idea what goes on here* to change the colour of another webpage in real time. So I simply set up my laptop, start the node.js server from a command prompt, and direct the iPods to the IP address of the laptop, plus /input or /output for the respective pages and go to town. It feels magical to me. Anyway, here is the video that you really want to see, the rover actually moving. Note that my camera is getting really really old, and the delays that you see between touching the button on the iPod, the rover moving, and the sound are all due to the camera. In reality, the control is almost instantanious.

Wednesday, 16 April 2014

The Window is finished! (Well, kinda)

On Friday night of last week, I came home to a nice box of goodies sitting on the table, my KK2.1.5 board, some connectors and a small prop balance stand, and after working a little bit on Saturday, Sunday and Monday, I ended up with a functioning octocopter. Here are a couple of pictures of it complete:
 Upside down:
 A closeup of the center:
 And a closeup of the camera mount:
I soldered up a big nasty wiring harness out of 14 gauge wire running up the arms to supply power to the two motors per arm, and some 12 gauge wire running to two XT60 connecters each to allow for a total of 4 batteries to be plugged in at any time. I mounted the electronics and batteries in an old Tupperware container which is screwed to the middle of the frame and which has a bunch of holes drilled thru it for running all the wires, and I mounted the KK board in its foam packaging as recommended by the hobbyking manual; this serves to protect the board, and isolate it from vibrations transfered thru the frame. I also had to extend the ESC wires using a bunch of extentions, splitters and ugly hacking, but it all connects up and works well. As you can see, at the moment I only have two batteries mounted, owing to the fact that I only have 3 un-bulgy LiPo batteries that I trust not to catch fire or explode, but there is room for two more in the container, I only need to drill some more holes for the wires to exit. To fly properly, this thing actually needs four 20C 2.2Ah batteries, not the two that I am currently running because each motor can draw a maximum of 18A of current, and I have 8 of them, roughly equaling 160A total current draw with all the motors maxed out, and right now with my two batteries, they can only deliver 2.2Ah times 20C, a little over 80A of current. Nonetheless, it still does fly, but the flight time is a disapointing 5 or so minutes, and I am not getting full lift (which I calculated to be 9kg with the motors running full out) While I am on the subject of lift and weight, the copter with no batteries weighs approximately 2.6kg, and four of the batteries I am using weigh together about .7kg, so once I get enough to actually fly with 4, the total weight of the octocopter will be less than 3.5kg, leaving quite a bit of payload capacity.
The camera is an Oregon Scientific "ATC mini" action cam that I got on amazon.com for $40; I used its "tripod adapter"mount and threaded a 1/4in bolt thru some pipe and a tee with half cut off, hose clamped to the frame as a mount. Its simple and sturdy, but transfers a lot of vibration to the camera, and that makes the footage, well, less than perfect. Lastly, I used some red, green, and black electrical tape to indicate orientation, the black stripes is the back side, green is right (starboard) and red is left (port). I have not yet played with the PI values that are tuneable on the KK board, and so while usable, the octocopter is not quite as stable as it should be. Still, the fact that it flies pretty good with stock settings is pretty awesome. I expect it to get much more stable when I properly tweak the PI settings and perhaps the altitude dampining.

So on to what everyone really cares about, the videos of it in action! The first two are good if you get bored quickly, they are short and you see it reletavely close up and doing cool stuff. The middle two are if you want to see a bit of a longer video, and were actually taken first, but they get a little boring. The last two are also slightly boring, they are the footage shot by the ATC mini mounted on the octocopter. Enjoy.
So that is all for now, next up will be getting some more batteries so it can actually get some decent flight time, and an underslung pan/tilt bracket for the camera with some landing gear to keep it out of the ground, and video feed back to the ground as well as a seperate tx/rx combo for someone else to film while I fly, and perhaps after that, AN AIRBORNE PAINTBALL GUN! awwwww yeahhhhhhh. A project is never really finished, but at least the beginning is finished :)

Tuesday, 8 April 2014

PKP (it's alive again)

In my last post about PK, I had completed the motor controller, but had not yet tested it, so I started off by getting out my UNO and writing some test control code for the motor controller:
I got the code all written up, and gave it a test with two multimeters hooked up to the outputs (Unfortunately this video is really dark, it looked lighter when I was taking it)
video
And hooked it all up and gave it a try (The motor directions are reversed in this video, I fixed that shortly after)
video
The code running on the UNO during all of these videos is as follows:

#define in1 3
#define pwm1 9
#define f1 5
#define b1 7
#define in2 4
#define pwm2 10
#define f2 6
#define b2 8
void setup()
{
  // Channel 1:
  pinMode(in1,INPUT);
  pinMode(pwm1,OUTPUT);
  pinMode(f1,OUTPUT);
  pinMode(b1,OUTPUT);
  // Channel 2:
  pinMode(in2,INPUT);
  pinMode(pwm2,OUTPUT);
  pinMode(f2,OUTPUT);
  pinMode(b2,OUTPUT);
  Serial.begin(9600);
}

void loop()
{
 int p1=pulseIn(in1,HIGH);
 int p2=pulseIn(in2,HIGH);
 int p3=p1+p2-1500;
 int p4=p1-p2+1500;
 p1 = constrain(p3, 1200, 1800);
 p2 = constrain(p4, 1200, 1800);
//============= Channel 1 =============
 if(p1 > 1530)
 {
   int s1=map(p1, 1530, 1800, 255, 0);
   analogWrite(pwm1,s1);
   digitalWrite(b1,LOW);
   digitalWrite(f1,HIGH);
 }
 else if(p1 < 1470)
 {
  int s1=map(p1, 1470, 1200, 255, 0);
  analogWrite(pwm1,s1);
  digitalWrite(f1,LOW);
  digitalWrite(b1,HIGH);
 }
 else
 {
  analogWrite(pwm1,255);
  digitalWrite(b1,LOW);
  digitalWrite(f1,LOW);
 }
//============ Channel 2 ==============
 if(p2 > 1530)
 {
   int s2=map(p2, 1530, 1800, 255, 0);
   analogWrite(pwm2,s2);
   digitalWrite(b2,LOW);
   digitalWrite(f2,HIGH);
 }
 else if(p2 < 1470)
 {
  int s2=map(p2, 1470, 1200, 255, 0);
  analogWrite(pwm2,s2);
  digitalWrite(f2,LOW);
  digitalWrite(b2,HIGH);
 }
 else
 {
  analogWrite(pwm2,255);
  digitalWrite(b2,LOW);
  digitalWrite(f2,LOW);
 }
//====================================
delay(15);
}

For my actual outdoor run, in order to get some footage, I made up a quick little camera bracket for my transmitter, I call it the "forever alone camera mount"


And I also made a little mount for my action cam to mount on PK in place of the paintball gun, since I do not yet have the necessary parts to make it opperational yet.
And with all that set up and working, I went out and drove it around my driveway for a bit (woohoo, my first legitimate run :)) The first video is me filming, and the second is from PK's camera
Well, it works. After I finished driving it around, I stuck it in an outdoor shead, here are a couple op pics of the various parts, and the whole thing as it sits:
Motor controller:
 Arduino:
 The whole backside:
 And from the front,
 Top,
 And side:
Anyway, it runs, which brings a smile to my face :) Onward and upward!!

Monday, 31 March 2014

More Window

Just a little work done, but besides the electronics/battery box in the middle that I have yet to mount, this will probably be all the progress I make untill my KK2.1.5 board comes in the mail. Starting to look like an Octocopter...