Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drift #68

Open
TheGermanIng opened this issue May 3, 2020 · 19 comments
Open

Drift #68

TheGermanIng opened this issue May 3, 2020 · 19 comments

Comments

@TheGermanIng
Copy link

TheGermanIng commented May 3, 2020

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 ?

@misan
Copy link
Owner

misan commented May 3, 2020

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?

@TheGermanIng
Copy link
Author

TheGermanIng commented May 4, 2020

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
Copy link
Author

$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

@misan
Copy link
Owner

misan commented May 4, 2020

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.

@TheGermanIng
Copy link
Author

TheGermanIng commented May 4, 2020

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.

@misan
Copy link
Owner

misan commented May 4, 2020 via email

@langwadt
Copy link

langwadt commented May 4, 2020

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

@TheGermanIng
Copy link
Author

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 :-)

@paukstelis
Copy link

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).

@misan
Copy link
Owner

misan commented May 5, 2020

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

@TheGermanIng
Copy link
Author

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.

@misan
Copy link
Owner

misan commented May 6, 2020 via email

@TheGermanIng
Copy link
Author

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.

@misan
Copy link
Owner

misan commented May 7, 2020 via email

@TheGermanIng
Copy link
Author

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

@misan
Copy link
Owner

misan commented May 8, 2020 via email

@TheGermanIng
Copy link
Author

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,

@misan
Copy link
Owner

misan commented May 8, 2020

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
Copy link
Owner

misan commented May 9, 2020

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants