4 years, 5 months ago.

EventQueue. Can't make controller work in real time.

Hi, I need several functions to be called every 1 ms precisely at the same time. Take a look at the code. I use eventqueue for this. To monitor real time, I send an integer via uart every 10ms, and then increase it. But it happens slower than a real time goes. After 2 minutes of monitoring, it delays for 2s from real time. How can i make it execute in real time, without delays, what do i do wrong?

code

#include "mbed.h"
#include "rtos.h"
#include "QEI.h"

#define SAMPLE_TIME 0.001f
#define PWM_PERIOD 0.0001f
#define PI 3.14159265359f



class ControlLoop{
    private:
        float dutyCycleI, dutyCycleK, dutyCycle;
        
    public:
        float uz, e, ep, ew, wz, uzp;
        QEI enc;
        PwmOut in1, in2;
        
        ControlLoop(PinName driverIn1, PinName driverIn2, PinName encoderChA, PinName encoderchB, int ppr):\
        enc(encoderChA, encoderchB, NC, ppr, QEI::X4_ENCODING), in1(driverIn1), in2(driverIn2){
            in1.period(PWM_PERIOD);
            in2.period(PWM_PERIOD);
            in1.write(0);
            in2.write(0);
        }

    
      float zpOutput(float uz, float acc, float wmax){ //zp
            
            float sign, temp;
            ep = uz - uzp;
            if(ep >= 0) sign = 1.0f;
            if(ep < 0) sign = -1.0f;
            temp = sign * sqrt((abs(ep) * 2.0f));   
            if(temp >= wmax) temp = wmax;                   
            if(temp <= -wmax) temp = -wmax;
            ew = temp - wz;
            if(ew >= 0) sign = 1.0f;
            if(ew < 0) sign = -1.0f;
            wz = wz + sign * acc * SAMPLE_TIME; 
            uzp = uzp + wz * SAMPLE_TIME;
            return uzp;
       }
            
      void control(float uZpOut, float k, float i, float dcl){ //pi-regulator
            
            e = uZpOut - (float)enc.getPulses() / 16.1f * PI / 180.0f;
            dutyCycleK = abs(e * k);
            dutyCycleI = abs(dutyCycleI + e * i);      
            dutyCycle = dutyCycleK + dutyCycleI;
            if(dutyCycle >= dcl) dutyCycle = dcl;
            
            if(e >= 0){
            in2.write(dutyCycle);
            in1.write(0);
            }else{
            in1.write(dutyCycle);
            in2.write(0);
        }
    
      } 
};

Serial pc(PD_5, PD_6);
Serial bluetooth(PD_8, PD_9);

EventQueue eventQueue;

ControlLoop system1(PB_3, PB_8, PA_2, PA_3, 5800);
ControlLoop system2(PB_3, PB_8, PA_2, PA_3, 5800);
ControlLoop system3(PB_3, PB_8, PA_2, PA_3, 5800);
ControlLoop system4(PB_3, PB_8, PA_2, PA_3, 5800);
ControlLoop system5(PB_3, PB_8, PA_2, PA_3, 5800);
ControlLoop system6(PB_3, PB_8, PA_2, PA_3, 5800);


int c = 0;
void uartOutF(){
    
    pc.printf("%i %f %f %f %f %f %f;\n", c, system1.uzp,system6.uzp,system2.uzp,system3.uzp,system4.uzp,system5.uzp);
    c++;
}

void move1m(){
    system1.zpOutput(1, 1, 1);
}
void move2m(){
    system2.zpOutput(2, 1, 1);
}
void move3m(){
    system3.zpOutput(3, 1, 1);
}
void move4m(){
    system4.zpOutput(4, 1, 1);
}
void move5m(){
    system5.zpOutput(5, 1, 1);
}
void move6m(){
    system6.zpOutput(6, 1, 1);
}


int main() {
   
   pc.baud(115200);  
 
   eventQueue.call_every(1, move1m);
   eventQueue.call_every(1, move2m);
   eventQueue.call_every(1, move3m);
   eventQueue.call_every(1, move4m);
   eventQueue.call_every(1, move5m);
   eventQueue.call_every(1, move6m);

   eventQueue.call_every(10, uartOutF);

   eventQueue.dispatch_forever();
}

Firstly, i thought it's because of printf function, but i tried to disable it and monitoring with led. It's still executing slower than real time.

1 Answer

4 years, 5 months ago.

Hello Alex,

Maybe it's because the EventQueue is starving. You can check it for example as follows:

...

Timer timer;
int buf[100];
int i = 0;

void move() {
    buf[i++] = timer.read_us();
    timer.reset();
    if (i == 100) {
        timer.stop();
        for (int j = 0; j < i; j++) {
            pc.printf("%d: 'move' called after %d us\r\n", j, buf[j]);
        }
        eventQueue.break_dispatch();
    }
    system1.zpOutput(1, 1, 1);
    system2.zpOutput(2, 1, 1);
    system3.zpOutput(3, 1, 1);
    system4.zpOutput(4, 1, 1);
    system5.zpOutput(5, 1, 1);
    system6.zpOutput(6, 1, 1);
}

int main() {
    pc.baud(115200);  
    eventQueue.call_every(1, move);
    timer.start();
    eventQueue.dispatch_forever();
}

move should be called after <= 1000 us for each iteration. Otherwise the eventQueue is starving and probably you need a faster hardware to run the controller in real time.

Accepted Answer

Hi, Zoltan, thank you for the answer. I tried your code, and the result is: function "move" was called in 998us in all 100 cases. But I also tried another code:

code2

#include "mbed.h"
#include "rtos.h"
#include "QEI.h"


DigitalOut led(PC_1);


       



void ledSw(){
    
    led=!led;
}

Ticker timey;

 

int main() {

    timey.attach(&ledSw, 5.0f);
    
}

Here, I switch the led in Interruption every 5 sec. And even in such simple program there is a delay. And the mistake is getting bigger with time. Firstly, it seemed ok, but then, after 2 minutes, delaay was about 1.5 sec. So i suspect the timer in controller is slower than it should be. How can i check it? Is it hardware or software problem?

posted by Alex Lav 08 Nov 2019

What is your hardware? Is it a NUCLEO-F103RB board? If it is a Blue Pill or a custom board equipped with an external crystal oscillator then to select the correct clock source add an mbed_app.json file :

mbed_app.json

{
    "target_overrides": {
        "*": {
            "target.clock_source": "USE_PLL_HSE_XTAL"
        }
    }
}
posted by Zoltan Hudak 08 Nov 2019

I'm using Black STM32f407vet6, and i write code in mbed studio. I choose SeeedArchMax as a target, cause it has the same microcontroller and pinnames. I tried to add this file. It built without errors, but didn't help. The same delay. PS: maybe it's important: when i open this file in mbed studio it says: Failed to start JSON language server: Error: Failed to spawn node Perhaps it is not on the PATH. but compiling goes without aany errors.

posted by Alex Lav 08 Nov 2019

I'm sorry. There was an error in the mbed_app.json. It's fixed now. Copy & paste it to your project and compile again.

posted by Zoltan Hudak 08 Nov 2019

It's still the same. Maybe i should try internal oscillator? PS. The error with json server is also there. Does it matter? PPS. I tried the same program on the bluepill, there it works fine, without delays. PPPS. The problem really was in USE_PLL_HSE_XTAL. I found file "system_clock.c" in mbed sources and commented lines, where it tries to set USE_PLL_HSE_EXTC. After that it began to work fine. Thank you! And your way to do it with json didn't work because of the error i've written above (and it appears when i open any json file). I could not find the solution, so if you know how to fix it, i'd love to hear it. Thanks again!

posted by Alex Lav 08 Nov 2019