Joystick Filters in LabVIEW

advertisement
LabVIEW Joystick Filters for Lunacy
A common request this year for programmers is to turn down the sensitivity of the drive
motors so that the drivers can maintain traction easier. In an effort to learn LabVIEW, I
have tried several different methods, which I will share below. Not all of these methods
are “good”, but they are enumerated for completeness. Please note that I am a novice
LabVIEW programmer, so please feel free to correct/modify/add-to this document. Also,
if you find a new method, please contribute it!
In this document, I have attached pictures of snippets of code. I’ve replaced the Joystick
and Motor functions with placeholder inputs and outputs in an effort to focus more on the
method and less on the implementation.
Replace the “Input from Joystick” with the result of the Joystick Get Axis.
Feed the “Output to Motor” into the input of an Arcade/Tank Drive VI or into the lower
level Motor Set Speed VIs.
The “Command Limit” input is a generic “tweak this until you like the results” variable.
I suggest making it a control so that you can easily modify it while the code is running in
debug mode. Once you get it where you like it, lock it down.
Coercion – “How do I make the motor never go faster than X?”
This method creates hard limits for the outputs. The signal from the joystick will go
directly to the motor, unless it is outside of the specified range. If it is outside of that
range, it will clamp to the closest limit.
This is done with the “In Range and Coerce” VI that is under “Programming ->
Comparison”. This VI is a quick and simple way to clamp an output and may prove
useful elsewhere in your code.
Although this is a very simple and very effective clamp, it is harder to control. This is
because you effectively limit the throw of the joystick. If you clamp at [-0.5 , 0.5], half
of your joystick’s available travel will either give -0.5 or 0.5. This will hurt your driver’s
ability to do fine control.
Linear Map – “How do I rescale the Joystick?”
This method has the same output range as coercion, but doesn’t sacrifice joystick throw.
This is done by simply multiplying the joystick’s signal by the maximum forward speed.
Multiply is under “Programming -> Numeric”.
This works because we are using numbers between [-1 , 1]. In the past, you would have
to add and subtract 128 to center it around 0, and also divide by 256 to bring it back into
range. The formula here is actually
Out = In * new_limit / old_limit
Since the old limit is +/-1, we are in luck and don’t need those extra steps.
This method is very good if you are sure you don’t ever want to go full speed, because it
doesn’t sacrifice any joystick throw. However, it has two flaws. One, it is inappropriate
if you still need access to your top speeds. Two, it is time insensitive – it has no idea
what happened in the past, and therefore can not compensate for it.
Selectable Map – “How do I toggle my scaling?
This is a simple modification to the Joystick Scaling. Instead of having a fixed scaling, a
case structure is used to switch between two constant scalings.
The case structure is found under “Programming -> Structures”. The case structure has
an input that will allow you to select which of its cases are being used. Here, a button on
the Joystick selects beween 1 (full scale) and the Command Limit. In the false case, the
structure ignores Command Limit (it doesn’t go anywhere) and instead passes 1 along.
In the true case, it simply passes Command Limit straight along.
You can have more than 2 cases by using an integer to switch between states. Also, I like
to use case structures to be able to disable features on the fly. At some point during
competition, the driver will encounter a situation you did not think of. At that point they
may disable your coded assistance and go for it.
Slew Rate – “How do I limit the rate of change?”
So far, all of these methods ignore the time element. What we really want to do is to
limit the acceleration of the motors, because applying too much torque will cause things
to slip. Limiting available power and increasing sensitivity helps, but this is a more
natural fit to the solution.
Slew rate limiting limits the effective rate at which the motors may accelerate by only
allowing the signal to change by a small fixed amount each time the code executes.
To do this, we need to remember what the last value was that we sent. LabVIEW does so
by using a “Feedback Node”. This can found under “Programming -> Structures”.
Alternatively, you can simply create an impossible situation by wiring one VI’s input to
its own output. Since this can’t be computed, it assumes you want to use the old output
as the new input and automatically inserts a feedback node. Your arrow may point in the
opposite direction – simply right click and flip it around.
Note the small circle below the arrow. This is where it gets its first value – with out it,
how do we start? LabVIEW assumes that I intended it to be 0.0, so I don’t have to wire
anything to it. If I intended otherwise, that is where I would put it.
The code shown takes the previous value (from the feedback node) and adds or subtracts
a small constant (Command Limit) to create limits for the new value.
To choose a good value for Command Limit, consider how long you want to take to
accelerate AND that this code will execute ~50 times a second. As an example, lets say
that my robot can go from standstill to full forward in 2 seconds without slipping (nice!).
Since I want to go from 0 to 1 in {50/second * 2 seconds = } 100 iterations, 1/100 = 0.01
might be a good place to start. Tweak it a bit to figure out what works for you.
This method is good in that it allows full speed but limits acceleration. However, it is
still not perfect, since it doesn’t allow the driver to control the acceleration. Put another
way, there is no difference between slamming the sticks forward and gently bringing
them forward. I want the robot to know the difference!
LabVIEW has a built in VI that does this, which can be found under “Control Design &
Simulation -> PID -> PID Output Rate Limiter.
Low Pass Filtering – “How do I do this with more awesome?”
For those of you who need slightly more awesome, LabVIEW provides support for
digital filtering. I won’t get too far in depth in signals and systems here, but please do
consider using this as a launching point for some interesting self-guided learning.
Simply put, a filter allows you to select for parts of a signal. A Low-Pass filter passes
low-frequency (slow) events and ignores high-frequency (quick) events. For example,
you may have an accelerometer in a patient’s shoe. You could use a low pass filter to
help you watch how her leg moves, and a high pass filter to watch how her foot impacts
the floor.
Closer to home, we want to be sensitive deliberate movements (low frequency) and
insensitive to twitches or slams (high frequency which may lose traction).
To use the built in VIs in LabVIEW that perform these functions, go to “Signal
Processing -> Point by Point -> Filters Point by Point”. There are a lot of options, and I
encourage you to explore them later. For now, pick the Butterworth filter. We are using
the “Point by Point” variant of these filters because we only have access to one moment
in time at a time. The other variants take a recorded piece of history and filter it.
There are a few constants that have been wired in.
Filter Type is low pass, because we want to ignore quick signals.
Sampling Frequency is 50, because we are calling this code 50 times per second.
Low Cutoff Frequency is a variable you should play with. It will determine the threshold
between signals you care about and signals you don’t and is measured in 1 / seconds.
Going back to our slew rate example, if the robot can cleanly accelerate to full speed in 2
seconds, you may want to start at 1/(2 seconds) = 0.5. Fiddle with it until it feels right,
then share the results.
Order indicates how severe the filter is. A higher order filter will create a sharper
threshold, but may have some wonky side effects. Experiment here as well.
Download