Skip to content

Latest commit

 

History

History
247 lines (160 loc) · 13.3 KB

Using-Motors-Run-Limited.md

File metadata and controls

247 lines (160 loc) · 13.3 KB

This page introduces the time and position run modes of the ev3dev motor driver. It's part of a series of wiki pages that describe using motors with the EV3 running ev3dev that includes:

Table of Contents

While the forever run mode is useful, sometimes you want to tell the system to run a motor for a fixed amount of time, or to some specific position. It's relatively easy to run at full power for n milliseconds, but that's not always helpful. Some robot mechanisms do not react well to being yanked up to full speed and then brought to an abrupt halt.

For these cases, a more general mode of operation that includes a ramp-up to a specified speed, and then a ramp-down to zero has been developed. In fact, there are 2 ramp-enabled run_modes. The first is time and the second is position.

We'll start with the time description, then move on to a general description of how the ramp_up and ramp_down attributes are defined, and close out the note with runmode set to position.

The examples below all assume we're starting from where we left off in the previous tutorial - Using Motors - Run Limited.

The run_mode attribute default is forever, but you can simply write time to it. So let's go ahead and do that to get started.

user@ev3dev:~$ echo  time > /sys/class/tacho-motor/tacho-motor2/run_mode
user@ev3dev:~$ echo   off > /sys/class/tacho-motor/tacho-motor2/regulation_mode
user@ev3dev:~$ echo coast > /sys/class/tacho-motor/tacho-motor2/stop_mode
user@ev3dev:~$ echo    40 > /sys/class/tacho-motor/tacho-motor2/duty_cycle_sp
user@ev3dev:~$ echo     1 > /sys/class/tacho-motor/tacho-motor2/run

What happened? Nothing. That's because we have not told the motor how long it should run for yet!

We have gone over the duty_cycle_sp in a previous section to set the power level that can be delivered to the motor.

It stands to reason that there should be an attribute that tells the motor driver how long it should run for, and that's exactly what time_sp does for us. As soon as we set a value and tell the motor to run, it will run for time_sp milliseconds from that point in time.

user@ev3dev:~$ echo 0    > /sys/class/tacho-motor/tacho-motor2/run
user@ev3dev:~$ echo 2000 > /sys/class/tacho-motor/tacho-motor2/time_sp
user@ev3dev:~$ echo 1    > /sys/class/tacho-motor/tacho-motor2/run

Nice! The motor runs for exactly 2 seconds - but it coasts to a stop. We know how to fix that.

user@ev3dev:~$ echo brake > /sys/class/tacho-motor/tacho-motor2/stop_mode
user@ev3dev:~$ echo    1  > /sys/class/tacho-motor/tacho-motor2/run

And note that the time_sp does not change, even after the run. That means you can easily tell the motor to run for the same amount of time without having to reload time_sp.

The time_sp works well, but has the disadvantage of starting and stopping somewhat suddenly, and that's where ramp_up_sp and ramp_down_sp come in to help us.

The ramp_up_sp attribute is the number of milliseconds that it would take to ramp the motor up from 0% to 100% power.

The ramp_down_sp attribute is the number of milliseconds that it would take to ramp the motor down from 100% to 0% power.

What's really neat about this is that no matter what your duty_cycle_sp or pulses_per_second_sp is, the ramp rate never changes. This is super useful when you are tuning your motor control operation. In other words, the slope of the ramp stays constand no matter what the final power or speed setting is.

As an experiment, we can try this command that should ramp the motor up to 100% power for 1000 msec (1 sec), then ramp the motor back down to 0% for 1000 msec.

user@ev3dev:~$ echo brake > /sys/class/tacho-motor/tacho-motor2/stop_mode
user@ev3dev:~$ echo  1000 > /sys/class/tacho-motor/tacho-motor2/ramp_up_sp
user@ev3dev:~$ echo  2000 > /sys/class/tacho-motor/tacho-motor2/time_sp
user@ev3dev:~$ echo  1000 > /sys/class/tacho-motor/tacho-motor2/ramp_down_sp
user@ev3dev:~$ echo   100 > /sys/class/tacho-motor/tacho-motor2/duty_cycle_sp
user@ev3dev:~$ echo     1 > /sys/class/tacho-motor/tacho-motor2/run

Now let's say that 100% power is too fast for our operation, and we change the duty_cycle_sp to 50 - what will the motor do? Think about it for a few seconds...

The ramp_up_sp and ramp_down_sp attributes have not changed, so the ramp rates are the same, but the duty_cycle_sp is now half of 100% - so it will take half as long for the increasing speed to hit the setpoint!

The motor should ramp up to 50% power in 500 msec, run at 50% for 1000 msec, then ramp the back down to 0% in 500 msec.

user@ev3dev:~$ echo    50 > /sys/class/tacho-motor/tacho-motor2/duty_cycle_sp
user@ev3dev:~$ echo     1 > /sys/class/tacho-motor/tacho-motor2/run

Notice that we only had to change the speed_setpoint - all the other values stay the same.

Similarly, if we change the ramp_up value to 500 then the motor will only spend about half that time getting to 50% power, or 250 msec.

user@ev3dev:~$ echo   500 > /sys/class/tacho-motor/tacho-motor2/ramp_up_sp
user@ev3dev:~$ echo   500 > /sys/class/tacho-motor/tacho-motor2/ramp_down_sp
user@ev3dev:~$ echo     1 > /sys/class/tacho-motor/tacho-motor2/run

Experiment a bit with the time based run_mode to get the hang of using it.

The position run mode is how you get precise, repeatable servo motions from the tacho motors attached to the EV3 - this is arguably the feature that set the LEGO NXT apart from the RCX, and with ev3dev there is unprecedented control of the motor operation.

This run_mode benefits from having regulation_mode set to on for more stable low_speed operation, and it's a good idea to also set stop_mode to make sure that the end point is hit more accurately.

NOTE: Check to see if position modes work at all when the regulation_mode is off.

The ev3dev motor driver will take into account any overshoot or undershoot in the final position of the motor before the next run to a specified position.

For the ultimate in accuracy, you can also set hold_mode to on - this will effectively snap the motor into the final position and hold it there - very handy if you're trying to hold an arm in a fixed position.

Finally, we should note that when using the position run mode, some tuning will be needed to get the ramp and speed setpoints correct. For some combinations of speed and position and ramp time, you'll see that the motor either overshoots the mark (high speed or short ramps) or slowly creeps up to the final position (low speed or long ramps).

Be prepared to experiment and get awesome results!

If you have been following along and running the motors, the position of your motor will be at some non-zero value, you can check it like this:

user@ev3dev:~$ cat /sys/class/tacho-motor/tacho-motor2/position
8527

What do you think will happen the first time we ask the motor to go to a setpoint, for example 360? Think for a minute...

Right - it will start spinning from 8527 to 360 - which may not at all be what we intend to do. So, how can we fix this?

The position attribute was advertised as read-only. In fact, you can write to it, and the new motor position will be reflected in the value you write. For the next section on the position_setpoint, we'll want the starting position of the motor to be 0 - so let's set it up that way...

user@ev3dev:~$ echo 0  > /sys/class/tacho-motor/tacho-motor2/position
user@ev3dev:~$ cat       /sys/class/tacho-motor/tacho-motor2/position
0

We'll assume that you've got the ramp_up_sp and ramp_down_sp concepts well in hand. The position` mode uses these values to control the departure form the current position and the approach to the new position.

Also make sure you've zero'ed the current motor position as described in the previous section.

Here's a set of instructions to set up a motion to put the new motor position at 360 - remember, the tacho motor counts pulses, not degrees. It just happens that the engineers at LEGO designed the motors to count 360 pulses for a full circle!

We'll do this in two parts, resetting the motor position and setting up the motion characteristics that will not change, like the run, stop and regulation modes and the ramp and speed setpoints:

user@ev3dev:~$ echo        0 > /sys/class/tacho-motor/tacho-motor2/position
user@ev3dev:~$ echo position > /sys/class/tacho-motor/tacho-motor2/run_mode
user@ev3dev:~$ echo    brake > /sys/class/tacho-motor/tacho-motor2/stop_mode
user@ev3dev:~$ echo       on > /sys/class/tacho-motor/tacho-motor2/regulation_mode
user@ev3dev:~$ echo      300 > /sys/class/tacho-motor/tacho-motor2/ramp_up_sp
user@ev3dev:~$ echo      300 > /sys/class/tacho-motor/tacho-motor2/ramp_down_sp
user@ev3dev:~$ echo      500 > /sys/class/tacho-motor/tacho-motor2/pulses_per_second_sp

Then set up the move to 360 and execute it:

user@ev3dev:~$ echo 360 > /sys/class/tacho-motor/tacho-motor2/position_sp
user@ev3dev:~$ echo   1 > /sys/class/tacho-motor/tacho-motor2/run

Cool! The motor moves one full circle. And if we ask the motor to run again, what happens?

user@ev3dev:~$ echo 1  > /sys/class/tacho-motor/outB:motor:tacho/run

Nothing, because the motor is already at the target position. It might wiggle a little bit because we're not in hold mode. You need to give the motor a new position_setpoint to get it to move, like this:

user@ev3dev:~$ echo 720 > /sys/class/tacho-motor/tacho-motor2/position_sp
user@ev3dev:~$ echo   1 > /sys/class/tacho-motor/tacho-motor2/run

One thing to also keep in mind is that the sign of the pulses_per_second_sp is ignored in the position run mode. It's too much of a hassle to ask the programmer to keep track of whether the position_setpoint is in the positive or negative direction, so the driver looks after this for you.

In the previous section, we set up things so that the motor could move to a specific setpoint. This is very useful for robots that need to have their positions specified in absolute values, such as chart recorders, XY plotters, etc.

But what if your motor needs relative motion? For example, many robots need a mechanism that always turns in the same direction by steps. This is easily done with the position_mode attribute.

The default value for position_mode is absolute. That's why the previous example needs a new position_setpoint for every move. But you can also set the position_mode attribute to relative mode.

user@ev3dev:~$ cat             /sys/class/tacho-motor/tacho-motor2/position_mode
absolute
user@ev3dev:~$ echo relative > /sys/class/tacho-motor/tacho-motor2/position_mode
user@ev3dev:~$ cat             /sys/class/tacho-motor/tacho-motor2/position_mode
relative

Keep in mind that relative mode moves the motor a certain number of steps from the previous setpoint. This is very important when you transition from forever or time run modes to position.

Always remember to set your position attribute when changing into the relative postion run mode. You can set the position to 0, the current value of position or some other arbitrary value, but you MUST set it.

user@ev3dev:~$ echo   0 > /sys/class/tacho-motor/tacho-motor2/position
user@ev3dev:~$ cat        /sys/class/tacho-motor/tacho-motor2/position
456
user@ev3dev:~$ echo 456 > /sys/class/tacho-motor/tacho-motor2/position
user@ev3dev:~$ echo 100 > /sys/class/tacho-motor/tacho-motor2/position

We'll leave the run, stop and regulation modes as they were in the previous example and set things up for relative position mode, remember to set the position. We'll also set the position_sp to 90 counts, and execute the move:

user@ev3dev:~$ echo relative > /sys/class/tacho-motor/tacho-motor2/position_mode
user@ev3dev:~$ echo        0 > /sys/class/tacho-motor/tacho-motor2/position
user@ev3dev:~$ echo       90 > /sys/class/tacho-motor/tacho-motor2/position_sp
user@ev3dev:~$ echo        1 > /sys/class/tacho-motor/tacho-motor2/run

Nice, the motor runs exactly 90 counts (degrees in this case).

To run the exact same motion again, all we need to do is write 1 to run:

user@ev3dev:~$ echo        1 > /sys/class/tacho-motor/tacho-motor2/run

And now the motor should be at 180, right?

user@ev3dev:~$ cat /sys/class/tacho-motor/outB:motor:tacho/position
180

Yes, it's exactly 180 in this case. The actual position may be +/- 5 count from the setpoint, but it's usually exactly correct if you have hold_mode set to on.