Go Down

Topic: From linear to exponential PWM output (Read 53488 times) previous topic - next topic



Got Excel working with copying formulas.
Now when I use Rob his formula just as an example y = pow(x, n) / pow(255, n-1)
then the result is not what we are aming at.
The final last result Y should always be 255 when X is 255 too.
With the suggestion from techylah I converted the Arduino formula to excel  but there same result.
Where do I go wrong?

Never to old to learn and I learn every day


May 13, 2012, 12:19 pm Last Edit: May 13, 2012, 12:35 pm by Techylah Reason: 1
I am unable to open either of the xlsx files, (at least with Bytescout XLS viewer). Can someone check that they are valid?

To put the conversion into a single equation:

curvedvalue = floor(0.5 + pow(value/255.0, 0.5) * 255);

As value goes from 0 to 255, curvedvalue also goes from 0 to 255, but in an exponentially curved way.
For example, if value is 64 ( 1/4) , curvedvalue should come out 128 (1/2).

This might help debug.
64 / 255 = 0.251
pow(0.251, 0.5) = 0.5001
0.5001 * 255 = 127.75
floor (0.5 + 127.75) = 128

Note that though your input and output values are integers, the intermediate calculations must be floating point.
Important only for your Arduino code, not the spreadsheet.


a quick look at the sheet:

The formula
Code: [Select]
=($B7^$D$5)/(255^ $D$5-1 )  should be  
Code: [Select]
=($B7^$D$5)/(255^ ($D$5-1) )

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)


Thank both,

Rob was on it.

I  saved it as older excel version.

Will try to get it in Arduino form now.
Never to old to learn and I learn every day


Code: [Select]

=($B7^$D$5)/(255^ ($D$5-1) )

float val = pow(input, n) / pow(255, n-1);

n = <0..1>
n = 1
n = <1..-->

when n = <0..1> it is the mirror image of 1/n 

e.g.  0.25 and 4 are mirrored in y=x
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)


New excel file added.  :)
Both formula options are used from Rob and Techyla

Never to old to learn and I learn every day


Looking at a curve in Excel isn't going to tell you how it actually "feels" in practice. Instead of meddling with Excel why not just implement the equation I gave and see how it goes? Once you have a feel for how it really responds you can decide whether to leave it as it is or adjust it.

Replace this:
Code: [Select]
>>>>>>>> speedcurveValue = speedvalueWorked with the quotation to calculate the exponential power curve // added speedcurve value
with this:
Code: [Select]

// Pick one or the other version of the curve
// This is the "negative" curve
speedcurveValue = round(speedvalueWorked * speedvalueWorked / 255.0);
// This is the "positive" curve
// speedcurveValue = round(sqrt(speedvalueWorked * 255.0));

Don't send me technical questions via Private Message.


The excel formulas seems similar to 6 digits for almost all values of n, so you might check which one is most time / size efficient.

And yes, follow Pete's advice as "the proof is in eating the pudding"
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)


Hi Pete and Rob

I will use the code dont worry.
As getting the formula correct and I like to learn what I am doing (not just copy and paste) I did the homework first in Excel.
Learned today again some valuable stuff in Arduino and Excel world.

I whished the slot car world would be that easy that one fixed curve would do the trick.
All cars and motors behave different on the tracks and then there is also different lanes that require different feel (set up).
So ONE fixed curve positive or negative is a no go....  :-)

The powercurve should be adjustable (currently is) by push buttons + and - for direct setting on the control handle or through menu structure by display.
The MEGA powered project is still prototype as the power board is still under construction so no real life testing with a motor or at the track.
I currently use two LED's for the PWM output (speed and brake) to see what happens while operating the trigger.
The speedcurveValue now is adjustable from 0 to125 and BYTE declared.
As I need both sides of the curves I have to switch formulas at the 1 value point.
if speedcurveValue = 0.1 to 0.99 then formula positive
if speedcurveValue = 1 to 2 then formula negative
speedcurveValue was initially set up as BYTE length but I guess I have to change all after this line and declare to FLOAT?

Never to old to learn and I learn every day


I hope I was helpful.  Glad to help if I was.

I'm thinking of something totally new and better for these slot cars.  I know only the kid controllers I used 50 years ago!
I do know programming and have linearized many processes in the prepress world.

I think I'm seeing what you want to accomplish - a perfectly linear (with speed) hand controller for forward and reverse.
Since you're going to implement a lookup table anyway for speed and flexibility, let the lookup table do the whole thing, both sides of the curve and the dead zone,
say values 121 - 135, (16 values centered on 128) are zero.

Then for both the forward and the reverse you take actual speed readings for say 10 forward and 10 reverse controller settings.
You "invert" the response curves, either mathematically or graphically, and enter those values into the lookup table, interpolating the inbetweens.

Say your top speed is measured at 50 mph at full, 255 throttle.   135 is to be 0 (top of dead zone).  That means you want your controller to have 120 steps from 0 to 50 mph.
The exact middle settting, 60 + 135 = 195 should cause 25 mph.    You look at your response curve (draw a hor line) and see that 25 mph actually happened at
controller position 100.  Therefore you store a 100 in lookuptable[195].     lookuptable is an array of 255 bytes.
So far lookuptable of  135 is 0, 195 is 100, and 255 is 255.  You do this for all 120 positive speeds and all 120 reverse speeds.
You now have your table.  No on-the-fly calculations; just near instant table lookups.  Outside the dead zone, speed is perfectly linear with throttle position.
(Your code makes sure to switch the voltage direction for values below 121).

This brings up an interesting question about slot car racing.   Do people indeed want and implement a "velocity pedal", rather than an "acceleration pedal".
If so, is that only because it is hard to get the current velocity, which is what would be needed for a true accelerator pedal like in a car?
If you could read back velocity (wheel speed) and implement an accelerator in the mathemeematic sense of the term, would that be better or worse for slot car racing.
In other words, if you push the throttle position forward a little, the velocity starts constantly increasing at a slow constant rate. Push it further and the rat of speedup increases, like in a real car. 
The above described lookuptable implements a perfect, calibrated velocity pedal.


Hello Techlya,
Thank you very much for thinking with me and the project.
You can find the project here:
I like to take care of some misunderstandings ?.
Slotcars only run one direction in the slot and that is forward which is typical for these cars.
There is no feedback coming what so ever from the car or track except what the driver see is happening while driving with his eyes. So this is and stays interactive control.
There is no reverse speed or do you mean this as BRAKING?
With RC modelcar transmitters the trigger has forward and brake movement for both side of 35 degrees where there is a real mechanical zero point for both directions. With slotcar race controllers they do not have a zero point like RC controllers but only 0 to 100 travel where around zero the brake is activated (deathbandzone).
The reaction speed slotracers need is much higher as RC racers so if the reverse part of the trigger is used as linear braking then this is taking too much time and response action.
I try to make a slot race controller that is capable of many settings.
Only linear response will not work on all tracks and cars. So there come the extra settings like startspeed and exponential curve in play.
Please let me know if you understand my direction.
If not let me know
Slotcars have evolved since the late 60's ? and electronic controllers are the way to go.

Regards, Paco

Never to old to learn and I learn every day


May 14, 2012, 05:21 pm Last Edit: May 14, 2012, 05:33 pm by Techylah Reason: 1
Ok Paco, tnx for the brief education.   I looked up slot car response curves and found a site that graphically presents what I think you describe.

To implement that you need just two parameters to fill your lookup table.  No dead zone; the curve takes care of that.

parameter 1 -  Base level bias - The voltage percentage you want to have even at trigger level 0. (their softtouch gets as high as 40)
parameter 2 -  Curvature - How much you want to curve the response, to give you increased control meaning low trigger sensitivity at low trigger levels, with the reverse at high trigger levels.

Whenever the user changes either of these parameters you calculate a new lookup table:
(Assume user sets Bias to be 0-255  and Curvature to be 0-255 (let max 255 mean a MaxGamma of 4)

float gamma = Curvature * (MaxGamma - 1.0) / 255.0 + 1.0;
for (i=0; i<256; i++)
    table = (int) ( 0.5  +  Bias +  pow(i/255.0, gamma) * (255.0 - Bias));

When Curvature is 0, you get no curvature.  When it is 255 you get the max curvature of 4.
To see the curve part, consider gamma to be 2.
Your table value for 50% would be the value for 1/2 squared (2nd power), or a value for 1/4 or 25%.
The actual table value is the bias value plus 1/4 of the remaining way from the bias to full.
Say the bias is 75.  (table[0] = 75   ....)
table[127] is the value you want for a halfway trigger push.
That comes to 75  +  1/4  *  180.
So table[127] = 120

Is this what you are looking for?



Appreciate your guidance effort highly.

If you see what they try to achieve at JayGee they exchange probably eeproms with software curves.
Why would you do that if you just can do it by software and the arduino. :)
This way you can make ONE universal controller. 24 bands/steps for the jayGee or 255 steps for our version  :smiley-roll-sweat:.
And later no contact vurnable sensors to be used.

Some more explanation.
The trigger I use is currently coupled to a potentiometer which has some play around the zero point.
The whole trigger movement is around 45 degrees from 0 to full.
The raw value of the sensor is mapped from 0 to 255.
With this base value we go further and control deathband and speed.

If the trigger is at the mechanical 0 position due to the play the sensor value can be higher as 0.
In real world the sensor value can vary around the zero point upto 5.
So what I have done is create a deathband which is user adjustable from 0 to 15.
So if the trigger is in zero/deathband position there is no activity possible at the speed output.
In this zero/deathband zone the brakes are always activated and the PWM break output is adjustable from 0 to 255 (0 to 100%).

As soon as the trigger leaves the zero/deathband zone the PWM speed output is activated and the brakes switched OFF.
From this point on the value is mapped from 0 to 255 and linear.
If we add speedstart then the pwm starts at a higher point and not at 0.
So if speedstart is set at 45 then the trigger regulates the output from 45 to 255 in linear fashion.

If the speedstart is set to 0 and we like to curve the linear line we call this speedcurve and this is the exponential curve we like to create.
This will run then from 0 to 255.
The speedcurve should be able to be adjusted upper or lower then the linear line.
If we add speedstart and speedcurve then from 45 to 255 the curve should be exponential.
See the previous graphs I added to the responses.

I assume your parameter 1 Bias is what I call startspeed(speedstart) and parameter 2 Curvature the speedcurve.
The softtouch of the JayGee controller is a curve with startspeed intergrated.
I like to see them both as seperate adjustable parameters.

Do not fully understand the purpose of the look up table and the benefit of it.
I know that is my problem due to the lack of knowledge.
Does my code do the same or is the look up table an easier way to achieve the same?
Is not using a look up table slowing down the controller reaction.
Do I see it wrong but 16 Mhz should be enough with the code I have or is calculating slowing down the reaction of the trigger compared to the speed dramaticly. Are we talking about micro seconds or milliseconds delays?

Please let me know your valuable opinion.

Current code... for the speed brake section.
Not optimized just for the knowledge I have gained sofar.
Code: [Select]
//     +++++++++++++++ regular speed - brake mode +++++++++++++++
      speedstartValue= constrain (speedstartValue,0,255);
      speedcurveValue= constrain (speedcurveValue,0,255);
      brakeValue= constrain (brakeValue,0,255);
      modelNumber= constrain (modelNumber,1,10);
      // control the outputs with output cross block function to prevent speed and brake to be ON together
      sensorValue = analogRead(sensorspeedPin); // read the raw value from the linear hall sensor/potentiometer:
      sensorValue = map(sensorValue, sensorMin, sensorMax, 0, 255);// apply the calibration to the sensor reading from the hall sensor/potentiometer
      // sensorMin and sensorMax are stored in the EEPROM during calibration.
      sensormappedValue = constrain (sensorValue,0,255); // keep value in range
      speedValue = map(sensormappedValue, 0, 255, speedstartValue, 255); //speedstart added to the speed
      //speedcurveValue = speedvalue with the quotation to calculate the exponential power curve // added speedcurve value
      //speedfinalValue = speedcurveValue
      if (speedfinalValue > 250) {speedfinalValue= 255;} //make sure we reache full speed due to play.
      speedfinalValue = speedValue;
      if (sensormappedValue > deathbandValue){analogWrite(pwmoutspeedPin, speedfinalValue); analogWrite(pwmoutbrakePin, 0); digitalWrite(led13Pin, LOW);}
      {analogWrite(pwmoutspeedPin, 0); (speedfinalValue, 0);analogWrite(pwmoutbrakePin, brakeValue);digitalWrite (led13Pin,HIGH);} // startspeed and curve included
      if (speedfinalValue < speedfinalValueold){analogWrite(pwmoutspeedPin, 0); (speedfinalValue, 0);analogWrite(pwmoutbrakePin, brakeValue);digitalWrite (led30Pin,HIGH);} // regenerative breaking
      {digitalWrite(led30Pin, LOW);}
Never to old to learn and I learn every day


May 14, 2012, 09:21 pm Last Edit: May 15, 2012, 12:11 am by Techylah Reason: 1
Very good.  The curve should be added before the speedstart is added.

speedValue = map(sensormappedValue, 0, 255, speedstartValue, 255); //speedstart added to the speed

speedValue = (int) ( 0.5  +  speedstartValue + pow(sensormappedValue/255.0, gamma) * (255.0 - speedstartValue));

If gamma is 1.0 it should operate the same as the unchanged version.
When gamma is greater than 1.0, you get the Jaygee effect.
If you make gamma < 1.0, say .5 or .33, you curve the opposite way.  I'm not sure why you'd want that.

If you do, you can still combine both curves into one, with precise control at low end and at the high end, but you quickly adjust with small trigger movements in the middle speeds.

The reason for the lookuptable is just for speed.  A simple lookup is much faster than floating point math, especially exponential (pow) function.
You should verify this by seeing how long it takes to do 1000 lookups (for the same or different values) vs a loop to do 1000 of the "pow" version.
Just make sure you don't put any serial.print stuff in the loop, only at the end to subtract the millis times and print that out.


They didn't have or know about Arduinos!  Yours indeed will be better, more flexible, and use a simple pot!

Go Up