Interrupt PPM SUM cancels main loop

28 Jun 2012

Hi there

I recently started with the mbed to rewrite my flightcontroller from 8-bits to 32-bits.. Now I have a problem. I'm reading a Radio Controllerd receiver. It practically always interrupts because the pin is always changing! Causing my main loop to stop..

So the serial printf's aren't executed.. How do I fix this?

int main() {

    setup();
    _interruptPPM.rise(&RxTrigger);     // Bind Interrupt
    wait(0.5);
    
    while(1) {
   
        _serialPC.printf("Any output: " + buf_ppm[2] );
        _serialPC.printf("\n");
    }
   
}

Trigger:

void RxTrigger() {
    
    deltaTime.stop();                        // Stop timer
    buf_ppm[i] = deltaTime.read_us();        // Read timer to buffer[i] i=turns
    deltaTime.reset();                       // Reset timer
    deltaTime.start();                       // Start timer
    i++;                                // increment i.
    if(buf_ppm[i]>5000) idx = i;    
    if(i== 7) i = 0;
    _serialPC.printf("Random: " + buf_ppm[2]);
    _serialPC.printf("\n");
  
}
28 Jun 2012

You should never do anything computationally expensive or time consuming in an interrupt callback, or you get stuck in it as it has priority.

In your case I think its probably the serial transfer, that will take a long time.

Keep callbacks to the absolute minimum, get the data, process it in the main loop.

28 Jun 2012

I see. But I got to check my values that I get from the readings.. How can I check them

28 Jun 2012

just store the data so you can access it from the main loop? the only problem with your code is the serial i think, id write a class specific to reading the ppm signal, encapsulate the timer, reading and callback

28 Jun 2012

Well.. I can't simply store the data and read it again since it would take too much time to do that. It's a flightcontroller that keeps a multicopter in the air.. Here's the arduino code that works like it should be.

The rxInt functions get triggered by this attachInterrupt(0, rxInt, RISING); PIN 0

void rxInt() {
    uint16_t now,diff;
    static uint16_t last = 0;
    static uint8_t chan = 0;

    now = micros();
    diff = now - last;
    last = now;
    if(diff>3000) chan = 0;
    else {
      if(900<diff && diff<2200 && chan<8 ) {   //Only if the signal is between these values it is valid, otherwise the failsafe counter should move up
        rcValue[chan] = diff;
      }
    chan++;
  }
}
28 Jun 2012

Just to clarify. There is another piece of code that get called when they need the actual data.. (every singe loop)

uint16_t readRawRC(uint8_t chan) {
  uint16_t  rawValue;
  uint8_t   oldSREG;
  oldSREG = SREG;

  cli(); // Let's disable interrupts
  rawValue = rcValue[rcChannel[chan]];
  SREG = oldSREG;
  sei();// Let's enable the interrupts

  return rawValue;
}

void readReceiver() {
  uint8_t chan;
  for (chan = 0; chan < 8; chan++) {
    rcData[chan] = readRawRC(chan);
  }
}
28 Jun 2012

my flight controller reads 3 different serial connections and feeds data back to a ground station, while reading a pwm signal and controlling 4 others, and using this data to update 4 pids in the main loop, there's a lot you can do in < 1ms with 100mhz to play with =), now if only my quads frame would vibrate less

28 Jun 2012

This is great.. Good you have experience with flightcontrollers.

Let's assume there is no base station.. How would I save my data? I'm a programmer, but first time in Flightcontrollers and with 32-bit boards.. sorry :)

Thanks for helping

28 Jun 2012

You mean to pass around yout program or for telemetry to the mbeds storage?, not sure I'm understanding the problem as you seem to have it fixed?

28 Jun 2012

Well, you said that you read the signal pass it to the ground station. Let's assume that I just want to read my PPM SUM without any ground station.

What do you advise me? Why wouldn't a simple interrupt won't work?

Jesse

28 Jun 2012

oh the ground station just for logging flight characteristics, and i control my quad from an xbox controller over xbee serial connection from it, nothing todo with the control loop,

as long as you dont try to use serial, or spend more then a few us is the interrupt its fine,

id modify

Import libraryPwmIn

An interface to read a PWM input signal, using InterruptIn

for the 8 channels and read it like that,

28 Jun 2012

I just use Serial to see the actual values of my transmitter.. How would you show them without serial?

That PwnIn library is every channel apart. Or did you mean to rewrite it to use CPPM / PPM SUM?

(Got it working at the moment but it when I move my stick I need to wait tiny 2 seconds until Serial gives me the right values)

28 Jun 2012

should you be disabling the interrupts?, could you corrupt the PPM signal?

i meant rewrite PwmIn for ppm using the same principles,

you can output serial from the main loop probably at about 100hz but keep in mind the baud limit

28 Jun 2012

Yes I corrupted the PPM signal. Everything is working fine except for the lag on the serial. Takes longer than 3 seconds now before it show up on my screen. Could you explain the serial stuff. Need it for debugging information without any lag..

It reads my values very well now :)

28 Jun 2012

Jesse Struyvelt wrote:

Well, you said that you read the signal pass it to the ground station. Let's assume that I just want to read my PPM SUM without any ground station.

What do you advise me? Why wouldn't a simple interrupt won't work?

Jesse

Here, use this as a reference: http://mbed.org/users/aloeppert/programs/mbedMPU/mcbwdl/docs/board_8cpp_source.html

srcX_hdlr calling a generic interrupt handler, which does precious little and lets the I2c communication and serial printfs go on in user mode (the out_thread() function)

There is your advice.

28 Jun 2012

Funny.. I was going to use the Invense MPU6050 as sensor.. Thanks for the file. Will check it out right now Basically what you are doing is disabling & enabling the interrupts.. which I also did in my code now. This is pretty new for me since I did web development & game programming ;)

28 Jun 2012

just send the serial message every 100ms or so?

id need to see you main loop to help with the lag

28 Jun 2012

http://pastebin.com/PUWw0Qb8

Here's the mainloop

28 Jun 2012

That code should be flooding you with serial data, corrupt more then likely due to the speed, so i should tell you to put a timer around the printf and limit it to 10hz,

from that code there is no lag just an unlimited loop,

28 Jun 2012

Nvm.. Changed baud rate to 9600 and it's fixed. Forgot it was too high for my purpose.

28 Jun 2012

Chris Pepper wrote:

That code should be flooding you with serial data, corrupt more then likely due to the speed, so i should tell you to put a timer around the printf and limit it to 10hz,

from that code there is no lag just an unlimited loop,

Just a timer that counts to 10000 microssec do the thing, reset, count, ..?

Jesse

28 Jun 2012

id limit the printf with a timer, the slower the baud the more time youre wasting sending the data, yea just use a new Timer, you have as many as you want

28 Jun 2012

I didn't knew that! Thanks for the tip. Fixing it right away :)

Thanks guys, it's working!

Jesse

28 Jun 2012

no problem =) good luck with your quad, always fun testing new software =P

28 Jun 2012

Thanks!

Yes it is. Will get a tough time with sensor filtering and PID I guess..

28 Jun 2012

get a good enough imu/ahrs/gyro and all you have to worry about is vibration, pids are quite simple (people will probably point out errors in my implementation now i've said that)

double PidController::update(double input, double setpoint, float prediction, float delta) {
    double error = setpoint - input;
    error = constrain(error, -(_config._max_input), _config._max_input);

    _accumulation += error * delta;
    _accumulation = constrain(_accumulation, -(_config._max_accumulation), _config._max_accumulation);

    double output = (_config._p * error) + (_config._i * _accumulation);
    output = output - (prediction * _config._d);
    output = _config._multiplier * output;
    output = constrain(output,-(_config._max_output), _config._max_output);
    return output;
}

Thats the important bit of my pid class

28 Jun 2012

Thanks for sharing your code! So the basic PID rules you are controlling there. I have a few quadcopters lying here all running on MultiWii FC. Tired of using someone else his software.. Time to do it on my own.

28 Jun 2012

I'm only disabling and enabling the interrupts around the variable I'm updating between the thread loop and the ISR, essentially acting as a MUTEX (since it is a single threaded system, only the ISR and main loop access this variable). The code works just fine without the enabling/disabling of the interrupts, you just might miss clearing or handing a single interrupt without it. Regards, Anthony

Jesse Struyvelt wrote:

Funny.. I was going to use the Invense MPU6050 as sensor.. Thanks for the file. Will check it out right now Basically what you are doing is disabling & enabling the interrupts.. which I also did in my code now. This is pretty new for me since I did web development & game programming ;)

28 Jun 2012

Thanks for the information ;)

29 Jun 2012

There is already a published quadcopter project by Prof Greg Egan . Greg says it is not flightworthy , but he has done quite a lot of work . I think it should be better not to reinvent the wheel each time !

http://mbed.org/users/gke/code/UAVXArm-GKE/