Friday, April 25, 2014

So I have received a confirmation email of my Atmel chips being shipped. I should get them sometime next week.  In the meantime I have downloaded the AtmelStudio app that is free from Atmels site.  I think I am going to use this to break the code down for the embedded chips.  It is based on Visual Studio which I have used in C++ classes before so its not much of a jump.  It also has an Arduino plugin extension that I may start using to do some further testing with the arduino mega before we fully go to the ATtiny chips.  Jimmy is already in the process of laying out the new board for the embedded chips.  I am also researching the best way to load the chips.  It will be a little bit of a pain to have to manually connect each one to an AVR loader like Jimmy's DragonAVR or one of our UNOs.   If we include a switchable USB onboard AVR loader, maybe Ill just order a chip like the USBasp loaders and add that circuit to the board.  Im sure that there will be a use for it to change values like distances from the wall to react at a later date anyway.  
Well OSH park made some really nice PCBs for our IEEE robot team this year, I guess once we get a working model on the copper milled board we can produce at the school we will order a few of those boards too.
Code update.   The one I posted for demonstration apparently hid a few items when I used the HTML to do the pretty print syntax highlighting stuff on it (aka put it into the dark box and highlighted the codes different pieces).  So don't go selecting and pasting it into your stuff.  Oh the failures to compile will be beautiful.  Hate mail filter engaged.  Not like anyone comments on this blog anyway.  Well there are a few more changes I plan on making to the code before it goes totally embedded.  Ill try to share them with you.
Gyro's?  I think that adding a Gyro control from the embedded system board to drive the servos that are leveling the sensors has got to be done.  This is the only way I can truly make this an addon to any quad copter.  That is my end goal anyway.  No matter your flight controller setup, I want to be able to add this onto it and give your quad copter a small degree of wall avoidance.  Yeah if your silly enough to make it go full pitch forward into the wall, there isn't much anythin can do to stop you from crashing into the wall within a certain range.
Well you guys have fun.  Im out for the night, prob taking the weekend off also, its been a rather full week so far, 2 presentations, one innovative design competition 1st place win, etc. 

Thursday, April 24, 2014

The next steps. Well Since my semester is coming to a close and the Quad is working as intended I have decided to continue the process further. My next step is to start designing an embedded system to perform the functions that the Arduino Mega is currently doing. The reasons behind turning it into an embedded system is that I can break the different processes out onto multiple processors and still reduce the energy consumption while speeding the responsiveness of the system up. Too that end I have ordered a few ATTINY84-20PU chips to test with and requested some samples of some other AVR chips. My plan is to design a board with onboard gyro stabilization for the servos that keep the ultrasonic servos parallel to the ground, control the ultrasonic sensors with dedicated AVR processors, read in the user control on another AVR, then do the overide signals on another AVR before sending the commands to the flight controller. What will this accomplish? Well right now there is a roughly 1/4 second delay between the user sending commands to the quad copter and the quad copter responding. The reason for this is the ultrasonic readings. Having a dedicated processor for the ultrasonic sensors removes that delay. Also, I want to use the Arduino for what it is intended for, early stages of prototyping. I feel it is time to move away from the Arduino and begin fine tuning the process. It will also allow me to use more sensors to cover more area around the quad. I think once I have tested the viability of breaking everything down into different AVRs I will add 4 more sensors to the quad basically at 45 degrees off the existing. The problem there will be the EMI and noise from the motors because the ultrasonic sensors will have to be mounted very near them. I am still massaging the code daily and will post any improvements here until I move to the embedded stage of the process. At that point I feel it is only suitable to either start a new blog or create some sort of webpage to show off my progress. As always, thanks for reading my thoughts here.

Wednesday, April 23, 2014

Adding the full code for demonstration purposes


#include 
#include 

/*
*Version 1.10b
** DISCLAIMER!!!!  This is a work in progress.  If you decide that adding this
** to you own quad copter, please do so at your own risk.  I am not in any way shape
** or form responsible for your silliness.
** While this is listed as a beta, its really between alpha and beta realities, meaning
** If you look hard at it its alpha, if you look away its beta.  Also remember:
** ---Alpha. Software undergoes alpha testing as a first step in getting user feedback. Alpha is Latin for "doesn't work."
** ---Beta. Software undergoes beta testing shortly before it's released. Beta is Latin for "still doesn't work.
** Copyrights???  This is open source man.  Don't make money off of it at my expense
** enjoy.
** This code is intended to be used in conjunction with an Arduino Mega2560 to interpret
** ultrasonic readings and limit or override user RC control on a quadcopter.
** It is flexible in that it doesnt matter what kind of flight controller you are
** using.  Tested with APM 2.5, APM 2.6, MultiWii 328p and Multiwii MegaPirate.
** If it uses a standard RF controller it will use the same type of control signal
** and this only mimics user control when seen from the flight controllers point of view.
** As stated on my blog, Understand that this is heavily influenced by
** Duane's 8 channel RCArduino work at
** http://rcarduino.blogspot.co.uk/2012/04/how-to-read-multiple-rc-channels-draft.html
*/

#define PITCH_CHANNEL_IN 2  // attach from receiver elevator channel for pitch control (Mega2560 interrupt 0)
#define ROLL_CHANNEL_IN 3   // attach from receiver ailerons channel for roll control (Mega interrupt 1)

#define PITCH_CHANNEL_OUT 12  // attach to flight controller elevator pin
#define ROLL_CHANNEL_OUT 13  // attach to flight controller aileron pin

Servo servoChannel1;  // setup servo channel for pwm output
Servo servoChannel2;  // setup servo channel for pwm output

#define PITCH_FLAG 1  // flag to determine if new input is detected on pitch channel
#define ROLL_FLAG 2   // flag to determine if new input is detected on roll channel

volatile uint32_t SharedNewFlag;  // global shared flag for determining if any flag has been triggered

volatile uint32_t PITCH_IN_SHARED;  // global shared flag for pitch input trigger
volatile uint32_t ROLL_IN_SHARED;   // global shared flag for roll input trigger

#define SONAR_NUM       4 // Number of sonar sensors
#define MAX_DISTANCE  179 // Max distance in cm
#define PING_INTERVAL 33 // Milliseconds between sensor pings (29ms is about the min to avoid cross-sensor echo).

unsigned long pingTimer[SONAR_NUM];
unsigned int cm[SONAR_NUM];
uint8_t currentSensor = 0;

NewPing sonar[SONAR_NUM] = { // NewPing v1.5 library and examples used here.
 // Visit https://code.google.com/p/arduino-new-ping/ for more info
 NewPing(4, 5, MAX_DISTANCE),
 NewPing(6, 7, MAX_DISTANCE),
 NewPing(8, 9, MAX_DISTANCE),
 NewPing(10, 11, MAX_DISTANCE)
};

void setup()
{ Serial.begin(115200);
  servoChannel1.attach(PITCH_CHANNEL_OUT);// attach the servo channel 1 to pitch out pin
 servoChannel2.attach(ROLL_CHANNEL_OUT); // attach the servo channel 2 to roll out pin

 pingTimer[0] = millis() + 75;           // First ping starts at 75ms
 for (uint8_t i = 1; i < SONAR_NUM; i++) // Set the starting time for each sensor.
 pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL;

 attachInterrupt(0, calcPitch, CHANGE); // attach interrupt to the in pins for pass through
 attachInterrupt(1, calcRoll, CHANGE);  // attach interrupt to the in pins for pass through
void loop()
 {
  // static local copies to be used as output and calculation
  static uint32_t PITCH_IN_LOCAL;
  static uint32_t ROLL_IN_LOCAL;
  // local update flag
  static uint32_t LocalNewFlag;
  // check if global flag has been triggered then turn off interrupts until output has been completed
  if (SharedNewFlag)
  {
   noInterrupts(); // turn off hardware interrupts
   LocalNewFlag = SharedNewFlag; // copy the shared flag status into the local flag to allow the shared one to be reset for the next input
   if (LocalNewFlag & PITCH_FLAG)
   // if the local flag is true (greater than 0) and the pitch flag is true update the local copy of the user input
   {
    PITCH_IN_LOCAL = PITCH_IN_SHARED; // set local copy of input to the global shared value
   }

   if (LocalNewFlag & ROLL_FLAG) // same as before local flag and roll flag must be true
   {
    ROLL_IN_LOCAL = ROLL_IN_SHARED;  // set local copy of input to the global shared value
   }

   SharedNewFlag = 0;  // reset global update flag to zero for next loop
   interrupts();
  }

  for (uint8_t i = 0; i < SONAR_NUM; i++)
  { // Loop through all the sensors.
   if (millis() >= pingTimer[i])
   {       // Is it this sensor's time to ping?
    pingTimer[i] += PING_INTERVAL * SONAR_NUM;  // Set next time this sensor will be pinged.
    sonar[currentSensor].timer_stop();          // Make sure previous timer is cancelled.
    currentSensor = i;                          // Sensor being accessed.
    cm[currentSensor] = MAX_DISTANCE;           // Make distance MAX_DISTANCE if there's no echo.
    sonar[currentSensor].ping_timer(echoCheck); // Do the ping (interrupt will call echoCheck).
   }
  }
  int distancef = map(cm[0], 0, 180, 1, 4);
  int distanceb = map(cm[1], 0, 180, 1, 4);
  int distancer = map(cm[2], 0, 180, 1, 4);
  int distancel = map(cm[3], 0, 180, 1, 4);
  
  if (distancef <= distanceb) // checks to see which distance is closer that involves this channel
  {
   switch (distancef)
   {
   case 1:
    if (LocalNewFlag & PITCH_FLAG)
    {
     if (PITCH_IN_LOCAL > 1700)
     {
      servoChannel1.writeMicroseconds(PITCH_IN_LOCAL);
     }
    }
    else
    {
     servoChannel1.writeMicroseconds(1700);
    }
    break;
   case 2:
    if (LocalNewFlag & PITCH_FLAG)
    {
     if (PITCH_IN_LOCAL > 1500)
     {
      servoChannel1.writeMicroseconds(PITCH_IN_LOCAL); //  no user input over 1500
     }
    }
    else
    {
     servoChannel1.writeMicroseconds(1500); 
    }    
    break;
   default:
    if (LocalNewFlag & PITCH_FLAG)
    {
     servoChannel1.writeMicroseconds(PITCH_IN_LOCAL);
    }
   }
  }
  else
  {
   switch (distanceb)
   {
   case 1:
    if (LocalNewFlag & PITCH_FLAG)
    {
     if(PITCH_IN_LOCAL < 1300)
     {
      servoChannel1.writeMicroseconds(PITCH_IN_LOCAL); // back away from the wall
     }
    }
    else
    {
     servoChannel1.writeMicroseconds(1300);
    }
    break;
   case 2:
    if (LocalNewFlag & PITCH_FLAG)
    {
     if(PITCH_IN_LOCAL < 1500)
     {
      servoChannel1.writeMicroseconds(PITCH_IN_LOCAL); //  no user input over 1500
     }
    }
    else
    {
     servoChannel1.writeMicroseconds(1500);
    }
    break;
   default: 
    if (LocalNewFlag & PITCH_FLAG)
    {
     servoChannel1.writeMicroseconds(PITCH_IN_LOCAL);
    }
   }
  }
  if(distancer <= distancel)
  {
   switch (distancer)
   {
   case 1:
    if(LocalNewFlag & ROLL_FLAG)
    {
     if(ROLL_IN_LOCAL < 1300)
     {
      servoChannel2.writeMicroseconds(ROLL_IN_LOCAL); // back away from the wall
     }
    }
    else
    {
     servoChannel2.writeMicroseconds(1300);
    }
    break;
   case 2:
    if(LocalNewFlag & ROLL_FLAG)
    {
     if(ROLL_IN_LOCAL < 1500)
     {
      servoChannel2.writeMicroseconds(ROLL_IN_LOCAL);
     }
    }
    else
    {
     servoChannel2.writeMicroseconds(1500);
    }
    break;
   default:
    if(LocalNewFlag & ROLL_FLAG)
    {
     servoChannel2.writeMicroseconds(ROLL_IN_LOCAL);
    }
   }
  }
  else
  {
   switch (distancel)
   {
   case 1:
    if(LocalNewFlag & ROLL_FLAG)
    {
     if(ROLL_IN_LOCAL > 1700)
     {
      servoChannel2.writeMicroseconds(ROLL_IN_LOCAL); // back away from the wall
     }
    }
    else
    {
     servoChannel2.writeMicroseconds(1700);
    }
    break;
   case 2:
    if(LocalNewFlag & ROLL_FLAG)
    {
     if(ROLL_IN_LOCAL > 1500)
     {
      servoChannel2.writeMicroseconds(ROLL_IN_LOCAL);
     }
    }
    else
    {
     servoChannel2.writeMicroseconds(1500);
    }
    break;
   default:
    if(LocalNewFlag & ROLL_FLAG)
    {
     servoChannel2.writeMicroseconds(ROLL_IN_LOCAL);
    }
   }
  }

  LocalNewFlag = 0; // reset local flag to zero for next update
 }
 // calculate the PWM pulse lengths and flip flags
void calcPitch()
 {
  static uint32_t ulStart;

  if(digitalRead(PITCH_CHANNEL_IN))
  {
   ulStart = micros();
  }
  else
  {
   PITCH_IN_SHARED = (uint32_t)(micros() - ulStart);
   SharedNewFlag |= PITCH_FLAG;
  }
 }
void calcRoll()
 {
  static uint32_t ulStart;

  if(digitalRead(ROLL_CHANNEL_IN))
  {
   ulStart = micros();
  }
  else
  {
   ROLL_IN_SHARED = (uint32_t)(micros() - ulStart);
   SharedNewFlag |= ROLL_FLAG;
  }
 }
void echoCheck() { // If ping received, set the sensor distance to array.
  if (sonar[currentSensor].check_timer())
  cm[currentSensor] = sonar[currentSensor].ping_result / US_ROUNDTRIP_CM;
 }

Monday, April 21, 2014

Testing is going well.  I am posting the current code which is purely wall avoidance.  I am thinking about extending the range of ultrasonic detection to 4 ft and adding an event at that range for non movement towards the wall.  For now this is what we are going with for our progress review presentation today.

first the current version
one event, triggered at the two ft range.
Wall avoidance one event 2 ft pull away

The next untested version adding another event back in
two events, triggered at two ft and four ft ranges
Wall avoidance two events

Reducing the number of events speeds up the responsiveness, so we are attempting a happy medium with the two events version.  something that will let you get close to the wall.

Wednesday, April 16, 2014

So, some loose solder points and an inexplicable loss of settings on the flight controller caused me to question my code.  Result, a partial redesign of the logic which after testing actually increased the responsiveness by quite a factor.  After going through the code trying to flush out what may have been causing the quad to freak out.  I was told by several people that it must be my code messing up.  Well guess what, it wasn't my code.  BUT WAIT, I did go through redesigning of the code and it ... improved it?
OK long story short.  With the help of a classmate I realized that what I was attempting to do with the different levels of user limitations was not needed as much as I first thought.  If someone is trying to run the thing into the wall there isn't much that can be done to stop it.  So assuming the user isn't a complete moron and they are not trying to hit the wall, I removed the various levels of limitations and went for one trigger event.  Roughly 2 ft away from the wall if you are not trying to pull away, the Arduino Mega will do it for you.  This reduced the code down to around 100 ish lines of code (180 with all the comments).
What does this do?
First the ultrasonic sensors can be sped up.  The max range they will look for was reduced so less time waiting in a timed interrupt cycle.  This allowed me to reduce the time between each sensor firing by half.  The ultrasonic sensors are advertised to accurately range up to somewhere around 20 ft.  Under testing, at best I was getting some accurate readings at 12 ft and about 75% accuracy at 10 ft and beyond.  The best ranges were less than 6 ft which were about 95% or better accuracy.  So I am disregarding anything less than 70 cm (roughly 2 1/4 ft).  I will probably increase this range a bit.  Maybe disregard over 3.5 ft and adjust under 3 ft.  So the loop spends about 20% of the time it used to spend in timed ISRs but I doubled the amount that they do.  Still that's only 40% of the time it was in them before.   I could reduce the number of pings back to what we had before to speed the main loop up further if needed.  I don't think its needed though.
Also I have drastically reduced those nasty nested if else statements.  Since we only have the one trigger event now I only need to check the sensors and do something other than pass through if the event is triggered.

What does this mean.  The quad is very quick.  There is no observable response lag.

I did bring my laptop home which has the only copy of the most current code, but its late and I will try to upload it tomorrow for anyone to look at.

Future:  Possible additions to the project for after I present it to the school are in the research phase.
Breaking the code down into different chucks (e.g., ultrasonic reads and trigger,  RF PWM read in, on-board gyros for sensor leveling independent of the flight controller)  This will allow me to load the different chunks onto individual PIC chips and create a much lighter and faster embedded system.  (my goal is to make an attachment for multiple configurations of multi-rotor flight vehicles).
Additional sensors to provide a better 360 degree coverage for wall avoidance.
These possible future changes will be added to the blog if/when I do them.  but for now if anyone knows a good PIC chip I should be looking into let me know.

Well goodnight whoever may be wasting your time following my project updates.

Monday, April 14, 2014

Breakthrough!!
After getting rather frustrated by the code not operating as I thought it should.
Well I spent a good hour just line by line inspecting the code and making sure I totally understand what I was asking it to do.  I removed about 120 lines of code that was essentially redundant, which also compounded the if else statements making them rather complicated.  So here it is in a working format.  Some very small things need some tweaks, and I am still researching switch cases to lay the code out better.
So check it out, working wall avoidance on pitch axis and roll axis.  I am only using 4 ultrasonic sensors to prove the concept.

Version 1.06 Beta working
So the drift factor is fixed but now I have a lovely error that I cannot figure out.  Once the distances trigger for danger area, it no longer allows any user control, even backing away from the wall.  Right now you could put the thing in a 10'X10' room it will automatically find the middle but that is not what we are after.
Most recent code:

1.05 beta

Wednesday, April 9, 2014

Second and third flight tests today.  We are almost there people.  Most of the wall avoidance did perform as expected.  I think I saw something in the logic of the code though so I tested that possible failure out later.  I see that the code as it was written is not doing anything with the sensor data if there is no updated input from the user.  I was afraid of that but assumed, yeah bad thing, that the Transmitter constantly updated the receiver whether the operator changed something or not.  This is not the case.

I was able to run the quad into the wall by letting it drift.  In other words, I started it moving towards the wall and then stopped giving it commands.  What occured was that the quad went to level out, but because we were testing in a hallway the momentum and eddy currents from the props let the quad drift towards the wall allowing the quad to hit the wall.  Never fear, I think I have a solution for this.
The way I had the code written before it only updated the data sent to the flight controller if it received input from the transmitter.  I have rearranged the if else statements to be driven more so by the ultrasonic sensors.  So first it checks to see which distance is closer in each axis, then it checks for the update flag and updates the flight controller.  if no update is seen then in the 45 cm range it still backs away from the wall and at the 60 cm range it tells the flight controller to stay put unless the TX/RX has an update that tells it to move away.

Posting version 1.04beta below.  More testing tomorrow.

text version of 1.04 beta


Monday, April 7, 2014

First Flight test today went... well not so good.  First off I found an issue with the APM 2.5 where the pitch channel is basically inverted.  If you move the stick up on your hand station to simulate pitch forward it increases the PWM frequency to between 1500 to 2000 milliseconds, and the radio calibration on the mission planner software for the APM shows this as correct.  The problem lies in the Arducopter firmware.  It registers 1500 down to 1000 as pitch down.  This is the opposite of what the hand station defaults to.  The solution was a minor rewrite of my code to account for this and reversing the channel in the hand station.  Problem one solved.
Problem two.  I did not have enough female to female extension jumpers to connect the ultrasonic's 4 wires to the Mega and I modified some female to male connectors.  This was not making a complete connection with the Mega board.  With the vibration that the Quad suffers in flight these connections became , well ... non connections.  If the sensors lose connection I get no distance data and no override or control happens to slow an approach towards a wall and no auto back away.  What does this mean, well for me it meant 3 broken props from 2 wall strikes while hovering 1 to 2 inches off of the ground.  Problem 2 will need attention before the next flight.
Well that's the bad news, now for the good news.  The quad avoided the wall in one direction perfectly.  The servos are also working perfectly to keep the ultrasonic sensors horizontal to the ground.  Once I get the hardware connection problems fixed we will try another flight test.  If everything goes well, the quad will actually be ready for demonstration by this weekend.

I updated the link for the current code on my dropbox account.

Wall avoidance 103beta  

Sunday, April 6, 2014

Weekend update.

So the Quad is now about 90% assembled.  I wanted to do some testing today, but ran out of time.  I am posting some pictures of what it looks like right now.  When this is all tested and working I will start a new blog with everything a little more organized.  I know this blog isn't really frequented by people outside my circles, but I wanted it to be open so anyone who may be interested.  For now, enjoy/hate my quads current state.  Understand this is not a mass produced store bought quad, all parts were either fabricated by us or ordered separately and assembled by either Jimmy or myself.
Note the ultrasonic mounts on all four cross beams.  They have servos attached that will change the pitch of the sensor to keep them horizontal during flight.


Im using a sensor sheild with the arduino Mega2560 so I can easily distribute power among the sensors.

My silly hinged double decker thing I made to get to the flight controller.


Those black parts were printed on the makerbot printer at the lowest resolution.  You can actually see the different layers of plastic.



yep thats flex tubing conduit you can buy from just about any auto parts place or hardware store, relly wanted the larger ones to be black though, couldn't find any.


Well for now that will have to do.  Tomorrow I will show our progress to our professor before continuing work on it.  Hopefully this week I can see if my code is going to save or destroy this quad.  

Wednesday, April 2, 2014

A quick update on the project.  We are printing the ultrasonic mounts today and hope to have the servo mounts printed tomorrow.  A quick drawing of the proposed quad copter is below:




Below is our first draft proposal for the project

The 3D models that we are printing
Servo mount to tilt the sensors
corner mount for the rods

While these presentations and proposal draft have changed, they show some of the process we have gone through to get the project to where it is now.

Some of our previous test videos with the quad copter:
 (we will be updating this channel with the new videos)
youtube channel of test flights

coming soon videos:
3D printing parts
assembly
outdoor test flights
indoor test flights

Tuesday, April 1, 2014

Well I found some more silly errors with my code, updated the link.  Just had my pins declared wrong and my array calls incorrect.
Meanwhile today the schools Maker bot 3d printer was being... well rather difficult is not a strong enough word.  Needless to say some foul language crossed my lips while in the heat of battle today with it.
What I learned from the maker bot today:
black ABS plastic + default settings + rafts = part moving around the build plate with the nozzle.  Too much fun.
Anyway we changed the build plate temperature to 115 C and slowed the printing movement down since the Maker Bot is on a table that allows it to shake a bit when moving between extrusions.
Tomorrow we will try 120 C on the build plate and see if that remedies my parts coming "unstuck from the build plate" issue.  We did get the last two corner mounts printed and now we will be working on the ultrasonic and servo mounts.  Servos for tilting the ultrasonic sensors with the Quad copter to keep them perpendicular to the walls.  It all makes sense, seriously.

I am thinking of trying out switch cases to replace some of the if else statements in the code.  Not sure how that will work since I would be trying to switch ranges.  I think something like:
switch(distancef)
{
case 1 ... 45:
do stuff
break;
}

yeah yeah I'm typing this from my vast knowledge in my brain and there are probably some syntax errors there.  Don't judge me I'm learning lol.

Back to the Quad copter.  Tomorrow I will post some drawings of the quad.  Those files are at the school on my laptop in my office so I don't have access to them right now.  Jimmy also finished redesigning the servo and ultrasonic mounts.  just go to one of his thingiverse posts listed a couple of blog posts back to see his work.

So, if we get all the parts printed within the new couple of days, and we get time to test the code I will be posting videos.  My current deadline for something proto typed and working is before April 24th 2014 for a presentation to the Industrial Advisory Committee.  So definitely look for updates between now and then.