programming model for jogging?

731 views
Skip to first unread message

Jon Magill

unread,
Aug 22, 2012, 8:29:25 PM8/22/12
to accels...@googlegroups.com
Hi -- I am very new to Arduino and new to AccelStepper, so trying to learn a lot of things at once, including starting over again with learning C.

I am in the process of designing a two motor system, with one linear axis and one rotary axis, with a very simple 2-line LCD keypad user interface (UI). Right now I am experimenting with the DF Robot LCD Keypad Shield, and using the keys on that. I also have a 5-way tact switch from Adafruit if a joystick model makes more sense for "jogging" while displaying on an LCD.

My basic question has to do with the fact that I need to get some setup info from the user in the form of an initial position and a final position, which the user will "jog" to, which will then be used by the Arduino/chipKIT and AccelStepper to carry out a repetitive process. I was thinking of asking them to do something like:

JOG TO START   (position)
<<  [SAVE]  >>

Where "<<" and ">>" are intended as the left and right keypad buttons, and SAVE is for the select button.

Then ask them to:

ROTATE TO START (position)
<<  [SAVE]  >>

Then ask them to JOG TO FINAL, and ROTATE TO FINAL, as above. In theory the jogging process would let me collect 4 positions, say x1, theta1 and x2, theta2.

Is there some sample code using AccelStepper that would allow both jogging a motor to a desired position, saving (or zeroing?) that position, then allowing a user to move to another position while keeping track of the distance moved, and then store and repeat the process? (For simplicity I'm leaving out a bunch of steps, but obviously there would be a rewind process to get back to the initial position, etc.)

Have other people tried jogging with some distance or time per button press? Or should I do it in a loop, checking frequently, that keeps moving while the button is still down?

Is there some preferred way using AccelStepper to count or track distance moved in something like the jogging loop above?

I am stymied by a programming model for jogging while keeping track of location in some simple, sensible way.

Any help or ideas would be appreciated.

--Jon

Mike McCauley

unread,
Aug 22, 2012, 9:51:47 PM8/22/12
to accels...@googlegroups.com, Jon Magill
Hi,

we wont be able to design your code for you, but:

if jogging is really just a small change in the desired position, then I would
suggest you have your majn loop always call accelstepper.run(), but just
change the target position by a small amount whenever the user jogs.

Then when the user zeros, call setCurrentPosition(0). From then, the current
position will be considerd as the origin.
--
Mike McCauley mi...@open.com.au
Open System Consultants Pty. Ltd
9 Bulbul Place Currumbin Waters QLD 4223 Australia http://www.open.com.au
Phone +61 7 5598-7474 Fax +61 7 5598-7070

Radiator: the most portable, flexible and configurable RADIUS server
anywhere. SQL, proxy, DBM, files, LDAP, NIS+, password, NT, Emerald,
Platypus, Freeside, TACACS+, PAM, external, Active Directory, EAP, TLS,
TTLS, PEAP, TNC, WiMAX, RSA, Vasco, Yubikey, MOTP, HOTP, TOTP,
DIAMETER etc. Full source on Unix, Windows, MacOSX, Solaris, VMS, NetWare etc.

Sandy Noble

unread,
Aug 23, 2012, 9:39:40 AM8/23/12
to accels...@googlegroups.com
I think Mike's solution is right. Whether to have motor.run() in the
main loop or not will probably depend on how many other events are in
that loop that you want to still happen while it's jogging. So you
could have something like

loop()
{
checkIfButtonsWerePressed();

if (jogButtonWasPressed)
{
motor.move(10); // increment the target position by your jog size
while (motor.distanceToGo() != 0)
{
motor.run();
}
jogButtonWasPressed = false;
}
}

Which I quite like because it means that jogging takes place in little
distinct packets, with nothing else interfering. It means you can't
do anything with it until it's finished it's move. Normally that
would be frowned up (blocking = bad!), but in this interactive case it
might be desirable.

An alternative might be:

loop()
{
checkIfButtonsWerePressed();

if (jogButtonWasPressed)
{
motor.move(10); // increment the target position by your jog size
jogButtonWasPressed = false;
}

motor.run();
}

Which seems more elegant, and would reduce the number of places that
.run() is called. The problem with this is that if your motor speed
was slow and you tapped 10 times fast, then you could end up setting
the target to 100 when you only meant 10. And you'd just have to wait
for the motor to finish before you knew where it was going to end.
You have to wait with the first version too, but you have more
feedback about what's happening. On the other hand, if each jog moved
a sled 1mm, then it would be quite handy to know that if you hit it 10
times fast, then you could leave it and rely on it moving 10mm.
Whereas with the first one, you'd have to tap, wait, tap, wait, tap,
wait.

loop()
{
// read the buttons - how you do this depends on what your circuit
is, what library you're using etc
checkIfButtonsWerePressed();

// if a button was pressed, change the target position of the motor
if (jogButtonWasPressed)
{
motor.move(10); // increment the target position by your jog size
while (motor.distanceToGo() != 0)
{
motor.run();
}
jogButtonWasPressed = false;
}
else if (homeButtonWasPressed)
{
motor.setCurrentPosition(0);
motor.moveTo(0);
homeButtonWasPressed = false;
--
Sandy Noble

Jon Magill

unread,
Aug 24, 2012, 2:39:46 AM8/24/12
to accels...@googlegroups.com
Thank you Mike and Sandy for the comments. As I said, I am just starting out. I have two motors running basic code at the moment, but am really trying to sort out how to use AccelStepper in this interactive mode, and reading the forum posts so far I haven't seen too many examples where there is user interaction. The thread from the end of May (Knob control using the accelstepper library), that Mike added to the samples sort of helped. But the differences in using a one-time adjustment on a pot vs. holding a button (or joystick) down to jog for an extended time/distance is where I was having trouble seeing how to structure the code.

The subtleties of where to call accelstepper.run/motor.run are among the things I am trying to understand, and Sandy's examples of two ways to call .run inside loop() give me some ideas to try.

I think I was imagining jogging within a while loop, e.g.

while (jogRightButton != 0)
  {
  motor.move(10);  //or whatever the appropriate distance is after testing
  motor.run();
  }

I assume that the motor would keep running if the user kept the button pressed, maybe with some chugging, depending on the distance value used. And I think because this is an interactive process, it is ok to use a blocking call, because I'll keep jogging until they let go of the button at the desired location.

Real jogging on CNC machines usually takes input from an encoder, and/or a range multiplier. I was sort of hoping I could get a similar effect, where holding a button longer, accelerated the motor, to cover longer distances. After I get the basic loop working, perhaps some sense of duration of the button press can be used to increase the speed/distance moved.

I'm not at home right now, but clearly need to test some code for speed and distances to see what is appropriate once I get back to my bench.

Thanks again for the suggestions.

--Jon

Sandy Noble

unread,
Aug 25, 2012, 5:40:07 AM8/25/12
to accels...@googlegroups.com
Jon, with the code

while (jogRightButton != 0)
{
motor.move(10); //or whatever the appropriate distance is after testing
motor.run();
}

each time that while loop is executed (so for as long as the button is
held down), the motor would be signalled to move 10 steps, but would
move for a maximum of one step. So the target position could easily
accelerate away from the actual position - if it was held down for 10
cycles then the target would be 100 but the furthest the motor could
possibly have moved would be 10 steps. Remember .run() isn't a
blocking call. If you used .runToPosition() instead of .run(), that
would do it though. It would set the target, then pause while it
moved the motor before cycling round to see if the button was still
pressed.

>>> Real jogging on CNC machines usually takes input from an encoder, and/or
>>> a range multiplier. I was sort of hoping I could get a similar effect, where
>>> holding a button longer, accelerated the motor, to cover longer distances.
>>> After I get the basic loop working, perhaps some sense of duration of the
>>> button press can be used to increase the speed/distance moved.

Aha though, I see what you mean here - the loop above could be used for this:


while (jogRightButton != 0)
{
motor.move(100); //High value so it has some room to accelerate
motor.run();
}

// then when the button is released, kill the motor dead!
motor.setSpeed(0);


Maybe?
--
Sandy Noble

Jon Magill

unread,
Aug 26, 2012, 2:06:55 PM8/26/12
to accels...@googlegroups.com
Hi Sandy,

I'm sitting in the airport between flights and can hardly wait to get home to test some ideas in code with motors now!

It is so helpful to get your feedback and insiights, as you clearly have a firm grasp on how AccelStepper works (I love your polargraph!!). I would have probably written the loop and stared at it wondering why it was only taking one step! Duh. Thanks again.

I'm wondering, and will experiment with it soon to see, if the longer run in the while loop will jerk to a stop when the button is released? From what I've read of the behavior, it sounds like the beginning of the while loop will let AccelStepper ramp up, but then not have time to decel when the button is released. And in truth, I'm not really sure what the desired jogging behavior is. I am sure I will find the speeds and accel settings that will make sense with the jogging, which in this case is sort of a way to get user input, then adjust the settings for the actual running cycle.

I'll know more later...

--Jon

Sandy Noble

unread,
Aug 26, 2012, 2:45:53 PM8/26/12
to accels...@googlegroups.com
Aye, I think that's the real problem with that way of doing it - it
means going around accelstepper's main feature, and coming to a halt
with a bump. The alternative though, as far as I see it, is to do
something like

motor.moveToNewPosition(motor.currentPosition()+20); // 20, enough
steps to decelerate a bit

instead of the .setSpeed(0), and that might give a slightly softer
landing, but it'd make it hard to be very precise with it, because it
would always overshoot a little. Probably depends on the likely speed
of your movement in the first place whether that would make a
difference though. Might find human reaction times are the limiting
factor and 20 steps here or there are within your margin for error.

Thank you re polargraph :) I'm not an expert with accelstepper by any
means though - but I do think it is what made the polargraph so
workable - soft-start and gentle stop is important when you're
swinging weights around on bits of string.

cheers!
sn
--
Sandy Noble
Reply all
Reply to author
Forward
0 new messages