Logarithmic Drive

Hi Everyone,

My team’s robot is geared 1:2 with a 6 motor drive base, and my driver wanted to somehow decrease joystick sensitivity on low speeds so that he can better control the robot as it goes up to a post to score. I know that to do this I would need to implement a logarithmic drive, but beyond this I know nothing. Any suggestions on implementation?

Bell Animator

check out this thread:
its basically the same subject
and 2:1 with only 6 motors (3 wire?) WILL give you breaker problems!
we had 2:1 EIGHT motor drive (2HS) and still had issues with breakers today, but that was with pushing/shoving involved

Logarithmic Drive is another way to solve the same problem as Precision Mode, but it isn’t exactly the same. With a logarithmic drive, you don’t need a button to change you into precision mode; it automatically goes into precision mode while the joystick is near the center, and goes into high-speed mode near the edges.

You are looking for a function that takes a ±127 speed value and transforms it into a new speed value, also in the ±127 range, but with the values “pulled” towards 0.

There are a couple ways to do this, but an easy way is to apply an exponent or inverse log function to the speed, and then scale the result back to ±127. If the function you used looses the sign (such as squaring a number will do), then you need to restore the sign.

Here is a simple squaring function:

if (RawSpeed >= 0) {
    LogSpeed = (RawSpeed * RawSpeed) / 127
} else {
    LogSpeed = (RawSpeed * RawSpeed) / -127

You can try some numbers and see what you get, but these sample points give you an idea of the result:

[INDENT]If RawSpeed=0 (0%), then LogSpeed=0 (0%)
If RawSpeed=±32 (25%), then LogSpeed=±8 (6%)
If RawSpeed=±64 (50%), then LogSpeed=±32 (25%)
If RawSpeed=±96 (75%), then LogSpeed=±72 (57%)
If RawSpeed=±127 (100%), then LogSpeed=±127 (100%)

Another way to solve this is to divide the throttle range into a few “zones” and scale each zone separately. This give you more control to tweak the algorithm until it drives just right, since you can decide the exact points in the range that you will shift from accurate to fast, and you can decide exactly how much each zone “feels” different to drive. This code usually takes the form of several if() statements to pick apart the raw speed value into ranges, and then apply the appropriate linear transformation.

You can also do this with a lookup table. An array of 256 bytes will allow you to explicitly map each joystick setting to an exact speed value. Total control, but a pain to change anything, since you have to manually recompute much or all of the table each time you tweak it.


  • Dean

Not necessarily, if you remember 2919B (Brute) from worlds (Math Division finalist) it had a 2:1 ratio with 6 3-wire motors and never had problems with the breaker on the PIC.

And also Binary Blitz had one in Elevation geared 3:1 with 6 motors which worked fine (they upgraded it to 8 motors but only to get more power). I posted a photo of this robot in the “Please help with driving issue” thread.

I checked in the RobotC compiler (I don’t have a microcontroller with me right now) and Rawspeed^2 instead of Rawspeed*Rawspeed compiled fine as well.

One formula for logarithmic drive is:
((((input-127)/127)^3)127) + 127

MathWorks (MatLab and Simulink) had a great idea in their demo. It is gearing up and gearing down. For instance, if you press the button 6 up once, you would gear up (1/4 power), press it again 1/2 power, press it again, 3/4 power, etc. Press button 6 down, and you would go down a gear.

Essentially, it is 1/4127, 1/2127, 3/4*127…

Our team members really liked this in the BEST competition!

Hope I am explaining that correctly. The students caught on really fast.


Thanks a lot, Quazar! I’ll try out this method.

This is the cubic variant, which conveniently preserves the sign so you don’t have to restore it like the squared function I posted. It provides a more extreme curve, so you end up with even more of the joystick range being used for accuracy, and only the very edges providing top speed.

What programming environment does this work in?
The ‘^’ operator in C and C++ is used for bitwise xor and not for raising a number to a power. (ref)


  • Dean

I know absolutely nohting about programming robots. I just posted a possible function to give you the range of values needed. It is not meant to have the syntax required for programming in any language. I have talked about this function previously:


For larger exponential equations, as to not max out your variables, you can always use something like:

Temp = JoystickValue / 127
MotorPower = Temp^x * JoystickValue

Increasing ‘x’ would give you a greater and greater curve in your exponential equation. This is what our team uses right now, and are currently making x = 4. At our competition last Saturday we still experienced trouble with having precision in the low motor speeds, so we may have to increase ‘x’ even more.


P.S. Obviously ‘^’ will not work in RobotC, (or easyC for that matter) so you would simply write TempTempTemp… etc., for as many times as you find needed.

Just a word of warning here. If you are using a Cortex, all this should work fine. If on a Pic, V0.5, or whatever you want to call the original processer, watch out for the integer math (divides etc). I am sure it can still be done but may need a few tricks.

We used this type of control for FTC and hadn’t needed it here until we switched to the new controllers and the bigger motors, but we will implement this very soon.

Jon T

I am curious about this. Maybe the new motors negate this, but in the past we would need a certain percentage of motor power, say 25%, just to move. I am thinking if “x” is more than 2 or maybe 3, you may be using a lot of the joystick stroke in the range of no robot movement.


Yes! I have the same thought.
On one hand, the joysticks need a deadband anyway.
On the other hand, the minimum useful power is significantly > 0, ie 25%

There should be an equation to provide a curved line between minimum useful power and max power. If not an equation, then make a lookup table in excel, and preload the lookup array once at initialization time.

On the third hand, a full PID loop should theoretically compensate for the realistic effects that minimum useful power is 25% to start up from a stop, but once the robot is moving, there is a speed difference between 10% and 25% of power applied. But that is more complicated that many teams would want to implement.
A button-gear mode for precision mode is easier, but maybe less cool.

See also the other thread with precision drive modes described.

Yes, though as jgraber said you do need a small amount of deadband. Still, the deadband is somewhat large, but to compensate you can always add a (probably small) number, (y) and simply make it:

Temp = (JoystickValue + y) / (127 + y)
MotorPower = Temp^x * JoystickValue

This should work, unless I am really tired and did something wrong, someone please check this for me. (Though it has worked from what I tested right now.)


EDIT: Okay, never mind. I’m not sure exactly what I was thinking, but use this instead:

MotorPower = InitialPower + (127-InitialPower) * (JoystickValue/127)^x

Where InitialPower is the power your robot needs to start moving. (That is, if you want no deadband. If you do, take that number and subtract whatever you want your deadband to be.)
(Use “PEMDAS” for Order Of Operations, as usual.)