View Full Version : Equation for joystick input to Talons
hello all, we currently have decided to look into tweaking the operator controls of driving the robot. we currently have the joystick to Talon equation as a linear equation: y=x. What the joysticks get is sent to the talons. Each get values between -1 and 1. I'm sure you know this. y is what the Talons receive and x is the joystick input. What we're looking for is an equation that starts out slow, but once you get x to be around .4 to .6, y should be roughly equal to the x value. Past that, the y value should rapidly increase until you reach where x is around .75 or .8, where it should become very close to 1.
Example point table:
x,y
0,0
.1,.005
.5,.5
.6,.8
1,1
I know it may not be much, but I am also wondering what you may have used. this isn't really an issue with sensitivity, we are just looking to drive a little more slowly when the joysticks are lightly touched, but once they get past .6 or .7, drive very closely to full power if not full.
I understand we can do this with simple if statements, but an equation would make it... "flow"... much better.
Thank you for your help :)
Something like this (http://www.chiefdelphi.com/media/papers/download/2842)?
Here's how to do it (http://www.chiefdelphi.com/media/papers/download/2843).
You could use an interpolation table.
Basically, you make a table like you already made, and the software linearly interpolates between the points. Super easy to write, calibrate, etc.
I wrote a LV VI to do this (it's in the BuzzLib download here (http://www.chiefdelphi.com/media/papers/2841)). I can try to dig up my C version if anyone wants it.
Here is an sketch I drew up, I'm not entirely convinced that if I found it's equation we would use it, but it was my first idea.
http://i.imgur.com/57TuSZw.jpg (ignore the scribble :) )
@ the posted image:
yes, i have come across those equations in my searches. i would like something that changes concavity once it reaches roughly .5. nothing extremely fancy like my sketch, but something of the likes. my sketch doesn't reflect this paragraph, btw. i'm probably confusing you all. sorry about that.
i would like something that changes concavity once it reaches roughly .5. nothing extremely fancy like my sketch, but something of the likes.
Post or PM me a set of (x,y) points defining your desired curve, and I will generate a function for you.
Or I can show you how to do it yourself.
Post or PM me a set of (x,y) points defining your desired curve, and I will generate a function for you.
Or I can show you how to do it yourself.
I've know the basics of how to do it with f'(x) and f''(x), but the only problem I run across is changing the way the curve "bends" per se... If you could PM me how you do it that would be fantastic.
If you must have an equation, you could type your in->out pairs into Excel, graph them (x vs y), then add a trendline and use the equation.
If you must have an equation, you could type your in->out pairs into Excel, graph them (x vs y), then add a trendline and use the equation.
Will try that now, completely forgot about this. thank you.
I've know the basics of how to do it with f'(x) and f''(x), but the only problem I run across is changing the way the curve "bends" per se... If you could PM me how you do it that would be fantastic.
apalrd beat me to it. see his post.
connor.worley
04-02-2014, 16:05
http://www.wolframalpha.com/input/?i=4th+degree+polynomial+that+passes+through+%280% 2C+0%29+and+%28.1%2C+.005%29+and+%28.5%2C+.5%29+an d+%28.6%2C+.8%29+and+%281%2C1%29
Wolfram Alpha can do some magic... try tweaking this around a bit
Thank you for that wolframalpha link! I didn't know you could do that. We will definitely be tweaking that. I've found an equation to use for now by means of Excel - y = 0.9703x^5 - 2.673x^4 + 0.3901x^3 + 2.0981x^2 + 0.2075x. It seems to look good and we will be testing it on the drive train soon. Thank you to all your posts! Definitely helped.
If you have even powers in your equation, you will have to take the abs of the input variable and multiply the output by the sign of the input, because you will lose the sign on the even terms but not the odd terms.
An equation with all odd powers would not do that.
Yep, I've got that accounted for.
ekapalka
05-02-2014, 01:20
For a basic interpolation given a few points, this (http://www.wolframalpha.com/input/?i=interpolate+%7B0%2C0%7D%2C+%7B.1%2C.005%7D%2C+% 7B.5%2C.5%7D+%2C%7B.6%2C.8%7D+%2C%7B1%2C1%7D%2C%7B-.1%2C-.005%7D%2C+%7B-.5%2C-.5%7D+%2C%7B-.6%2C-.8%7D+%2C%7B-1%2C-1%7D) should give you an idea. Your particular data points wouldn't produce a perfect equation fitting into ±1 range, but that can be fixed with some scaling. I would really like to know if there's an alternative to doing it this way, though :)
I would really like to know if there's an alternative to doing it this way, though :)
Cubic splines
y = x^2, and then if (x < 0) y= y * -1?
or y = x^3
Simplest approach.
I would really like to know if there's an alternative to doing it this way, though :)
Here is your XY data:
-1.000 -1.000
-0.600 -0.800
-0.500 -0.500
-0.100 -0.005
0.000 0.000
0.100 0.005
0.500 0.500
0.600 0.800
1.000 1.000
Here is your (machine generated) LUT code:
double y(double x) {
if (x < -1.000) return error();
else if (x <= -0.600) {return -0.500 + x*(0.5000);}
else if (x <= -0.500) {return 1.000 + x*(3.0000);}
else if (x <= -0.100) {return 0.119 + x*(1.2375);}
else if (x <= 0.100) {return 0.000 + x*(0.0500);}
else if (x <= 0.500) {return -0.119 + x*(1.2375);}
else if (x <= 0.600) {return -1.000 + x*(3.0000);}
else if (x <= 1.000) {return 0.500 + x*(0.5000);}
else return error();
}
If you like using lookup tables (I come from an automotive world where everything is pretty much a table or surface), you can write a routine to do it.
I do it as a two-step process. First, I 'prelookup' the fractional index of the input. Then, I interpolate the output. I have a 2d (1 input 1 output) and 3d (2 input 1 output) interpolation block, you simply use two prelookup blocks for the two inputs.
Header (structs):
/*
STRUCTURES
*/
typedef struct {
float frac,
int num
} prelookup_t;
Prelookup function:
/*
prelookup
Finds the lt/gt points for a given X vector and the fraction between them
Returns prelookup struct which can be used by interp_2d or interp_3d
*/
prelookup_t prelookup(float x, float *x_tbl, char size)
{
int num_cur = 0;
while(1)
{
if((x_tbl[num_cur] > x) || ((num_cur + 1) >= size)) break;
num_cur++;
}
int num_last = num_cur - 1;
//Find fraction between num_cur and num_cur--
float lt, gt, tmp, range;
prelookup_t out;
lt = x_tbl[num_last];
gt = x_tbl[num_cur];
tmp = x - lt;
range = gt - lt;
out.frac = tmp / range;
out.num = num_cur;
return out;
}
Interp 2d function:
/*
interp_2d
Looks up a point in the z-table based on the prelookup from an x table
Assumes that z_tbl is the same size as the X table
*/
float interp_2d(prelookup_t x, float *z_tbl)
{
int num_last = x.num - 1;
//Find the two points on the z table
float lt, gt, range, z_out;
lt = z_tbl[num_last];
gt = z_tbl[x.num];
range = gt - lt;
z_out = (range * x.frac) + lt;
return z_out;
}
Interp 3d function:
/*
interp_3d
Interpolate a surface in three dimensions (x,y,z)
Takes X and Y prelookups and Z table
X size of the Z table is required to properly index the array
*/
float interp_3d(prelookup_t x, prelookup_t y float* z_tbl, int sizex)
{
int x_num_last, x_num_cur, y_num_last, y_num_cur;
x_num_cur = x.cur;
y_num_cur = y.cur;
x_num_last = x_num_cur - 1;
y_num_last = y_num_cur - 1;
//Find the two points on the z table
//This isn't a great algorithm, but here's what we do:
//Find the value using y_num_last and the two x points weighted by x_frac
//Find the value using y_num_cur and the two x points weighted by x_frac
//Weight the two values by y_frac
float z_fracl,z_fracg,z_out;
//Find frac less
lt = z_tbl[(x_num_last*sizex+y_num_last)];
gt = z_tbl[(x_num_cur*sizex+y_num_last)];
range = gt - lt;
z_fracl = (range * x.frac) + lt;
//Find frac greater
lt = z_tbl[(x_num_last*sizex+y_num_cur)];
gt = z_tbl[(x_num_cur*sizex+y_num_cur)];
range = gt - lt;
z_fracg = (range * x.frac) + lt;
//Find final weighted result
z_out = (z_fracg * y.frac) + (z_fracl * (1 - y.frac));
return z_out;
}
You can then write an interp curve as a pair of arrays, x and z. X must be monotonic (strictly increasing), z does not have to be. It will first find the points of x that bound the given point X and the fraction between them (the prelookup step). Then it finds the corresponding z points and weights them with the fraction, returning Z (output).
Surfaces are similar, but you instead have 2 arrays (x and y) and a 2-dimensional array z. The sizes of x and the first dimension of z must match, and the size of y and the second dimension of z must match. The function needs to know the x size to index the array.
In this way, you can make some really easily change the response of the curve or surface based on how you want it to be, non-linearly (there is no dependence between x and y as there would be in a multi-variable equation).
For more than 3 dimensions, an interpolation is impractical. If you need more dimensions, you can use multiplied factors (curve with a variable as the input which scales the output).
If you pre-compute the slope between each pair of points in the XY table and store those in an array, it makes the lookup marginally faster (and the code a lot cleaner). You can do this pre-computation at runtime at power-up, or after loading a table into memory from a config file.
Once you've got a table that you're pretty sure won't need to be tweaked or tuned, you can do the pre-computation offline and hard-code the coefficients into the lookup routine (as was done in my previous post - I have an app that does this, to avoid human error).
Greg McKaskle
06-02-2014, 01:23
If using LV, the interpolate function in the array palette accepts an array of XY pairs that are your control points. You can then pass in the fractional index and it will perform the search/interp approach.
Be sure the array is sorted, though.
Greg McKaskle
vBulletin® v3.6.4, Copyright ©2000-2017, Jelsoft Enterprises Ltd.