Saturday, June 15, 2013

Linear axis movement

After MF was over, I got to thinking about linear axis control and how it might have been used for the clip, instead of the rotating mechanism.

I returned to the printer carriage assembly I'd had earlier and finally got the nerve to pull out its DC motor and try to put a stepper motor in its place.  I partially succeeded.  The original DC motor had a nylon, single-flange timing pulley mounted to the motor, and the spindle was very small, like 1mm or 2mm diameter.  I had no other motors that would come close to that size.  The Teco motor that I wanted to use, because of its 1.8 degree accuracy, has a 5mm shaft, and there no easy or inexpensive way to step it down.  I also couldn't use the aluminum timing belt pulley that came with it.  It would have been great to have done that, because the belt pitch matched, but the belt width was slightly too wide for the aluminum timing pulley, and the pulley itself was of such a large diameter that it would have caused too much tension on the old belt and would have been misaligned.

Instead, I was able to use the cheap 7.5-degree paddle stepper that I'd gotten at Halted early on.  It had a timing pulley already built onto it (and impossible to remove) so I wouldn't have to get one, and wouldn't try to put the old nylon pulley onto it.  While it was less than ideal to have only 48 steps per full rotation, I wanted the experience of mounting my own motor to the assembly.  Its pulley had a 2mm pitch, so every other tooth was aligned with the original belt, and the pulley diameter was quite similar to the original.

I tried to mount the paddle motor, drilled holes, and then found I'd drilled them too big.  Learned lesson.

I found a different way to mount the motor, drilled smaller holes, and then very carefullly widened them with a round file until a mounting screw could fit into it.  Two mounting screws then self-tapped into the sheet metal and held the motor firmly.

I then added contact switches on either side to make sure the stepper didn't errantly run the carriage off the end or, really, to reduce harm to the belt and motor.

Once this was in place, I could reconnect it to the same stepper motor controls I had for the WBMD, and add some commands for running clockwise and counter-clockwise for some number of steps.  What I wanted to control:
- minimum step delay.  Going lower than this can cause you to exceed the max pulses per second (PPS) of a motor, and cause it to stall
- number of steps to move
- direction
Also, it's not entirely useful to state "clockwise" and "counterclockwise" as terms here.  That all assumes a particular orientation of the motor.  I suppose a good convention would be to assume that the direction is interpreted with the motor facing up.  That would only get in trouble for motors where the shaft runs out both sides of the motor, and that's fairly rare.

The shift register code to drive the motor assumed two pairs of wires driving motor coils in an A-B and C-D pairing.  I use a bit definition for the values 1001, 1010, 0110, 0101 and then cycle around again to the start to move a full step.  So to drive the motor I have a "where am I now" state in the range of 0..3, and then index into a four-byte array that contains the values 0x09, 0x0a, x06, and 0x05.  Going forward means increasing the state by one, and going backwards means decreasing the state by one, and in all cases mod by 4 to stay within the 0..3 range.  Then push the byte value into the upper or lower 4 bits of either shift register and send the clock signal to push the bits to the motors atomically.

I had purchased some SainSmart L298N Dual H Bridge drivers from e-Bay.  In part, I'd gotten these in anticipation of driving higher amp motors than could be handled with an L293NDE or other similar drivers.  These worked out great.  The only gripes: you have to be careful about lead length going into the screw terminals / cinches, else you can get dodgy results; and if you want to release the Enable lines, you need a second 4x1 wire housing, or you need a 4x2 to control all four motor lines plus the two enables.  I did it with two 4x1 housings, and have to keep an eye on them, else they get loose.

I found that keeping the motors enabled caused the motor drivers and motors themselves to heat up over time, so adding explicit enable and disable commands to the input tab/module was a good idea.  But more generally, it seemed that I was bumping up against the next big challenge: avoiding burning out the motors.

In this picture, you can see the two enable pins (white wires) are now set up so I can enable/disable the motor as desired.  The four wires in the middle (green, yellow, white, blue) are the motor logic control lines, and those connect to shift register outputs.  In this example, you can see I had a pair of yellows for OUTA and OUTB, and a pair of greens for OUTC and OUTD, so when this was taken, I was only doing full-stepping.

At the same time, I started learning about microstepping.  The site at stepperworld.com has a nice explanation of it.  I had to be careful in reading that site, though, because its wiring descriptions are based on 1A/2A/1B/2B configurations, where I think in terms of 1A/1B/2A/2B, so the bit positioning they have isn't correct for my wiring arrangement.

In my first foray into microstepping, I had the wrong wiring order.  That will stop you right there, especially in wave drive mode, because reduced torque, combined with misdirection of the motor is a recipe for quiet stalling.  In full stepping, you just need to make sure the pairs of wires are properly determined, so it doesn't matter if the A/B wires are in a B/A order, nor if C/D is in a D/C order.  For half-stepping, you have to get them in the correct sequence.

After some experimentation, and again much thanks to stepperworld.com, I figured out the proper order of wiring for my motors.

Getting half-stepping working also meant that I could accelerate to a faster pulse rate than I had been using before, so I changed the code to recognize a step delay max, a step delay min, and a number of steps that the motor goes through in order to accelerate to the minimum step delay.

The acceleration code is based on cosine values and some number of acceleration steps.  I now run with 64 acceleration steps in Frankenplotter, but used far fewer earlier in the game.  If, for example, I were to have to traverse 200 steps, I'd accelerate in the first 64, decelerate in the last 64, and go at minimum step delay in the steps in-between.  That method fails if the total traversal is less than 128 steps, so in those cases, I halve the number of steps to move, and use those values as the number of accel and decel steps, possibly going one step in the middle if the total step count is odd.

The cosine value table allows me to slowly move from max delay to min delay, and back again on deceleration.  Cosine runs in the range +1 to -1 in radians 0..pi, so I normalize that to a +1..0 range, multiply by the max-min delay range, and add that back onto the min delay to get a value.  All the cosine values can be precomputed (they get re-computed if the input module receives a new value for max/min/n_accel) so I don't have to rebuild them with each vector.  Also, the structure allows each axis to have its own acceleration count and delay range.


No comments:

Post a Comment