c - Arduino Drone project, when output is "loaded" (even cap to gnd), input "steering" command starts to glitch -


arduino drone project, whenever output "loaded" ("open-circuit" signal-in pin esc or cap ground), input "steering" command starts glitch (go low values << 1000).

the motor speed function of both steering command, throttle. (in test-case 1 motor seen in code below, unmotorspeed = unthrottlein +/- unsteeringin)

when hooked scope, physical input signals (steering , throttle coming receiver) great, , swapped input pins make sure there wasn't problem between receiver , arduino. problem seems coming software, doesn't make sense, since when there isn't "load" attached, input , output values fine , clean. (i put "load" in quotes because it's open circuit --> super high impedance input signal electronic speed controller (esc), don't ground complete circuit).

would able check out code , see if i'm missing something?

at point, quick workaround not write new glitchy values motor , keep old speed values whenever new speed lower old speed (and these @ on 50khz, huge jump in 1 step bit crazy).

note: in code, total output of unmotorspeed leaves servothrottle pin. original naming didn't end changing... it's clear if read code , see variables.

update: weird thing is, ran setup without changes , worked...i reflashed arduino multiple times make sure wasn't lucky glitch, , kept on working, set up. dropped remote on ground , moved few of wires on breadboard around, , things went wonky ways after putting setup together. idk do!

// --> starting code found at: rcarduino.blogspot.com // see related posts - // http://rcarduino.blogspot.co.uk/2012/01/how-to-read-rc-receiver-with.html with.html   #include <servo.h>  // assign channel in pins #define throttle_in_pin 3 #define steering_in_pin 2   // assign channel out pins #define throttle_out_pin 9 //#define steering_out_pin 9   // servo objects generate signals expected electronic speed controllers , servos // use objects output signals read in // example code provides straight pass through of signal no custom processing servo servothrottle; //servo servosteering;   // these bit flags set in bupdateflagsshared indicate // channels have new signals #define throttle_flag 1 #define steering_flag 2  // holds update flags defined above volatile uint8_t bupdateflagsshared;  // shared variables updated isr , read loop. // in loop immediatley take local copies isr can keep ownership of // shared ones. access these in loop // first turn interrupts off nointerrupts // take copy use in loop , turn interrupts on // possible, ensures able receive new signals volatile uint16_t unthrottleinshared; volatile uint16_t unsteeringinshared;  // these used record rising edge of pulse in calcinput functions // not need volatile used in isr. if wanted // refer these in loop , isr need declared volatile uint32_t ulthrottlestart; uint32_t ulsteeringstart; //uint32_t ulauxstart;  void setup() {   serial.begin(9600);    // attach servo objects, these generate correct   // pulses driving electronic speed controllers, servos or other devices   // designed interface directly rc receivers    servothrottle.attach(throttle_out_pin);    // using pinchangeint library, attach interrupts   // used read channels   attachinterrupt(digitalpintointerrupt(throttle_in_pin), calcthrottle,change);   attachinterrupt(digitalpintointerrupt(steering_in_pin), calcsteering,change); }  void loop() {   // create local variables hold local copies of channel inputs   // these declared static thier values retained   // between calls loop.   static uint16_t unthrottlein;   static uint16_t unsteeringin;   static uint16_t difference;   static uint16_t unmotorspeed; // variable stores overall motor speed   static uint8_t bupdateflags; // local copy of update flags    // check shared update flags see if channels have new signal   if(bupdateflagsshared)   {     nointerrupts(); // turn interrupts off while take local copies of shared variables      // take local copy of channels updated in case need use in rest of loop     bupdateflags = bupdateflagsshared;      // in current code, shared values populated     // copy them without testing flags     // in future change, lets     // copy when flags tell can.      if(bupdateflags & throttle_flag)     {       unthrottlein = unthrottleinshared;     }      if(bupdateflags & steering_flag)     {       unsteeringin = unsteeringinshared;     }      // clear shared copy of updated flags have taken updates     // still have local copy if need use in bupdateflags     bupdateflagsshared = 0;      interrupts(); // have local copies of inputs, can turn interrupts on     // interrupts on, can no longer use shared copies, interrupt     // service routines own these , update them @ time. during update,     // shared copies may contain junk. luckily have our local copies work :-)   }    //serial.println(unsteeringin);    // processing here onwards   // use local values unauxin, unthrottlein , unsteeringin, shared   // variables unauxinshared, unthrottleinshared, unsteeringinshared owned   // interrupt routines , should not used in loop    // following code provides simple pass through   // initial test, arduino pass through   // receiver input if arduino not there.   // should used confirm circuit , power   // before attempting custom processing in project.    // checking see if channel value has changed, indicated    // flags. simple pass through don't need     check,   // more complex project new signal requires significant processing   // allows calculate new values when have new inputs, rather   // on every cycle.  ///// if-else chain commented out determine/prove problem steering signal --> buggy!      if(unsteeringin < 1400) // if steering joystick moved left   {   difference = 1400 - unsteeringin;   if(unthrottlein - difference >= 0)     unmotorspeed = unthrottlein - difference;   }   else if(unsteeringin > 1550) //if steering joystick moved right (needs tweaked, works now)   {     difference = unsteeringin - 1600;     if(unthrottlein + difference < 2000)       unmotorspeed = unthrottlein + difference;   }   else   {     unmotorspeed = unthrottlein;     }    //serial.println(unmotorspeed);   //serial.println(unsteeringin);   //serial.println(unthrottlein);    if(bupdateflags)   {     //serial.println(servothrottle.readmicroseconds());     if(servothrottle.readmicroseconds() != unmotorspeed)     {       servothrottle.writemicroseconds(unmotorspeed);       serial.println(unmotorspeed);     }   }    bupdateflags = 0; }  // simple interrupt service routine void calcthrottle() {   // if pin high, rising edge of signal pulse, lets record value   if(digitalread(throttle_in_pin) == high)   {     ulthrottlestart = micros();   }   else   {     // else must falling edge, lets time , subtract time of rising edge     // gives use time between rising , falling edges i.e. pulse duration.     unthrottleinshared = (uint16_t)(micros() - ulthrottlestart); // pulse duration      // use set throttle flag indicate new throttle signal has been received     bupdateflagsshared |= throttle_flag;   } }  void calcsteering() {   if(digitalread(steering_in_pin) == high)   {     ulsteeringstart = micros();   }   else   {     unsteeringinshared = (uint16_t)(micros() - ulsteeringstart); // pulse duration     bupdateflagsshared |= steering_flag;   } } 

you should read documentation of attachinterrupt() - in section "about interrupt service routines" gives information on how functions behave when called interrupt. micros() states:

micros() works initially, start behaving erratically after 1-2 ms.

i believe means after isr has been running more 1ms, rather 1 ms in general, may not apply in case, might need consider how doing timing in isr. that's problem arduino - terrible documentation!

one definite problem may cause fact unsteeringinshared non-atomic. 16 bit value on 8 bit hardware requires multiple instructions read , write , process can interrupted. therefore possible read 1 byte of value in loop() context , have both bytes changed interrupt context before read second byte, 2 halves of 2 different values.

to resolve problem either disable interrupts while reading:

nointerrupts() ; unsteeringin = unsteeringinshared ; interrupts() ; 

or can spin-lock read:

do {     unsteeringin = unsteeringinshared ;  } while( unsteeringin != unsteeringinshared ) ; 

you should same unthrottleinshared too, although why not see problem unclear - perhaps not problem observing, problem in case.

alternatively if 8 bit resolution sufficient encode input atomic 8 bit value thus:

uint8_t unsteeringinshared ;   ...   int32_t timeus = micros() - ulsteeringstart - 1000 ; if( timeus < 0 ) {     unsteeringinshared = 0 ; } else if( timeus > 1000 ) {     unsteeringinshared = 255; } else {     unsteeringinshared = (uint8_t)(time * 255 / 1000) ; } 

of course changing scale 1000 2000 0 255 need changes rest of code. example convert value x in range 0 255 a servo pulse width:

 pulsew = (x * 1000 / 256) + 1000 ;