Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
5 years, 1 month 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
5 years, 1 month 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.
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 08 Nov 2019What 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" } } }
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 08 Nov 2019I'm sorry. There was an error in the mbed_app.json
. It's fixed now. Copy & paste it to your project and compile again.
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 08 Nov 2019