controller response curve approaches

If there is a recent thread dedicated to this topic, I could not find it via search. Please point me if I just missed it - thanks.

We recently trained a bunch of potential drivers for the upcoming season using last year’s robot (xbox controller - triggers =+/- throttle & left stick steering) and a robot from several seasons ago (full size joystick - arcade style). The latter was nearly unanimously preferred by our dozen trainees, and timed navigation drills confirmed it performed better, but part of the feedback was that last year’s controls with the Xbox controller just weren’t well-tuned. That said, last year’s driver liked them & did well with them.

So now I’m looking into what approaches teams use to tune inputs from controllers to direct robot drivetrain / movement. Our programming lead has told me input values captured from controllers range from -1 (back or left) to 1 (forward or right), and then the code dictates what is sent downstream (also -1 to 1) as far as movement commands. I recall reading in a CD thread that there is a default of y= x^2 for >1 and (-1)x^2 for <1, or maybe it was just y=x^3.

The next logical step would be to come up with a controller response curve function that works for the specific robot and driver, and that’s what I’d like to discuss here. I have a couple ideas, but I’m a second year mentor who still has plenty to learn, so what do the teams that really have this figured out do?

Here are my ideas:

  1. Figure out what numbers (maybe it’s 0.08 for forward and -0.11 for backward) sent downstream are the minimum required for the robot to move at all, and make those numbers the floor/constant in the response curve function. And then decide what curve beyond that works best for the driver. Carrying the parenthetical examples forward, maybe the functions would be something like this…

  2. A more ambitious approach might be to do tests with the robot involving sending an incremental range of values (-1 to +1) to the drivetrain movement function, and for each value record actual results of movement (top speed, possibly rate of acceleration). And THEN come up with a control table for y=f(x) that results in the actual movement behavior that works best for the driver. Probably overkill, but might be the only way to get a “linear feeling” control approach, if that makes any sense.

Alright, I’ve teed it up hopefully. What do teams do about all this?

A note about the driver training: From my experience, arcade has a simpler learning curve than tank. Almost every driver I have seen try both types for the first time prefers arcade. That being said, over time preferences split. Keep in mind, plenty of practice with each method is essential. Also, you mentioned them driving different robots to test the different drive styles, however every robot differs in driving characteristics. I would recommend alternating between driving control types on the same robot to isolate the variable in this experiment. This, obviously, isn’t specifically related to the tuning, however it is essential to proper driver selection/training.

Yes, we fully intend to do this next year. Some constraints blocked us this year. Thanks.

See Ether’s white paper on joystick gain.

A great tunable system - you can fit a slope at low input, and curve to 100%/100% or do other neat things with it.

Thanks! And thanks Ether for the paper. The post-publish discussion of the paper is also great - covers most of the nuances swirling around as I’ve been thinking about this topic.

This is a good implementation, but an even better one is to just allow scaling by an arbitrary polynomial. You can even do a generalized polynomial and allow fractional powers. It’s very easy to write an object to do this.

Here’s our implementation, if you want example code.

The great thing about a cubic with a null parabolic term is that it is easy to implement and very fast to compute, yet has most of the flexibility you will ever really want without requiring an abs() function in your code if you’re happy with the null band of your motor controller. Before going to an arbitrary polynomial (and certainly fractional powers), I would add a fifth power term. If you want to optimize a well-behaved curve over -1,1] => -1,1], I suggest using Hermite polynomials for your fitting - it will also give you a good idea of how much your fit is improving as you add each term.

Compute time for any joystick scaling is totally trivial, and as the complexity can be totally hidden behind a utility class I’m really not convinced this is an issue.

I looked up some of the math mentioned, and I must admit it has been a long time (like 25 years)… Worthy of more study for sure.

What I have gleaned though through further experimentation is you can get a lot of mileage out of the form f(x) = a + bx + cx^3 + dx^5

From a gentle response curve:^3%2B.25x^5&func2=-.11%2B.48x%2B.18x^3%2B.26x^5&xmin=-5.073&xmax=4.928&ymin=-5.025&ymax=1.157

To a a quite aggressive one:^3%2B.26x^5&func2=-.11%2B1.47x-.83x^3%2B.24x^5&xmin=-2.467&xmax=3.133&ymin=-2.177&ymax=1.285

Thanks all

Note that if you include a constant term, the benefit of using only odd-order polynomials (that you don’t have to keep track of the sign of the input) is lost.

Oblarg, thanks for making that last point- understood.

I wanted to add another question. Reading about how Cheezy Drive works, it seems like they scale down turning/rotation as their speed increases, which makes sense in terms of sustaining gentle curves.

Let’s say our base function for turning is f(t) = t^3 where t is the -1 to +1 value captured from the controller for turning. Is the scaling approach something like f(t) = t^3 * (1-x), where x is the -1 to +1 value captured from the controller for moving forward/backward.

And then the result of the turning function looks something like this…^3%20*%20(1-0)&func2=x^3%20*%20(1-.25)&xmin=-1.733&xmax=1.733&ymin=-1.071&ymax=1.071



I played around with your gentle equation (the one that most teams should use for more precision). I liked the original curve, but I noticed the deadzone wasn’t as high as I wanted, so I changed it to .1, and I saw it was reaching full throttle before the input was full. I changed these two values and I think I got the equation pretty good. .1+.5x+.15x^3+.25x^5

Glad the discussion was useful to you. Remember, as Oblarg sort of pointed out, if you use a constant in the function then you will probably need one function for going forward (I.e. x>1) with the constant a positive number and a different function for reverse (x<1) with the constant a negative number.

You can get essentially the same response by setting a=0.54 and b=0.1

2parm-b, a=0.54 b=0.1.png

1 Like