Monday, November 03, 2008

Arduino and motor control part 2


arduino linear positioning with an ink jet printer carcass from Josh Kopel on Vimeo.
I spent a bit more time messing with the ink jet guts, and finally had some success getting the linear print head positioning to work. The first challenge was that the motor kept hanging up and moving in big jerks. After burning my finger on the Arduino's voltage regulator, I finally realized that routing all the power through the Arduino was the problem. Now I am running the Arduino off of the USB cable, and I hooked a random 13.5 volt wall wart up directly to the power terminals on the motor control board. Once I got enough torque out of the motor it works quite well.

I am getting a measure of the upcoming challenges though. For one I need to add at least one limit switch so that I can establish a repeatable zero position. That should be fairly easy.

I think there may be a bigger problem dealing with the interrupts from the encoder circuit. When I try to get any feedback from Serial.print() inside my loop{} it hangs up and stutters out only an occasional message. The issue seems to be that the encoder is too precise! The encoder strip has 200 line per inch rulings, and I am currently triggering an interrupt with each 0 ->1 and 1->0 transition. This means it is generating interrupt hits 400 times for each inch it travels, and I think the Arduino is never able to get through a complete loop execution without being interrupted (I can sympathize).

I am going to try just using one of the edge transitions (i.e. low -> high) and see if that helps. It may mean that the code needs to handle the rapid interrupts more gracefully. I can see this being with a very tight loop while the motor is seeking, and then a detachInterrupt() and power down (or set to shorted out braking) while it does anything else.

In the mean time it is fun to zip the motor back and forth.

13 comments:

Dave said...

So one way to get around dealing with all those interrupts is to use a little bit of extra circuitry and two counters (I'm pretty sure you can use pins on the Arduino as counters). Then, all the encoder signals are being counted in the background and you can just ask the processor for that info whenever you need it.

More info here (even though they used a PIC, it's the same idea).

JAK said...

Thanks Dave!
I actually had looked at that link before in my google searches for info on PID control. It is a really cool setup.

It does end up being a dedicated controller though and I am hoping to use the Arduino not only for the position control, but for the "business logic" as well.

It is not at all clear from these posts, but I am preparing materials for a beginner/intermediate Arduino class. That means I am trying to get simple solutions that are "good enough", and can be understood by the students.

The other constraint is trying to use as little external circuitry as possible (for cost control).

Dreschel said...

Josh,
How about just taking in position commands over the Arduino USB? Go positive 100 steps. Go negative 25 steps. Then you are on the verge of CNC, especially if you can control multiple motors.
You can ignore the serial talk-talk while in the motor control section...

I am really very interested in this and can provide you a source for some very nice encoder enabled gear motors if you would like.
THANKS,
Bill

JAK said...

Bill,

That kind of tethered control is certainly one of the ways I have been thinking of using this code. The other is that it needs to be able to provide motor control even when the Arduino is busy doing other things. I am thinking about robots and other semi-autonomous applications.

I would love to hear more about the motors. I will say that the whole point behind my experiments is to use ink jet parts since they are an almost unlimited source of motors. And they are free!

Mike said...
This comment has been removed by the author.
Mike said...

Shoot. I couldn't find your Email address. But here is a Washington state surplus sale of a pallet of old printers, should your Arduino class need more guts. PRINTERS

Drew Batchelor said...

Josh, thank you very much for this write up, I found you're blog after gutting a Canon Pixma 4000 and buying a Adafruit motor shield and have just got it working using your code - unreliable, but working. Yay.

I notice that in the video, yours is quite noisy - mine also, any idea's on optimizing it to reduce noise? (my fiance hasn't complained yet, but I don't want to push things) looking forward to reading your next installment.
Cheers Drew

Josh Kopel said...

Drew,
Glad it helped!

The noise is mechanical resonance from the PWM signal to the motor.
I used a fairly low frequency (MOTOR12_8KHZ) to get better torque, but if you change to a higher (MOTOR12_64KHZ) or lower (MOTOR12_1KHZ) one you may be able to get outside the resonant range.

I have not gotten back to playing with this in a while, but hopefully I will soon.

Josh

oskay said...

I don't know if you're still working on this or not... but I'll post anyway. :)

This is the same style of control that we use on the CandyFab: quadrature encoders read out by AVRs, with digital PID on the PWM output(s). It *can* work very well, doing exactly what you're trying to do.

The tricky part is that this application has time-critical interrupts, and only one interrupt can happen at a time. If you really want to be able to detect every fringe, you need to remove *every* other possible interrupt source in your program. That means (1) turning off the Arduino ms timer and (2) not using the Arduino serial library. (If you have other sneaky routines that are based on interrupts, you can avoid those as well.) You can replicate the function of either (or both) of these using interrupt-free functions, and then things will work happily.

(The ms timer can be replaced by a free-running timer that you poll occasionally, and the serial interface can also be replaced by just polling the serial hardware at a regular pace.)

bjoern said...

Hi Josh, thanks for your reply on the other post, and fir directing me here. Just to get an idea, how many interrupts per second are you currently getting?

Digital_Sin said...

I've been working on my old inject HP printer, it also comes with the agilent optical encoders identical to yours. When I first connected them to a 5v source the LED was visibly red, but after a few seconds it started to fade away, now it doesn't light up at all.

I've tried the other agilent encoder but this time on 3.3 volts, did the same thing! Are the LEDs inside them fried? would suck because now the printer carcass is worthless...

Josh Kopel said...

@Digital_Sin in general you should have a resister in series with your LED. While the value is dependent upon the specs of the individual LED, you can usually just use a 1k to test with. Without it you definitely run the risk of burning out the LED.

Jason W said...

Just want to say thanks for setting me to the right direction of working on my project.