Hi all,
I’m reading a quadrature rotary encoder from a motor. It’s pretty simple, it just change a variable in a interrupt. But I got a problem: I need to read it 100 times per second in a PID loop, but then it misses some pulses.
thread.sleep is not deterministic, ie you can’t rely on it being able to stay on a fixed schedule.
debug.print creates strings, and destroy them, meaning you are asking the GC to do stuff, which takes time. If you’re using debug.print and thread.sleep(10) you’re probably seeing exactly what I would expect, and the approach I’d take is to try your actual work you need to do and see if that is any different?
They are different, that the whole point!! Normally you would assign the variable as volatile. This is a example using the mbed: InterruptIn - Handbook | Mbed
The problem is that it tries to set a variable while is being read, which corrupts the variable. When the motors is on the following error occurs:
The sleep lets the main thread sleep but the interrupts should still be handled.
The main problem is more that the time at which the interrupt routine is scheduled might be out of phase with the encoders: OnInterrupt might be handled 20 ms after the actual interrupt. Inside the handler you are comparing e.g. the value of A when the interrupt happened and comparing it to the current value of B. This will fail from time to time.
So you’re saying you know why the code appears to miss values? Great, now deal with it.
“Volatile” is a compiler construct to tell the compiler that this variable may get adjusted in ways that the compiler may not understand, so don’t try to optimise the code; this isn’t an issue that I have ever seen discussed in NETMF.
Actually, why don’t you explain what you mean by “but it misses some pulses”. Is the problem that your interrups miss pulses, or that your PID loop doesn’t get to process each of the pulses as they come in? As I said, thread.sleep is not guaranteed to be a precise time interval; so a loop with a thread.sleep(100) in it won’t get processed 10 times a second, and if it was thread.sleep(10) it won’t get processed 100 times a second either.
Okay, I will try to reexplain my problem. The problem is that you can’t write to a variable while is being read. That is not a problem if you only read it approximately 10 times a second. But if you have to read it approximately 100 times a second (it has to feed a PID controller for a segway - it balances very well, but I would like to enable the encoders as well) it fails to read the encoders correctly - it misses the some of the pulses sent from the encoder.
It is a total of 1856 counts per revolution. I can count all of them when reading only 10 times a second, but when reading 100 times, it only counts something like 300-500, and it changes a lot.
So I was really asking if there were a similar function in NETMF, as you would normal just set the variable as volatile.
Hope that explained it better
I think a better understanding of how interrupts are handled is necessary.
When an interrupt occurs, an internal queue entry is created. The runtime then schedules the interrupt handlers. There can be a few millisecond delay between when the interrupt actually occurs and when the handler gets the interrupt. That is why there is a timestamp parameter.
In your code, you are handling an interrupt, which occurred in the past, and contains the state at the past point, and you reading the current value of the other phase. You have created a time warp.
Interrupts are handle in chronological order and one at a time. You should have variables which contains the state of the A and B. When handling A you should use the B value that existed in the last B interrupt, not the current value of B.
Since interrupts are queued in memory, if you don’t handle interrupt fast enough you will run out of memory and get an exception.
BTW, I have just finished writing code for an encoder with 512 changes per rotation. If I put Debug.Print statements into the interrupt handlers I often ran out of memory.
Hmm, it still throws an exception, if the motor spins to fast - even if I don’t do anything in the main thread. Might have to use RLP or set up the interrupt using the registers, or do anyone have any suggestions?