Welcome! Log In Create A New Profile

Advanced

Marlin for X-Y DC motor (interrupts issues and performance)

Posted by sgawad 
Marlin for X-Y DC motor (interrupts issues and performance)
September 19, 2013 08:38PM
Hello All,

This seems to be my first post here and I am sorry if I missed a piece of info in this forum (or elsewhere) which could be of use.
Essentially I got from a dump 2 very nice x-y axes with 24V DC motors and 500encoder steps / rev = 500 encoder steps/mm.

I started reading the Marlin code and understanding planner, stepper.cpp, etc, then the arduino PID library (also excellent read) and some quadrature decoder code found here: [www.hessmer.org]
Merging them all together within Marlin proved a bit less successful unfortunately.
(Btw if Zalm, Hessmer and Beauregard get together once in a restaurant, just get a picture of you three, dinner is on me!)

I should say that I am using an arduino Mega2560 and plan to target a mix of the RAMPS 1.4 hardware mated with the arduino motor shield v3 and placing the few extra encoder pins so I'll still be able to fit the 128x64 lcd screen in the future.
Reducing the amount of pins conflicts is quite a challenge but I think I got it (almost) right now. For some reason I had to change the timer for the stepper interrupt to timer4 too but that's out of focus.

Now here is the problem:
1. If I write a simple code to move my axis around even at full speed, the 2 encoder interrupts for x and y have no problem capturing the steps.
2. As soon as I try to get these interrupts code into Marlin I miss about 2/3 of the encoder counts.

Reading a bit about interrupts in AVR I understood that connecting the interrupts to the highest priority pins wasn't just enough.
If any of the serial, TWI (for the LCD) or other interrupts fired my counts would be lost.
So I tried to ISR(XXX_vect, ISR_NOBLOCK) the other interrupts too enable nested interrupts, but marlin just hangs.
One step further seemed to require completely disabling the TWILCD, still missing 2/3 of the counts.
update: (using the LCD screens per se seems not to be the issue since I added it to my test code and still can catch all the ticks

Now all of this doesn't even include the PID code yet.
My idea (probably a very bad one) was to keep using the stepper timer since I still wanted to move the E and Z axis with (steppers) according to the planner, and to reuse the constantly updating X and Y stepper position as the PIDs position Setpoints, and thus maintaining the E, Z, X Y in sync by the setpoints.
acc_step_rate with some scaling should be usable as the speed setpoint during the acceleration, hold and deceleration

It is probably very unreasonable to have the PID recompute every pseudo stepper step, so for now I decided to cheat Marlin in telling him my axis actually had 125 encoder step/mm so as to reduce it by a factor 4.
Meaning that the timer would actually fire every 4 encoder interrupts.
Added to that I would benefit from the code already in place that does multiple steps at high speeds and thus somehow reduce the computation. The drawback is the non constant time between the stepper timer interrupts but with a full form of the PID timeframe it should be ok, maybe....

So I would like some feedback on 2 things.
1. First what is preventing my encoder to work? which other interrupt is the making me loose steps and how could I make the encoder interrupts not only higher priority but nested.
2. What are your suggestions for the PID I could implement yet another interrupt with a constant time. but I like the idea of using the same time pace as is used for the original stepper code and sync with the E and Z this way. I couldn't really try my idea because of issue 1 yet.

I am also new to github still if you like to see some nice code turned into a big mess you can find my fork of Marlin here: [github.com]

P.S. I also looked at the possibility of using a dedicated decoder IC but the number of pins is prohibitive, I think. otherwise I could use 2 megas one for Marlin and one as a decoder but I'd prefer not to if possible. (not sure by which mean they should communicate together anyway.)

Thank you for reading this !!!!

Edited 2 time(s). Last edit at 09/21/2013 03:22PM by sgawad.
Re: Marlin for X-Y DC motor (interrupts issues and performance)
September 20, 2013 09:46AM
Quote

If any of the serial, TWI (for the LCD) or other interrupts fired my counts would be lost.

Shouldn't happen. Even if interrupts are locked for a moment, they fire as soon as they're unlocked.

Perhaps you should have a look at Teacup firmware. Cleaner implementation, each used interrupt well known and thought about and doesn't use this confusing Arduino library.


Generation 7 Electronics Teacup Firmware RepRap DIY
     
Re: Marlin for X-Y DC motor (interrupts issues and performance)
September 20, 2013 10:16AM
First thank you for your reply,

I think you are right if only 1 tick occurs during the interrupt, then I won't loose any steps. But what if the interrupt duration covers 2 or more ticks?
My understanding is that my decoding interrupt will only be run once and count 1 tick.
Actually worse, if I am delayed enough it is possible I think that the state of channel B (used to find the direction, channel A being the interrupt pin) would switch in the meanwhile and I'd thus measure a tick in the wrong direction.
If I presume that I'd like to move at 50mm/s max (is that a reasonable speed?) then I'd be generating 25k interrupts /s for 1 axis so 50 k if I take some margin... so that's 20ns if any interrupt in the code takes longer than that I think I am in no luck.
So I guess I could use some profiler data of the different firmwares or developper experience or
simply put a few instructions here and there to find the offending interrupts.

I'll take a look at Teacup, if the interrupts are shorter it's clearly a plus but I like Marlin's features too winking smiley.
Re: Marlin for X-Y DC motor (interrupts issues and performance)
September 22, 2013 12:08PM
Quote

But what if the interrupt duration covers 2 or more ticks?

You have to make sure this can't happen. All possible interrupt blockings and your interrupt routine together must not exceed this time.

Quote

I'd be generating 25k interrupts /s for 1 axis so 50 k if I take some margin

That's quite a lot already. 16 MHz / 50 kHz = 320 clock ticks. A single 32-bit integer division takes longer.

Have a peek at Teacups' ACCELERATION_CLOCK code on how to disconnect speed computations from step pulses. Or in your case, encoder pulses. Calculating/adjusting speed 500 times a second is easily enough, mechanics is a lot slower.


Generation 7 Electronics Teacup Firmware RepRap DIY
     
Re: Marlin for X-Y DC motor (interrupts issues and performance)
September 22, 2013 04:59PM
Hi,

I am deep into dda.c and timer.c since yesterday. I had to switch timers again due to pin conflicts with the DC motor shield (blah...).
I see the difference in code lightweightness with the marlin for sure winking smiley. I'll then try to have a few tests at full speed and see if the encoder code also skips ticks while having tea.

The situation is actually worse than what I thought, if the encoder interrupts is delayed by a mere quarter of the 25kHz cycle, the channel B will be read incorrectly, resulting in a tick in the wrong direction so it's actually more 100kHz so 160 CPU clocks (including the interrupt code)...
That is if I am targeting 50mm/sec speed on 1 axis.(with 500 ticks/mm)

I am thinking more and more that I'll have to use a dediacted motor controler board second mega2560 for the XY axes PWM + encoders.

Or wait for a port of teacup and ramps for due winking smiley
I have just seen that the DUE controller has one dedicated quadrature decoder... (or is it two? Apparently the documentation mentions the decoder circuit uses TCLK0,1and 2 but is there one also in front of 3,4,5 ?)

What I am not sure yet is if I should:
1. Integrate the position and speed PID on the mainboard and fetch position information and send back the speed output (PWM values) via some serial communication to the motor controller.
2. But I think that it's nicer (more elegant) to have the PID on the motor controler board, just needs to be have the PID interruptible and carefull with the divisions...

By the way you mentioned the divisions as a way to waste some useful cycles but wouldn't lenghty divisions be interruptible?

Edited 1 time(s). Last edit at 09/22/2013 05:42PM by sgawad.
Re: Marlin for X-Y DC motor (interrupts issues and performance)
September 23, 2013 07:50AM
Quote

1. Integrate the position and speed PID on the mainboard and fetch position information and send back the speed output (PWM values) via some serial communication to the motor controller.

There's no point in sending PWM values to some external board. Send it right to the PWM/timer register and everything else is done by the timer subcircuitry on the ATmega, zero CPU cycles involved.

Quote

2. But I think that it's nicer (more elegant) to have the PID on the motor controler board, just needs to be have the PID interruptible and carefull with the divisions...

Then you have to find a communications protocol with accurate timing to start/stop motors synchronized.

Quote

Or wait for [...] ramps for due

I thought your point is to use DC motors? If you look for a more affordable ARM-based controller, there's also Gen7-ARM. It works, two Teacup ports exist (that's great), still the code needs some polishing (which is the nature of young ports).


Generation 7 Electronics Teacup Firmware RepRap DIY
     
Re: Marlin for X-Y DC motor (interrupts issues and performance)
September 23, 2013 01:47PM
Yes you are right, the important thing is to have the encoder interrupt undisturbed by the other peripherals and main calculations. All lengthy calculations should be done on the mainboard...

case 1 All calculations (stepping + PID) I''l just transmit "values" to be put on the PWM on the Motor controller board
Motor controller does the encoder work and drives the motors that's all.

case 2 PID is implemented on the Motor controller board and I just transmit the setpoints from the mainboard.
speed /error calculations done on the MC board.

You are right!!! the acceleration_clock would allow for much simpler PID code because of the constant time. Thank you for pointing me to it. Do you plan to merge it at some future point or is this best left in a branch?

Yes I have X-Y axis as DC motor but I still need Z+E1+E2(eventually) + heatbed, nozzle, SD card,LCD so it's easier to use a halfly populated RAMP I think... ( which I already have).

Edited 2 time(s). Last edit at 09/23/2013 06:28PM by sgawad.
Re: Marlin for X-Y DC motor (interrupts issues and performance)
September 24, 2013 09:21AM
Quote

Do you plan to merge it at some future point or is this best left in a branch?

I plan to make it the default as soon as it works reliable. Currently it isn't, endpoint time and endpoint position sometimes miss by a few steps. One possible solution is probably to look at the current position while doing speed calculations. This is what you'd do anyways.


Generation 7 Electronics Teacup Firmware RepRap DIY
     
Re: Marlin for X-Y DC motor (interrupts issues and performance)
October 04, 2013 09:05PM
Hi,

I just got through some new trials and I have been working in parallel with Marlin and Teacup to compare performance for both.

Starting with Marlin first for those who are interested:
- First I changed most of the writeanalog and fastreaddigital in the stepper and encoder interrupts to macros similar to the ones in Teacup.
- Then I reduced the "pseudo" step/unit to 10/mm i.e. the stepper interrupt is only called every 50 encoder ticks in my case (500 ticks/mm)
At this point although it isn't perfect the performance got from missing 2/3 of the ticks to 90% registering. Quite sure it's far from good but it's some progress.
I also tried moving a sei() around in marlin timer stepper interrupt which would just result in troubles.(motor never stopping, etc..)

For Teacup I just included the encoders interrupts and initialisations, moved the timers around to be able to use timer1a and timer3c for the arduino motorshield v3 (since I HAVE to use pin 3 and 11 for the PWMs).
Then I just included some code which would move the motor at full speed (according to the planned direction) and measuried the actual distance and compared against the encoder registered distance.

I got about 90% immediately using the original 80368 steps/m which is 8 times more precise than the marlin for the same observed performance.
then I changed to 10000 steps/m and got a similar performance of 90% so rouglhy 100mm moved would only count as 90mm. sad smiley

This is strange but it seems the other 10% can't be gained easily by reducing the number of calculations in Teacup whereas it made quite a difference in the Marlin Firmware (maybe you have a better idea)
I don't know the Teacup so well yet, so maybe I am not actually changing the calculation workload by changing the STEPS_PER_M_X value.

All that in comparison with some other little code I just wrote to check if there was a chance.
If the mega is doing just decoding and driving the I2C to (show the encoded position on an LCD), then all ticks register without skips when
moving the whole thing at full speed around with a joystick.

In any case it seems that the Mega is not fast enough to decode 2 DC motors and also have other interrupts running especially those doing the dda.
Even if 10% seems low, some further headroom is actually recuired since I don't plan to miss encoder ticks at all.

So currently it seems that using a dedicated mega for the decoding would be fine and then communicating positions through I2C or else.
The encoder mega could probably also take the motor shield so this would also solve the RAMPS vs motorshield pins issues.
Re: Marlin for X-Y DC motor (interrupts issues and performance)
October 05, 2013 04:51AM
To me it looks like it's more a problem of getting interrupt priorities sorted. I can happily give you write access to the Teacup repository, then you can bring in your code in a branch to allow more people to look at it.


Generation 7 Electronics Teacup Firmware RepRap DIY
     
Re: Marlin for X-Y DC motor (interrupts issues and performance)
October 05, 2013 09:12AM
Hi,

The int2 and int3 hardware interrupt which I am using for the encoder are to the extent of my knowledge the higest priority in the system so I am not sure how I could further improve on interrupt priority.
I can only thank you for proposition, I am not sure my "code" can be named "code" at this point more something like a hack to be able to benchmark issues.
I would be happy to spend some time to merge back to the main (as a branch) when I'll have something noteworthy which is not the case yet IMO.
For now the code is available on my Teacup fork (well maybe tonight I need to sync it). [github.com]

Second is that there is no easy way for people to reproduce those tests without the same or similar hardware (arduino motor shield + 24VDC motors + encoders 500ticks/rotation). I am sure there are they just probably are very quite or haven't stumbled on this thread yet, or I am writing too much and get people scared.
But yes I agree that maybe someone more than just the two of us should participate in the discussion because I am unsure of the next step and any experienced input could help.

p.s. I do actually have a colleague which will be joining the effort as he has identical hardware and just got the motor shield as well.
Re: Marlin for X-Y DC motor (interrupts issues and performance)
October 06, 2013 06:20AM
I'd start with removing interrupts (#ifdef'ing them out) until it works reliably. Then add them back one by one to have a closer look at the one which brings in the failure.

That said, if you have all DC motors, you probably don't need the step interrupt anyways. STEPS_PER_M has no meaning unless you actually step something.


Generation 7 Electronics Teacup Firmware RepRap DIY
     
Re: Marlin for X-Y DC motor (interrupts issues and performance)
October 10, 2013 05:44PM
Hello,

Yes as I mentioned I plan to have Z axis and Extruder(s) on stepper so I would like to keep some synchronism through the stepper interrupt.
Basically the plan is to update the positional setpoint from planner + stepper interrupt to get a current position value. Same for the speed setpoint which is also updated with the stepper interrupt.

The problem is that I can't really remove the communication interrupt (hard to debug without it)
and clearly the setpper interrupt seems to be te problem here, there are no others "long" interrupts that I can see.

I will try the ACCELERATION CLOCK just to see if it works better.

Cheers.
Re: Marlin for X-Y DC motor (interrupts issues and performance)
October 11, 2013 05:07AM
Quote

The problem is that I can't really remove the communication interrupt (hard to debug without it)

You can to a number of enqueue() right in mendel.c after init(). This should give you movements without any communications.

Quote

and clearly the setpper interrupt seems to be te problem here, there are no others "long" interrupts that I can see.

There's temperature regulation. Reading thermistors and forming a well thought PWM value for the heaters requires quite a bit maths. Defining zero heaters removes some of the code, probably not all of it.


Generation 7 Electronics Teacup Firmware RepRap DIY
     
Sorry, only registered users may post in this forum.

Click here to login