dcservo icon indicating copy to clipboard operation
dcservo copied to clipboard

Drift

Open TheGermanIng opened this issue 4 years ago • 19 comments

Hi, I wrote the same program in bascom before I found yours. I had the problem if 1 interrupts occur at the same time, encoder int at the same time with a new step int, one can be forgotten, I work up to 20 khz encoder and 10 khz step (multiplied step) I have now programmed a 2nd Arduino which e.g. 10000 steps forward and 10000 steps back I let it run for a while, after a while the position drifts. also with your program, the signals are absolutely clean. do you have any idea ?

TheGermanIng avatar May 03 '20 09:05 TheGermanIng

Hi,

Overwhelming the Arduino with too many interrupts is definitely possible and if that happens, crashing the processor and not only missing steps is a very real possibility.

But, as you mentioned, if two interrupts happen at once (an encoder and step pulse for example) one might be ignored. Well, I do not know if that is the case but it should not be. I have not tested myself but I would expect the two events would be taken care of (assuming there is plenty of time before new interrupts). But if a second interrupt happens before the first one has been handled that is for sure mean a pulse in not recorded.

Could you please check what is the case?

misan avatar May 03 '20 10:05 misan

556/5000 the atmel does not crash, it is blind to another int while the interrupt is being processed. ev. helps external hardware as a counter so as not to miss a pulse, "serial" I have not observed this, although it also requires computing time. I will send you an early program in bascom with a 4-way encoder, but only P control, so very easy to understand. do you know bascom? You probably know the UHU servo, it uses the pin to the analog comparator, it somehow caches, it may be a trick.

the big difference for me i only use a memory value for the deviating position, the motor works infinitely, nothing overflows. Unfortunately I still have a different pin for your program, I will change that,

TheGermanIng avatar May 04 '20 06:05 TheGermanIng

$regfile = "m328pdef.dat" $crystal = 16000000

Config Portb.5 = Output 'LED Portd.5 = 0 Config Portb.1 = Output 'PWM Portb.1 = 0 Config Portb.0 = Output 'Kraftrichtung Portb.0 = 0

Config Portd.4 = Input 'Encoder A Portd.4 = 1 Config Portd.3 = Input 'Encoder B INT1 Portd.3 = 1

Config Portd.2 = Input 'Step INT0 Portd.2 = 1 Config Portd.5 = Input 'DIR Portd.5 = 1

Dim Encounter As integer Dim Encounter2 As Integer dim p as bit

Config Timer1 = Pwm , Pwm = 8 , Prescale = 1 , Compare A Pwm = Clear Up ', Compare B Pwm = Clear Down Pwm1a = 0 ' 0-255 2 khz

Config Int1 = Change On Int1 Getencoder Config Int0 = falling On Int0 Puls Enable Interrupts Enable Int1

Anf: IF Encounter > 2000 then Encounter = 2000 'safe overrun IF Encounter < -2000 then Encounter = -2000

Encounter2 = Encounter

if p <> Pind.2 then Encounter = Encounter + 2 p = Pind.2 endif

IF Encounter2 > 123 then Encounter2 = 123 'bei DC Motor IF Encounter2 < -122 then Encounter2 = -122 'bei DC Motor Encounter2 = Encounter2 + 127 'bei DC Motor Pwm1a = Encounter2 'bei DC Motor Goto Anf

Getencoder: '4Fachauswertung, wenn nicht nötig, besser wie Pusls aufbauen = schneller If pind.4 = 0 and pind.3 = 1 Then Incr Encounter If pind.4 = 1 and pind.3 = 0 Then Incr Encounter If Pind.4 = 0 and pind.3 = 0 Then Decr Encounter If pind.4 = 1 and pind.3 = 1 Then Decr Encounter Return

Puls: If pind.5 = 1 Then decr Encounter If Pind.5 = 0 Then incr Encounter Return End

TheGermanIng avatar May 04 '20 06:05 TheGermanIng

Hi,

If the interrupt rate is high enough, the processor may run out of stack space and that may crash it. Alternately, if no nested interrupts, a high-enough interrupt rate may prevent the main program to run, so only interrupt code is executed, which looks like the processor is doing nothing.

Several sources of concern:

  1. not sure how bascom handles the access to variables shared between interrupts and main program, that could well be causing you trouble (if, for example, there is an increase and a decrease over the Encounter at the same time).

  2. pulse and encoder interrupts seem to modify the same number (Encounter). I do not follow your logic, as they should be acting upon different variables. Encoder tells you where you are but pulses tell you where your target location is.

  3. the limitation of the range of Encounter in the main loop (Anf:) means that you might be destroying actual counts that lead the variable beyond 2000.

  4. Encounter is not only increased in the pulse interrupt but also in the main loop on Pind.2 changes ... not sure why.

misan avatar May 04 '20 08:05 misan

Thank you very much, you looked at my code very well and took your time :-) I am very interested in a solution, arduino software is new to me, I have been working with bascom for decades, but my area of ​​expertise is hardware, when I have printed circuit boards I can send you some,

I tested 2 variants, all 2 are included in the code.

  1. the int pulse: (this is part of the program is currently not active, "Enable Int0" is missing) that's simular how your prog works, I think
  2. alternative in the part "Anf:" loop, this works better, but the "Anf" loop has to run fast, I have no time for ki, kd or other, bad i don't have any drift,

Encounter variable only contains the deviating steps, (should-is) if 2000 steps are full, the motor is 400 revolutions wrong, if Encounter is 0 then the motor is exactly aligned. only limited the overflow.

encounter2 is only because the int can interrupt the main program at any time and does not already calculate half of it with a new value,

bascom reacts to Int like this: the program is interrupted at every possible point, all incoming int are ignored (blind), the code of the int is processed, the int are reactivated, the main program continues, this short time the another INT is ignored, is not made up for,

I think this is due to the avr, this has only 1 core, so it is definitely the same with arduino, no idea about the stm32 but encoder impulses and step signals sometimes come at the same time, just coincidentally.

TheGermanIng avatar May 04 '20 14:05 TheGermanIng

STM32 timers can work in very interesting ways, like quadrature inputs, so you timer can run at hardware speed (Mhz, that is millions of pulses per second) without the main program being interrupted.

But even if you do not use that feature for the encoder, interrupt response and processing speed is miles away from Arduino, so you would have system bottleneck further away.

My guess is that most of your problems are related to a too high interrupt rate for the Arduino, consider lowering encoder resolution and pulse signal max frequency (or go to a more capable platform). Cheapest STM32 is blue pill (less than $3) and a better one is Black Pill ($3-$5 depending if you go to f401 or f411). There is even microBASIC for them too.

On Mon, May 4, 2020 at 4:44 PM TheGermanIng [email protected] wrote:

Thank you very much, you looked at my code very well and took your time :-) I am very interested in a solution, arduino software is new to me, I have been working with bascom for decades, but my area of ​​expertise is hardware, when I have printed circuit boards I can send you some,

I tested 2 variants, all 2 are included in the code.

  1. the int pulse: (this is part of the program is currently not active, "Enable Int0" is missing) that's how your prog works, I think
  2. alternative in the "Anf:" loop, this works better, but the "Anf" loop has to run fast, I have no time for ki, kd or other

Encounter variable only contains the deviating steps, (should-is) if 2000 steps are full, the motor is 400 revolutions wrong, if Encounter is 0 then the motor is exactly aligned. only limited the overflow.

encounter2 is only because the int can interrupt the main program at any time and does not already calculate half of it with a new value,

bascom reacts to Int like this: the program is interrupted at every possible point, all incoming int are ignored (blind), the code of the int is processed, the int are reactivated, the main program continues,

I think this is due to the avr, this has only 1 core, so it is definitely the same with arduino, no idea about the stm32 but encoder impulses and step signals sometimes come at the same time, just coincidentally.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/misan/dcservo/issues/68#issuecomment-623506751, or unsubscribe https://github.com/notifications/unsubscribe-auth/AADRZSBKOZTID2PJI3QIKGDRP3IDJANCNFSM4MYBTFVA .

misan avatar May 04 '20 17:05 misan

or splurge and get a ~$13 NUCLEO-F411RE, it includes a proper debugger and Arduino compatible pinout if that's needed

langwadt avatar May 04 '20 18:05 langwadt

ok, i ordered 5 boards and a programmer, my first 32bit and 3.3V :-) for bascom i found it wasted too much time (100 cycles) when calling int, there is a nosave option mix with assempler, it is enough to save some registers, not all .. continue to test, i will also try a timer int one loop regularly with eg Call up 40khz to catch signals up to 20khz. I have also found very contradictory statements as to what happens if 2 int are triggered at the same time or during the runtime, there is a ranking list. I did not find microBASIC Pro cheap for sources either. we all stick to the thing :-)

TheGermanIng avatar May 04 '20 21:05 TheGermanIng

I did a STM32 Bluepill version of dcservo that uses hardware timers for reading quad encoders. It is in my repository (I made some mistakes in pin selections when designing my PCB which led me to only using 2 of 3 axes on hardware timers).

paukstelis avatar May 04 '20 21:05 paukstelis

@TheGermanIng Please note the work made by @paukstelis did pack three axes on a single Bluepill.

misan avatar May 05 '20 08:05 misan

I tested a little more: your program loses 1 step with every change of direction, my testprogram on the signal source board is very simple:

Config Portd.7 = Output 'step Config Portd.6 = Output 'dir Dim puls As long waitms 500

anf: puls = 0

Do Portd.7 = 1 waitus 25 Portd.7 = 0 waitus 25
incr puls Loop Until puls = 7200

waitms 1500 toggle portd.6 waitms 5 goto anf

that turns the motor back and forth 10 revolutions, each time a little further, you can see that very well on your "A" display,

if I make it even worse, I only go 1 step forward and one step back, the motor begin turns. if I write later without pulse x0 it will hit zero again.

anf: puls = 0

Do Portd.7 = 1 waitus 25 Portd.7 = 0 waitus 25 incr puls Loop Until puls = 1 waitms 15 toggle portd.6 waitms 5 goto anf

on the oszi you can see that well,

through you i am learning something arduino now :-) I also ordered STM8S003F3P6 test board, not only the STM32, I found it is in all cheap china tool, voltmeter for 1 € etc.

TheGermanIng avatar May 06 '20 18:05 TheGermanIng

I am not sure I follow you: Is your test code acting as a controller providing steps (portd.7) and direction (portd.6)?

On Wed, May 6, 2020 at 8:24 PM TheGermanIng [email protected] wrote:

I tested a little more: your program loses 1 step with every change of direction, my testprogram on the signal source board is very simple:

Config Portd.7 = Output 'step Config Portd.6 = Output 'dir Dim puls As long waitms 500

anf: puls = 0

Do Portd.7 = 1 waitus 25 Portd.7 = 0 waitus 25 incr puls Loop Until puls = 7200

waitms 1500 toggle portd.6 waitms 5 goto anf

that turns the motor back and forth 10 revolutions, each time a little further, you can see that very well on your "A" display,

if I make it even worse, I only go 1 step forward and one step back, the motor begin turns. if I write later without pulse x0 it will hit zero again.

anf: puls = 0

Do Portd.7 = 1 waitus 25 Portd.7 = 0 waitus 25 incr puls Loop Until puls = 1 waitms 15 toggle portd.6 waitms 5 goto anf

on the oszi you can see that well,

through you i am learning something arduino now :-) I also ordered STM8S003F3P6 test board, not only the STM32, I found it is in all cheap china tool, voltmeter for 1 € etc.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/misan/dcservo/issues/68#issuecomment-624812436, or unsubscribe https://github.com/notifications/unsubscribe-auth/AADRZSDJ3S7M5CV6ABYNNWTRQGTNPANCNFSM4MYBTFVA .

misan avatar May 06 '20 18:05 misan

yes, exactly as it is a cnc or gbrl or 3d source, if you use it e.g. 0.1mm would go back and forth long time. I switch the direction signal left, send 1 pulse, switch direction right send 1 pulse, I expect the motor to move back and forth between 2 positions or not to do anything because the deviation is so small, but x counts 1 up every time, but not down again.

If I do the whole thing with 5 pulses: I switch the direction signal left, send 5 pulse, switch direction right send 5 pulse, I expect the motor to move back and forth between 2 positions, but x counts 5 each time, but only 4 down.

I can only measure that, it has nothing to do with high speed.

I am happy that there are no problems with the encoder, I have tested a lot, it always counts correctly. my encoder has an index signal with led, i can see very well. x and motor position match.

TheGermanIng avatar May 07 '20 11:05 TheGermanIng

It is unclear to me what is the initial value of portd.7

Please note pulses are counted on the rising edge.

On Thu, May 7, 2020 at 1:15 PM TheGermanIng [email protected] wrote:

yes, exactly as it is a cnc or gbrl or 3d source, if you use it e.g. 0.1mm would go back and forth long time. I switch the direction signal left, send 1 pulse, switch direction right send 1 pulse, I expect the motor to move back and forth between 2 positions or not to do anything because the deviation is so small, but x counts 1 up every time, but not down again.

If I do the whole thing with 5 pulses: I switch the direction signal left, send 5 pulse, switch direction right send 5 pulse, I expect the motor to move back and forth between 2 positions, but x counts 5 each time, but only 4 down.

I can only measure that, it has nothing to do with high speed.

I am happy that there are no problems with the encoder, I have tested a lot, it always counts correctly. my encoder has an index signal with led, i can see very well. x and motor position match.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/misan/dcservo/issues/68#issuecomment-625184239, or unsubscribe https://github.com/notifications/unsubscribe-auth/AADRZSF2B3V7TBFEXEJY4ZLRQKIHRANCNFSM4MYBTFVA .

misan avatar May 07 '20 11:05 misan

hi, I found the solution and learned a little:-) I kicked it all: "direction last" next: attachInterrupt (1, countStep, CHANGE); // step input on interrupt 1 replaced with: attachInterrupt (1, countStep, RISING); // step input on interrupt 1

TheGermanIng avatar May 07 '20 20:05 TheGermanIng

if you use CHANGE each pulse causes two interrupts:: one on the rising and one on the falling edge. RISING will only create one interrupt per pulse and this is what I do in my code:

https://github.com/misan/dcservo/blob/master/dcservoProMicro.ino#L64

Have you seen it done otherwise?

misan avatar May 08 '20 08:05 misan

i test dcServoProtection.ino every time, have this drift problem, i try to fix, now i see exapmles dcservoProMicro.ino this is correct, i start only withe the false example, 1000 thanks, i hope the PCB come fast, i can send u example,

TheGermanIng avatar May 08 '20 08:05 TheGermanIng

Ok, thanks for pointing this out.

Unfortunately, it was a mistake on my code.

It should have said RISING instead of CHANGE. It is fixed now.

https://github.com/misan/dcservo/blob/master/dcServoProtection.ino#L62

misan avatar May 08 '20 08:05 misan

Now that I review the code of countStep I can see there is something I quite do not understand that could be causing you some more trouble: there is a "compensation" here https://github.com/misan/dcservo/blob/master/dcServoProtection.ino#L148

So, in fact, a pulse is lost in one of the direction changes (target++ and later target--). Code was contributed and I guess @sanchosk was fixing something I quite do not understand now.

Please use dcServoUNO if using an Arduino UNO.

misan avatar May 09 '20 06:05 misan