Saturday, June 7, 2014

Long time no update.  Progress on the project is on hold until I find a job.  Yeah gotta pay bills and stuff before playing.  I have still been researching ways to proceed though.  So I am asking for a couple more weeks before I update you again.  Once again let me reiterate that I am by no means abandoning this project.  It was still in its infancy when I put it on pause for real life stuff.
What changes to expect first:
New proposal
New initial circuit layout
New device sketches
etc.
Starting a new blog and will post the link here when I get it going.

Friday, May 2, 2014

So its been a week since I last updated this. So just to update anyone who does read this, I am in the middle of finals at the university so the updates will be slow for a couple of weeks.  Meanwhile, I got my ATtiny chips in and we are in the process of designing the circuit.  I think we have agreed on ordering a gyro sensor and a few more chips to make this a true addon system.  The idea is to take in the sensor data from the gyro to control the tilt of the distance sensors to keep them horizontal.  We were doing this by pulling that data and controlling the servos like they were camera gimbal servos.  But this requires a flight controller that has that ability to do.  Moving that to the embedded circuit will make things much better.  I am also toying with an idea to incorporate a different type of design to include a full frame.  Something that would allow someone to either take the addon system to their quad or they could build a new quad using the "smart" frame.  Just an idea.  I want to also look at a way to power the wall avoidance separately.  More information on this later, first I need a working prototype of the system to measure power requirements to see if it can be done effectively.
Embedded chips usage.  We hope to control 2 to 4 sensors on each ATtiny and output pins as high determined on the event triggered.  basically what I am thinking is assigning a 4 digit binary number to events.  so say the front sensor triggers at 2 feet then the four pins would be written as 0010, if it was 4 feet then they would be 0001.  Likewise the rear sensor would give 1110 for 2 and 1101 for 4.  I could add in the right left sensors to be 1010 right 2ft mark, 0110 left 2 ft mark.  The ATtiny chips I am using for this have 12 I/O pins.  If I rewire the ultrasonic sensors to have one shared pin for trigger and echo then I would need one pin per sensor, then 4 pins for output.  Thats only 8 pins used for pitch axis and roll axis.  That leaves me 4 pins available for maybe IR sensors in each direction for better detection of obstacles like sound absorbing humans.
Well back to studying for my finals.  Wish me luck

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.

Monday, March 31, 2014

Ok here is the same code made a little more presentable.  Thanks Notepad++.

Wall Avoidance attachment code version 1.02 beta

I have enabled all the sensors now and serial output for the pitch channel(front and rear sensors.  This code is still being tested.  Now to make those parts and assemble the quad for testing.

After this weekend I will post links to some success videos.  Fingers crossed.
Ok I think I have it working now, for the most part.  I am still refining the ultrasonic results but it does perform what I want it to.
I am adding the TXT file of my code so I can work on it at home.  It looks really terrible right now but it works, now to pretty it up a bit before posting it for sharing.  You should be able to downlod the txt file if you really want but I will add an arduino sketch once i have tested it out on the quadcopter.

https://www.dropbox.com/s/at5rpnige2im41s/front%20and%20back%20sensors.txt

Jimmy Chan is my partner in this project and he has made some 3D models for the sensor holders and cross bar connectors.  These will probably make more sense when I post pictures of the quad after assembly.

http://www.thingiverse.com/thing:285787
http://www.thingiverse.com/thing:282783

We will be using the schools 3D printer this week to make these parts and with a little luck maybe we can have some pictures, better looking code, and some video on our youtube site by this weekend.


for now these files are linked here for ease of access for ourselves to continue to work on things away from the school.

Feel free to check them out if you want.


Sunday, March 30, 2014

Ok, Ok, I know I said I would go work on the Arduino code today, but its Sunday and Im being lazy.  I thought I would at least link my proposed changes that I will test tomorrow.
First off, the if else code is slightly off

What I had:
if(LocalNewFlag & PITCH_FLAG)
  {     // below the code will limit user input differently at various distances from the wall
        // this should, in theory, limit the user input for a slow deceleration towards an obsticle and avoid it if 
        // the quad copter should drift towards the wall after limiting the users input to nill
        // this still allows the user to perform other movements unchecked.  That means the user could possibly fly at max             //  speed along a wall while maintaining a 1.5 to 2 ft range from the 
        // wall if the user gives some input towards the wall with the other direction.
       if((distancef && distanceb >= 246) || (distancef && distanceb <=0 )) // if outside the range of 1 cm to 245(10 ft)                    //ignore ultrasonic data
{
servoChannel1.writeMicroseconds(PITCH_IN_LOCAL);
}      
      else if(distancef < distanceb) // checks to see which distance is closer that involves this channel
{
        if(distancef < 45) // distances in cm danger close check accounts for drifting and inertia toward the wall
                {
servoChannel1.writeMicroseconds(1400); // back away from the wall
}
                else if(distancef < 60) // this one is the distance from the obsticle that we dont want user input to move that                           // direction
                {
servoChannel1.writeMicroseconds(1500); // no user input
}
                else if(distancef < 122) // closest distance that a user can still control the quad to move toward the wall
                {
    if(PITCH_IN_LOCAL > 1550) // limits the user to max of movement in this direction of very slow
      {
      servoChannel1.writeMicroseconds(1550); 
      }
      else
      {
      servoChannel1.writeMicroseconds(PITCH_IN_LOCAL); // allows the user to slowly close on the obsticle
      }
}
                else if(distancef < 183) // less limited and further away from the wall currently at the 6 ft range
                {
      if(PITCH_IN_LOCAL > 1600)
      {
      servoChannel1.writeMicroseconds(1600); // same as before limits users max to slow approach
      }
      else
      {
      servoChannel1.writeMicroseconds(PITCH_IN_LOCAL);
      }
}
                else if(distancef < 245) // even less limited further still from the wall currently at 8 ft range
                {
      if(PITCH_IN_LOCAL > 1650) 
      {
      servoChannel1.writeMicroseconds(1650); // same as before limits users max to slightly faster approach
      }
      else
      {
      servoChannel1.writeMicroseconds(PITCH_IN_LOCAL);
      }
}
        }
else

What I think will work better(some of this has been tested)
if(LocalNewFlag & PITCH_FLAG)
  {   if(distancef <= distanceb) // checks to see which distance is closer that involves this channel
     {
     if(distancef < 45) // distances in cm danger close check accounts for drifting and inertia toward the wall
         {
           if(PITCH_IN_LOCAL > 1400)
             {             servoChannel1.writeMicroseconds(1400); // back away from the wall
            }
            else
            {
            servoChannel1.writeMicroseconds(PITCH_IN_LOCAL);
            }
       } 
        else if(distancef < 60)
            {
                if(PITCH_IN_LOCAL > 1500)
                  {                  servoChannel1.writeMicroseconds(1500); // back away from the wall
                 }
                  else
                 {
                 servoChannel1.writeMicroseconds(PITCH_IN_LOCAL);
                 }
            } 
        else if(distancef < 122) // closest distance that a user can still control the quad to move toward the wall
            {
          if(PITCH_IN_LOCAL > 1550) // limits the user to max of movement in this direction of very slow
             {
            servoChannel1.writeMicroseconds(1550); 
            }
            else
            {
            servoChannel1.writeMicroseconds(PITCH_IN_LOCAL); // allows the user to slowly close on the obsticle
            }
        }
     else if(distancef < 183) // less limited and further away from the wall currently at the 6 ft range
        {
           if(PITCH_IN_LOCAL > 1600)
             {
             servoChannel1.writeMicroseconds(1600); // same as before limits users max to slow approach
             }
             else
             {
             servoChannel1.writeMicroseconds(PITCH_IN_LOCAL);
             }
      }
   else if(distancef < 245) // even less limited further still from the wall currently at 8 ft range
      {
         if(PITCH_IN_LOCAL > 1650) 
           {
           servoChannel1.writeMicroseconds(1650); // same as before limits users max to slightly faster approach
           }
           else
           {
           servoChannel1.writeMicroseconds(PITCH_IN_LOCAL);
           }
    }
  else
     {      
     servoChannel1.writeMicroseconds(PITCH_IN_LOCAL);
      }
}
else
blah blah blah from above with similar changes

These changes that I have highlighted in yellow did fix the logic problems I was having while using static distances.
Now what do I think may be going wrong with my ultrasonics.  Possibly the way I have defined the loop
What I have:

#define pingcnt 6  // define number of pings to loop through for ultrasonic pings
int avgf[pingcnt]; //array for front ultrasonc sensor
int avgb[pingcnt]; //array for rear ultrasonc sensor
int avgr[pingcnt]; //array for right ultrasonc sensor
int avgl[pingcnt]; //array for left ultrasonc sensor

What I am going to try Monday

int pingcnt = 6;  // define number of pings to loop through for ultrasonic pings
int avgf[pingcnt]; //array for front ultrasonc sensor
int avgb[pingcnt]; //array for rear ultrasonc sensor
int avgr[pingcnt]; //array for right ultrasonc sensor
int avgl[pingcnt]; //array for left ultrasonc sensor


Simple change really.  I hope that I am correct in assuming that I was stupidly trying to define a constant number incorrectly.  I don't really know why I tried using the #define instead of making it an int variable anyway.  I will still need to tweak the code a bit more.  
I did see that there was a problem when just assigning values to the distances within the segment of the code that the interrupts were off.  I'm not sure why that is, further testing will be required.  I would rather ping my ultrasonics without having pesky interrupts doing their thing and you know, interrupting them. 
Since the nature of how the RC signals are being utilized, they are constantly being updated whether the user is changing the hand held controller or not.  That stick position is still being sent and updated.  So the stick sitting at 1500 is going to update to 1500 even if it was 1500 during the previous loop.  Sorry if I lost anyone reading this there. 

Well back to being lazy today.  More to come later this week. 

Saturday, March 29, 2014

So I did some testing today and the ultrasonic reads are not working properly, and when testing with static distance values I found some errors with my if else statements.  Once I get those worked out, hopefully tomorrow, I will post the changes to the code.  Meanwhile I need to find a better way of reading the ultrasonic ranges in without breaking the hardware interrupts.   A really good library called NewPing will not work because the timed interrupts take a higher priority than my hardware interrupts.  This is why I tried using the mod function with multiple ping reads for each sensor.  This may still be the way I need to proceed but I need to nail down whats causing it to break the code right now.
Changes upcoming are removing the initial check for the distances out of range.   This was not working at all for some reason.  I will add a final condition for being further than 8 ft or 245 cm to give full control back to the user.  
Under tests today I found that there is a possible problem with how the if statements react to multiple conditions on the same channel.  Example in a hallway if the left and right distances should trigger events at the same time.  The way I have it written now, it will only adjust for the shortest distance.  This could allow for issues like if the wall is closer on the right side you can pull away from that wall at full speed towards the left wall until the distance is less for the left vs the right one.  In theory this shouldn't matter, but I can see a problem if you try to operate within a tight area.  This will all depend on the reaction time of the controller and code.

Wednesday, March 26, 2014

My first attempt quad copter

So my Senior Project for Computer Engineering Technology at the University of Southern Mississippi is giving me fits.  I am attempting to use an Arduino DUE to take in RC from a receiver and pass them through the DUE to an APM 2.6 flight controller on a Quad Copter.  The pass through works fine.   I am now adding ultrasonic sensors to the mix to add some wall avoidance to the quad.  I am currently testing methods to implement the ultrasonic reads as there are no Arduino DUE libraries for ultrasonics out there yet.
Another problem is the Arduino DUE can only handle a 3.3V signal to come from the echo of the sensor.  I am using the HC-SR04 sensors for testing right now due to their cost and fairly decent accuracy.  Just about all sensors and sheilds designed for the Arduino family use 5v signals.  This gives us a problem, well sorta.  I am testing different configurations of voltage dividers to reduce the voltage without compromising the signal.  This alas is my current hangup keeping me from testing my code out.
Below is the code in segments.
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
Without his code to basically copy I would still be very much lost.

UPDATE 3/28/2014 
I am putting my DUE away for now and testing with a mega2560
Pretty much the same code with a few minor changes if it works.  I have to change how the library servo.h is written syntax wise and how to use the attach interrupt statements.  I am highlighting what I forgot and what I changed.

Ok I found a couple of errors from above and changed some things around.  One I forgot to copy my local flag from my global one.  This flag is to tell the rest of the program that there was an update to one of the channels, basically any change triggers the ISR and that triggers the global flag.  I have to turn off the interrupt handler to make a local copy of the flag and the changed incoming values.
I forgot to turn my interrupts back on so of course the code doesnt update... duhh.  I am actually moving back to the Mega2560 arduino for further testing so I dont have to deal with the voltage divider and possible ruining my DUE.  but the code should work for both in theory.
Another change I am making is to move the ultrasonic for loop and mode calculation to inside the area of the code that the interrupts are turned off.  This should not add enough time with the interrupts off to be noticed.

First the includes and defines.
#include <Average.h>
//#include "Servo.h" // DUE
#include <Servo.h>  // big difference here huh  Mega2560

#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 9  // attach to flight controller elevator pin
#define ROLL_CHANNEL_OUT 10  // 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 pingcnt 6  // define number of pings to loop through for ultrasonic pings
int avgf[pingcnt]; //array for front ultrasonc sensor
int avgb[pingcnt]; //array for rear ultrasonc sensor
int avgr[pingcnt]; //array for right ultrasonc sensor
int avgl[pingcnt]; //array for left ultrasonc sensor

// using digital pins
#define TRIGGER_PINF 4   // trigger pin for front ultrasonic sensor
#define ECHO_PINF 5 // echo pin for front ultrasonic sensor
#define TRIGGER_PINB 6 // trigger pin for rear ultrasonic sensor
#define ECHO_PINB 7 // echo pin for rear ultrasonic sensor
#define TRIGGER_PINL 8 // trigger pin for left ultrasonic sensor
#define ECHO_PINL 9 // echo pin for left ultrasonic sensor
#define TRIGGER_PINR 10 // trigger pin for right ultrasonic sensor
#define ECHO_PINR 11 // echo pin for right ultrasonic sensor

Now that thats done we add in the setup portion

void setup() 
{
  Serial.begin(115200);  // for testing the PWM pass through just add Serial.print(the channel needed); after the servo write 
  
  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

  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 
  //attachInterrupt(PITCH_CHANNEL_IN, calcPitch,CHANGE);  // attach interrupt to the in pins for pass through
  //attachInterrupt(ROLL_CHANNEL_IN, calcRoll,CHANGE); // attach interrupt to the in pins for pass through
// notice above that the only change between DUE attach interrupt statement and the Mega is you can't just assign
// any pin as an interrupt in the Mega like you can in the DUE.
// I am using 2 interrupts so using pin 2 which is interrupt 0 on the mega
// and pin 3 which os interrupt 1 on the mega (arduino.cc datasheet had these wrong when I originally did some research)
// INT5 :        18
// INT4 :        19
// INT3 :        20
// INT2 :        21
// INT1 :        3
// INT0 :        2  
// check out http://arduinomega.blogspot.com/2011/05/external-interrupts-buttons-for.html for a good explanation of these


  // set ultrasonic pin modes trigger out and echo in
  pinMode(TRIGGER_PINF, OUTPUT);
  pinMode(TRIGGER_PINB, OUTPUT);
  pinMode(TRIGGER_PINL, OUTPUT);
  pinMode(TRIGGER_PINR, OUTPUT);
  pinMode(ECHO_PINF, INPUT);
  pinMode(ECHO_PINB, INPUT);
  pinMode(ECHO_PINL, INPUT);
  pinMode(ECHO_PINR, INPUT);
}

Now for the main loop

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();
       // check which channel was the flagged as updated
    LocalNewFlag = SharedNewFlag; // silly me left this out also without this there is nothing updated ever
    if(LocalNewFlag & PITCH_FLAG)
    {
      PITCH_IN_LOCAL = PITCH_IN_SHARED; // set local copy of input to global shared value
    }
   
    if(LocalNewFlag & ROLL_FLAG)
    {
      ROLL_IN_LOCAL = ROLL_IN_SHARED;  // set local copy of input to global shared value
    }
   
    SharedNewFlag = 0;  // reset global update flag to zero for next loop
}
//force trigger pins low then high for at least 10us to help clear false echos
//save the measured distances to an int variable
            
   for(int i=0; i<pingcnt; i++)
   {
    digitalWrite(TRIGGER_PINF, LOW);
    delayMicroseconds(2);
    digitalWrite(TRIGGER_PINF, HIGH);
    delayMicroseconds(10);
    digitalWrite(TRIGGER_PINF, LOW);
    long durationf = pulseIn(ECHO_PINF, HIGH);
    avgf[i] = (durationf/2)/29.1;
    
    digitalWrite(TRIGGER_PINB, LOW);
    delayMicroseconds(2);
    digitalWrite(TRIGGER_PINB, HIGH);
    delayMicroseconds(10);
    digitalWrite(TRIGGER_PINB, LOW);
    long durationb = pulseIn(ECHO_PINB, HIGH);
    avgb[i] = (durationb/2)/29.1;
    
    digitalWrite(TRIGGER_PINR, LOW);
    delayMicroseconds(2);
    digitalWrite(TRIGGER_PINR, HIGH);
    delayMicroseconds(10);
    digitalWrite(TRIGGER_PINR, LOW);
    long durationr = pulseIn(ECHO_PINR, HIGH);
    avgr[i] = (durationr/2)/29.1;
    
    digitalWrite(TRIGGER_PINL, LOW);
    delayMicroseconds(2);
    digitalWrite(TRIGGER_PINL, HIGH);
    delayMicroseconds(10);
    digitalWrite(TRIGGER_PINL, LOW);
    long durationl = pulseIn(ECHO_PINL, HIGH);
    avgl[i] = (durationl/2)/29.1;

    
   }
   int distancef = mode(avgf, pingcnt); // distance equals the most common value of the array currently set to 6
   int distanceb = mode(avgb, pingcnt);
   int distancer = mode(avgr, pingcnt);
   int distancel = mode(avgl, pingcnt);

interrupts();  // oops forgot to turn them back on last post


  //depending on which update flag was triggered output determined on ultrasonic calculations
  //distances are in cm 
if(LocalNewFlag & PITCH_FLAG)
  {     // below the code will limit user input differently at various distances from the wall
        // this should, in theory, limit the user input for a slow deceleration towards an obsticle and avoid it if 
        // the quad copter should drift towards the wall after limiting the users input to nill
        // this still allows the user to perform other movements unchecked.  That means the user could possibly fly at max             //  speed along a wall while maintaining a 1.5 to 2 ft range from the 
        // wall if the user gives some input towards the wall with the other direction.
      if((distancef && distanceb >= 246) || (distancef && distanceb <=0 )) // if outside the range of 1 cm to 245(10 ft)                    //ignore ultrasonic data
{
servoChannel1.writeMicroseconds(PITCH_IN_LOCAL);
}      
      else if(distancef < distanceb) // checks to see which distance is closer that involves this channel
{
       if(distancef < 45) // distances in cm danger close check accounts for drifting and inertia toward the wall
                {
servoChannel1.writeMicroseconds(1400); // back away from the wall
}
                else if(distancef < 60) // this one is the distance from the obsticle that we dont want user input to move that                           // direction
                {
servoChannel1.writeMicroseconds(1500); // no user input
}
                else if(distancef < 122) // closest distance that a user can still control the quad to move toward the wall
                {
   if(PITCH_IN_LOCAL > 1550) // limits the user to max of movement in this direction of very slow
     {
     servoChannel1.writeMicroseconds(1550); 
     }
     else
     {
     servoChannel1.writeMicroseconds(PITCH_IN_LOCAL); // allows the user to slowly close on the obsticle
     }
}
                else if(distancef < 183) // less limited and further away from the wall currently at the 6 ft range
                {
     if(PITCH_IN_LOCAL > 1600)
     {
     servoChannel1.writeMicroseconds(1600); // same as before limits users max to slow approach
     }
     else
     {
     servoChannel1.writeMicroseconds(PITCH_IN_LOCAL);
     }
}
                else if(distancef < 245) // even less limited further still from the wall currently at 8 ft range
                {
     if(PITCH_IN_LOCAL > 1650) 
     {
     servoChannel1.writeMicroseconds(1650); // same as before limits users max to slightly faster approach
     }
     else
     {
     servoChannel1.writeMicroseconds(PITCH_IN_LOCAL);
     }
}
        }
else
{
if(distanceb < 45)
                {
servoChannel1.writeMicroseconds(1600); // back away from the wall
}
       else if(distanceb < 60)
                {
servoChannel1.writeMicroseconds(1500); // no user input
}
                else if(distanceb < 122)
                {
   if(PITCH_IN_LOCAL > 1450)
   {
   servoChannel1.writeMicroseconds(1450); 
   }
   else
   {
   servoChannel1.writeMicroseconds(PITCH_IN_LOCAL);
   }
}
else if(distanceb < 183)
                {
   if(PITCH_IN_LOCAL > 1400)
   {
   servoChannel1.writeMicroseconds(1400); 
   }
   else
   {
   servoChannel1.writeMicroseconds(PITCH_IN_LOCAL);
   }
}
                else if(distanceb < 245)
                {
   if(PITCH_IN_LOCAL > 1350)
   {
   servoChannel1.writeMicroseconds(1350); 
   }
   else
   {
   servoChannel1.writeMicroseconds(PITCH_IN_LOCAL);
   }
}
}   
  }

  if(LocalNewFlag & ROLL_FLAG)
  {
if((distancer && distancel >= 246) || (distancer && distancel <=0 )) // if outside the range of 1 cm to 245(10 ft) ignore ultrasonic data
{
servoChannel2.writeMicroseconds(ROLL_IN_LOCAL);
}
      else if(distancer < distancel)
{
if(distancer < 45)
                {
servoChannel2.writeMicroseconds(1400); // back away from the wall
}
       else if(distancer < 60)
                {
servoChannel2.writeMicroseconds(1500); // no user input
}
                else if(distancer < 122)
                {
                    if(ROLL_IN_LOCAL > 1550)
   {
   servoChannel2.writeMicroseconds(1550); 
   }
   else
   {
   servoChannel2.writeMicroseconds(ROLL_IN_LOCAL);
   }
}
else if(distancer < 183)
                {
   if(ROLL_IN_LOCAL > 1600)
   {
   servoChannel2.writeMicroseconds(1600); 
   }
   else
   {
   servoChannel2.writeMicroseconds(ROLL_IN_LOCAL);
   }
}
                else if(distancer < 245)
                {
   if(ROLL_IN_LOCAL > 1650)
   {
   servoChannel2.writeMicroseconds(1650); 
   }
   else
   {
   servoChannel2.writeMicroseconds(ROLL_IN_LOCAL);
   }
}
}
else
{
if(distancel < 45)
                {
servoChannel2.writeMicroseconds(1600); // back away from the wall
}
       else if(distancel < 60)
                {
servoChannel2.writeMicroseconds(1500); // no user input
}
                else if(distancel < 122)
                {
                    if(ROLL_IN_LOCAL > 1450)
   {
   servoChannel2.writeMicroseconds(1450); 
   }
   else
   {
   servoChannel2.writeMicroseconds(ROLL_IN_LOCAL);
   }
}
else if(distancel < 183)
                {
   if(ROLL_IN_LOCAL > 1400)
   {
   servoChannel2.writeMicroseconds(1400); 
   }
   else
   {
   servoChannel2.writeMicroseconds(ROLL_IN_LOCAL);
   }
}
                else if(distancel < 245)
                {
   if(ROLL_IN_LOCAL > 1350)
   {
   servoChannel2.writeMicroseconds(1350); 
   }
   else
   {
   servoChannel2.writeMicroseconds(ROLL_IN_LOCAL);
   }
}
        }
  }

LocalNewFlag = 0; // reset local flag to zero for next update
}

Last 2 functions

// 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;
  }
}