From linear to exponential PWM output

Techylah,

for (int i=0; i<256; i++)

Gives and error in de INIT section.
Expected unqualified-id before "for"
expects contructor,destructor or type conversion before < or ++ token
I googled for it and the code is used more so code is correct.
Must be something in conjunction of the existing code I assume.

Also "lookupTable" needs to be declared as array?

Rob, do not make it more difficult as it is. 8) One step at the time.

Will look for PROGMEM and what it does.

Paco

Yes,

char lookupTable[256];

It needs to be declared outside both the init and the loop code.
And yes, get that working first and then go for saving the 256 bytes of RAM by using PROGMEM as Rob points out, if you won't be changing the curve on the fly.

Techylah,

So no error codes anymore.

I ran some test but all are different then desired.

I reduced some lines to get the basic without any switchpointValue and only used the lookupTable line.
speedstartValue is set at 1
gammaSValue is set at 1.0

speedfinalValue however in this case is always starting at 171 regardless all other settings.
Also ispeedfinalValue runs through and passing the 255 value going to 0 at the end of full trigger.

Current code for the output.

void setup()
for (int i=0; i<256; i++)
lookupTable[i] = (int) (0.5  -  speedfinalValue + pow((255 - i)/127.0, gammaSValue) * ((speedfinalValue  - speedstartValue) / 2.0));

void loop()
//  +++++++++++++++  regular speed - brake mode  +++++++++++++++

  // in regular mode 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:
  sensorValue = map(sensorValue, sensorMin, sensorMax, 0, 255);// apply the calibration to the sensor reading from the hall sensor
  sensormappedValue = constrain (sensorValue,0,255); // keep value in range
  
  //  ++++  curve section  +++++++
   //if (sensormappedValue < (switchpointValue - speedstartValue)) // switchpoint for test set at 120
   //speedValue = map(sensormappedValue, 0, 255, speedstartValue, 255);
   //else
   //speedValue = 0;
   speedValue = lookupTable[sensormappedValue];
  //  ++++  curve section  +++++++

  speedfinalValue = constrain (speedfinalValue, 0, 255);
  speedfinalValue = speedValue;
  

  if (sensormappedValue > deathbandValue)
  {
    analogWrite(pwmoutspeedPin, speedfinalValue); 
    analogWrite(pwmoutbrakePin, 0); 
    digitalWrite(ledDBPin, LOW);
    digitalWrite(ledBPPin, HIGH);
  } 
  else
  {
    analogWrite(pwmoutspeedPin, 0); 
    (speedfinalValue, 0);
    analogWrite(pwmoutbrakePin, brakeNValue);
    digitalWrite (ledDBPin,HIGH);
    digitalWrite(ledBPPin, LOW);
  }

Paco

Techylah,

For my cofirmation. with the before the init code you mean "void setup()" section?

Paco

For my confirmation. with the before the init code you mean "void setup()" section?

Yes.

Paco,
After looking at your hand-drawn curves, it occurs to me that perhaps you should implement it exactly as they described, i.e. linear until 0.75 and then
curving upwards to maximum. (I had wanted to make the top end curve down!) This can be implemented with a [ warning math follows ] curve called a cubic Bezier curve, the formula for which is:
http://www.moshplant.com/direct-or/bezier/math.html

The attached image uses 3 instead of 4 control points for the curve section after the up to 75% linear part. (I made point 1 and point 2 the same, and both at x = 1).
This greatly simplifies calculating the 6 coefficients ax, bx, cx and ay, by, cy
See if this is what you/they want.

Interestingly, it lends itself to implementation only with the lookup table, since as parametric functions of 't', you don't plug in X and get Y, or plug in Y and get X. Rather,
you plug in values of 't' from 0 to 1.0 and get any number of points in between. You make the increment small enough so it gives you all the values in the lookup table
from 3/4 (index 192) through full (index 255).

It's not simple math, but once you get it, it's very powerful and it's easy to implement. Your setup code can take any arbitrary point to be the transition point from linear to curve, and then compute the curve part of the lookup table with the two parametric equations. For example you might want the first 80% of control position to give you linear control from 0 to 60% power, and then curve to max fr the last 20%
You would make the X0, Y0 point then be (0.8, 0.6) and compute the table.

This is the math behind the curves in postscript, PDF and drawing packages (like google doc)

Techylah,

Can we go three steps back?
I have been reading articles about LUT's and how they work and how to implent them in code.
I also saw Robs multimap playground article but to technical for me.
Sofar I still have to understand the code you provided for my knowledge.

lookupTable[i] = (int) (0.5  -  speedfinalValue + pow((255 - i)/127.0, gammaSValue) * ((speedfinalValue  - speedstartValue) / 2.0));

I first have to sort out if the delay is really on the fly calculation.
So I wanted to make it linear taken from a lookuptable (instead of the current map) and test this first by the same guys.
Last week theya lso test the linear only version.
If they say the delay is gone, then I want to start to add any curve.
If your suggested end after 75 % just go up or down is up to the drivers and their feeling and a later issue.

I can take the laptop with me and load a prepared sketch with curve the same evening if the delay with a linear curve is OK and approved.
But I first have to get known to working/set up of the linear lookuptable.

lookupTable[i] = (int) (A , B);
or 
lookupTable[i] = (int) (speedfinalValue , (speedfinalValue  - speedstartValue));

If I simplify the code to this is that correct way of thinking?
Or did I misjudged the "," as a separator?

BTW, I know the Bezier curve. Work daily with it in Corel Draw to design the decals for my decal company Custom Racing Decal.

Paco

Ok. The lookupTable is a 1-dimensional array of char values (the compiler changes an int to a char automatically).
Yes, the comma was to separate the two arguments to pow().
So a straight-through linear test would be:

char lookupTable[256];
void setup()
{
     for (int i=0; i<256; i++)
          lookupTable[i] = i;
}

Techylah,

The straight full linear lookupTable works.
The lookupTable setup is put in void setup() but the excecution is put in void loop () so once the controller has started it only performs it once to fill the lookupTable with values?
So when you put things like startspeedValue in there too in void setup () with the lookupTable action are they taken into the process of the void loop() even if variables like startspeedValue are changed in runtime?

If you start the controller it reads the last saved value in void setup () for startspeedValue from the EEPROM to the variable with a value for exmaple 95.
The void loop() actions will work with that value and even can be changed by the pushbuttons up or down in value as long as the controller is ON.

Is my understanding correct?

Sorry for being a slow learner.

Paco

Paco, yes.
I would make a separate subroutine that fills the lookup table and is called with 3 values: speedStart, switchPointX, switchPointSpeed.
You could even have 3 pots that set those values, since pots are so easy to read, cheap, and add flexibility and feeling finesse to the controller.
The routine would be called once in the setup code, after setting those three variables to default values.
In your loop code, you would quickly read the pots and if and only if any of the values changed, call the fillLookupTable routine.
Also, the curved part of the table (from switchpointC to 100), can be implemented first as simple linear.
You might not even need the spline curve, and it's parametric equations. Just two simple map() calls, one for before the switchPointX and one for afterswitchPontX.
Something like:

char lookupTable[256];
int speedStart = 95;                          // out of 255,  default power level
int switchPointX = 80  * 255 / 100;     // the switch is at 80% (default) of the full input range (0 to this is linear)
int switchPointSpeed = 60 * (255 - speedStart)  / 100;  // the power or speed at the switch point is lower, only 60% of the remaining power level
void setup()
{
   fillLookupTable();
}
void fillLookupTable()
{
     for (int i=0; i<256; i++)
         if (i < switchPointX)
             lookupTable[i] = map(i, 0, switchPointX, speedStart, switchPointSpeed);
         else
             lookupTable[i] = map(i, switchPointX, 255, switchPointSpeed, 255 );       // this could get replaced by a curve after all is working
}

Then in your loop code, any time any of these three values change, by pot or button or remote,
you just simply call fillLookupTable() and you get a whole new feel and sensitivity, yet keep the fast response by having no on-the-fly calculations.

Techylah,

Slowly I am getting there.
Reworked your sample idea code.
Changed some variable names.
For friday testing I created a sketch with 3 possible actions to be tested.
1] Full linear with lookuptbale
2] Full linear with lookuptable with speedstartValue included
3] Power line with X-Y turningpoints.

As far as I can test they all work for what I see happening on the display.
Only thing I ran into is that when I call void fillLookupTable() from the void loop, speedstartValue is not changed in the void loop action of the speedfinaleValue.
This new speedstartValue is only validated when I reset the Mega.
I can change the value on the fly and the display acknowledged the action that there is a new value and it is written to the EEPROM but it is not changed in void fillLookupTable().
As the switchpointXValue and switchpointYValue are in the same void fillLookupTable() I assume they also only change when I reboot the Mega.
Do I miss something that is causing the behavior of void fillLookupTable() this way.

void setup()
{
  fillLookupTable(); // fill the look uptable
}

void loop()
{
  //  +++++++++++++++  regular speed - brake mode  +++++++++++++++

  // in regular mode 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:
  sensorValue = map(sensorValue, sensorMin, sensorMax, 0, 255);// apply the calibration to the sensor reading from the hall sensor
  sensormappedValue = constrain (sensorValue,0,255); // keep value in range for trigger motion
  //speedValue = map(sensormappedValue, 0, 255, speedstartValue, 255);

  //  ++++  curve section  +++++++
  speedValue = lookupTable[sensormappedValue];
  //  ++++  curve section  +++++++

  speedfinalValue = speedValue;

  if (sensormappedValue > deathbandValue)
  {
    analogWrite(pwmoutspeedPin, speedfinalValue); 
    analogWrite(pwmoutbrakePin, 0); 
    digitalWrite(ledDBPin, LOW);
  } 
  else
  {
    analogWrite(pwmoutspeedPin, 0); 
    (speedfinalValue, 0);
    analogWrite(pwmoutbrakePin, brakeNValue);
    digitalWrite (ledDBPin,HIGH);
  }
  
  // +++++ Write values to EEPROM when they change during operation after 3 seconds
  if (speedstartValue != speedstartValueold) 
  {
    speedstartOffTime = currentTime  + 3000;
    digitalWrite(ledEEWPin,HIGH);
    speedstartValueold = speedstartValue;
    fillLookupTable;
  }
  if (speedstartOffTime != 0  &&  currentTime  > speedstartOffTime ) 
  {
    EEPROM.write(2,speedstartValue);
    speedstartOffTime = 0;
    digitalWrite(ledEEWPin,LOW);
  }
  speedstartValueold = speedstartValue; 
}

//  ++++++ single loop actions +++++++

void fillLookupTable()
{

  //speedstartValueold = speedstartValue; //will this work here?
  //switchpointXValueold = switchpointXValue;  //will this work here?
  //switchpointYValueold = switchpointYValue;  //will this work here?

  // int switchpointXValue = 80  * 255 / 100;     // the switch is at 80% (default) of the full input range (0 to this is linear)
  // int switchpointYValue = 60 * (255 - speedStart)  / 100;  // the power or speed at the switch point is lower, only 60% of the remaining power level

    for (int i=0; i<256; i++)
    //++ linear powerline from 0 to 255 ++
    //lookupTable[i] = i; // linear powerline
    
    //++ linear power line from speedstartValue to 255 ++
    lookupTable[i] = map(i, 0, 255, speedstartValue, 255); // linear powerline with startspeed included
    
    //++ knicked powerline at X and Y value ++
    /*
    if (i < switchpointXValue)
    lookupTable[i] = map(i, 0, switchpointXValue, speedstartValue, switchpointYValue);
    else
    lookupTable[i] = map(i, switchpointXValue, 255, switchpointYValue, 255 );       // this could get replaced by a curve after all is working
    */
}

Paco

Change:
fillLookupTable;
to
fillLookupTable();

Otherwise, looks pretty good!
How does speedstartValue get changed anyway, from a pot?

//speedstartValueold = speedstartValue; //will this work here?
//switchpointXValueold = switchpointXValue; //will this work here?
//switchpointYValueold = switchpointYValue; //will this work here?

Yes. Whenever you change the lookupTable is a perfect time and probably only time to save the previous values.

The fun really starts when you let the user change switchpointYValue, or even switchpointXValue (within reasonable limits)
Just change code to:

if (speedstartValue != speedstartValueold   ||  switchpointXValue != switchpointXValueold  ||  switchpointYValue != switchpointYValueold) 
{
    eePromOffTime = currentTime  + 3000;
    digitalWrite(ledEEWPin,HIGH);
    fillLookupTable();
}
if (eePromOffTime != 0  &&  currentTime  > eePromOffTime ) 
{
    EEPROM.write(2,speedstartValue);
    eePromOffTime = 0;
    digitalWrite(ledEEWPin,LOW);
}

It becomes like steering ratio on cars. Newbies like a low ratio; racers like large ones.
With your switchpoint values, you effectively dial up the engine size and accelerator response you want and can handle.

Techylah () :wink:
I was again so close.

Pots? No way.
If you look at all current slotrace controllers they all use turnknobs with pots one way or an other.
Some have scales, some have 10 points click switch positions.
It is always a guessing and try and error game for the user.

I use pushbuttons on the controller handle.
I have 6 pusshbuttons In total now.
By every click up or down you know the value you change and can confirm on the display.
Currently I use the pushbuttons for startspeed +/-, switchpointX +/- and switchpointY +/-
All other values are done currently by MENWIZ an easy to use software MENU structure.
In the end all MENU actions need to be done by smartphone over BlueTooth.

For the change of X and Y values they need to be find out what is a reasonable range to be used.
I already put that code in my sketch but as I did not wanted to make the code in the response to large so I omitted it and only added the speedstart..
Your code is less lines so I will use it anyway for the rest of the code. Learned something new "||" !

Let you know the results from Friday.

Thanks again for thinking with me.

Paco

Just had an additional thought. You could data log the controller position history of some experts, or anybody, over a race or a period of time.
Then afterwards you histogram the speeds and see which speed ranges they spend most of the time in.
You can then automatically give them finer control in those regions, at the cost of having coarser control in the inbetween regions.
Each fine region would automatically add 2 switchpoints, one at the beginning and one at the end of the speed region.
It would all be done with map statements, like your current one switchpoint implementation.

As a high school kid (in the 60's!) I always wanted to do slot car racing, like my friends did, but my parents thought it too frivolous and they didn't want to keep driving me someplace 5 miles away. Maybe I like your project so much because I am a frustrated slot car enthusiast at heart!
Cheers!

Techylah,

Let your 60's frustration be my guide 8)
But not so fast.
Datalogging is also on the list but that comes after the stuff is all running with the smartphone on BT.
Have to dive into Android apps programming first. Not an easy task but will get there one way or the other.
In the mean time I use the 4 x 20 display.
One of the quick Dutch drivers already requested datalogging.
I first have to do the basics and convince the rusties (maybe also from the 60's :slight_smile: ) that with the WYSIWYG and the digital pushbutton actions they are better off then just adjust by try and error.

Time table:
1] working hardware (no delays)
2] BT connection with Amarino (Android) plugin
3] Design custom Android app to read the controller and adjust settings and other data from the controller.
4] Datalogging of settings and use of controller.

In the meantime if your frustration is still at a high level let your ideas flow or should I send you the whole skecth to rework and clean it? :slight_smile:

Cheers,

Paco

Techylah,

Test evening is postponed to next week. :0
They have a clubmeeting race at the track not allowing me with enough time to test.

Paco

Techylah,

Mixed results at yesyerdays evening test.
Had the laptop with me so I could choose different set ups.

1] With startspeed and linear line. They said there is no delay felt any more. The car follows the trigger nicely.
2] With startspeed and X and Y switchpoint lines. They said there is no delay felt anymore. The car follows the trigger nicely.
As there is no visualisation of the curve/lines they where having trouble to set up the rigth sweet spot.
3] Some one knowledgeable with programming changed the program and inserted a look up table for a exponential curve.
Since he has done that the driver who tested the controller noticed again a delay .

He changed in the void filllookupTable()

  for (int i=0; i<256; i++)
        //++ linear powerline from 0 to 255 ++
        //lookupTable[i] = i; // linear powerline
        //++ linear power line from startspeed to 255 ++
        //lookupTable[i] = map(i, 0, 255, speedstartValue, 255); // linear powerline with startspeed included
        //++ knicked powerline at X and Y value ++
        
        if (i < switchpointXValue)
             lookupTable[i] = map(i, 0, switchpointXValue, speedstartValue, switchpointYValue);
        else
             //lookupTable[i] = map(i, switchpointXValue, 255, switchpointYValue, 255 );       // this could get replaced by a curve after all is working
        lookupTable[i] = int (sqrt (map(i, switchpointXValue, 255, switchpointYValue, 255 )) * 15.96934);              //++++++++++

lookupTable[0] = 0;
lookupTable[1] = 48;
lookupTable[2] = 59;
lookupTable[3] = 67;
lookupTable[4] = 73;
lookupTable[5] = 78;
lookupTable[6] = 82;
lookupTable[7] = 86;
lookupTable[8] = 90;
lookupTable[9] = 93;
lookupTable[10] = 96;
lookupTable[11] = 99;
lookupTable[12] = 101;
lookupTable[13] = 104;
lookupTable[14] = 106;
lookupTable[15] = 108;
lookupTable[16] = 111;
lookupTable[17] = 113;
lookupTable[18] = 115;
lookupTable[19] = 117;
lookupTable[20] = 118;
lookupTable[21] = 120;
lookupTable[22] = 122;
lookupTable[23] = 123;
lookupTable[24] = 125;
lookupTable[25] = 127;
lookupTable[26] = 128;
lookupTable[27] = 130;
lookupTable[28] = 131;
lookupTable[29] = 132;
lookupTable[30] = 134;
lookupTable[31] = 135;
lookupTable[32] = 136;
lookupTable[33] = 138;
lookupTable[34] = 139;
lookupTable[35] = 140;
lookupTable[36] = 141;
lookupTable[37] = 142;
lookupTable[38] = 144;
lookupTable[39] = 145;
lookupTable[40] = 146;
lookupTable[41] = 147;
lookupTable[42] = 148;
lookupTable[43] = 149;
lookupTable[44] = 150;
lookupTable[45] = 151;
lookupTable[46] = 152;
lookupTable[47] = 153;
lookupTable[48] = 154;
lookupTable[49] = 155;
lookupTable[50] = 156;
lookupTable[51] = 157;
lookupTable[52] = 158;
lookupTable[53] = 159;
lookupTable[54] = 160;
lookupTable[55] = 160;
lookupTable[56] = 161;
lookupTable[57] = 162;
lookupTable[58] = 163;
lookupTable[59] = 164;
lookupTable[60] = 165;
lookupTable[61] = 166;
lookupTable[62] = 166;
lookupTable[63] = 167;
lookupTable[64] = 168;
lookupTable[65] = 169;
lookupTable[66] = 169;
lookupTable[67] = 170;
lookupTable[68] = 171;
lookupTable[69] = 172;
lookupTable[70] = 173;
lookupTable[71] = 173;
lookupTable[72] = 174;
lookupTable[73] = 175;
lookupTable[74] = 175;
lookupTable[75] = 176;
lookupTable[76] = 177;
lookupTable[77] = 178;
lookupTable[78] = 178;
lookupTable[79] = 179;
lookupTable[80] = 180;
lookupTable[81] = 180;
lookupTable[82] = 181;
lookupTable[83] = 182;
lookupTable[84] = 182;
lookupTable[85] = 183;
lookupTable[86] = 184;
lookupTable[87] = 184;
lookupTable[88] = 185;
lookupTable[89] = 185;
lookupTable[90] = 186;
lookupTable[91] = 187;
lookupTable[92] = 187;
lookupTable[93] = 188;
lookupTable[94] = 189;
lookupTable[95] = 189;
lookupTable[96] = 190;
lookupTable[97] = 190;
lookupTable[98] = 191;
lookupTable[99] = 191;
lookupTable[100] = 192;
lookupTable[101] = 193;
lookupTable[102] = 193;
lookupTable[103] = 194;
lookupTable[104] = 194;
lookupTable[105] = 195;
lookupTable[106] = 195;
lookupTable[107] = 196;
lookupTable[108] = 197;
lookupTable[109] = 197;
lookupTable[110] = 198;
lookupTable[111] = 198;
lookupTable[112] = 199;
lookupTable[113] = 199;
lookupTable[114] = 200;
lookupTable[115] = 200;
lookupTable[116] = 201;
lookupTable[117] = 201;
lookupTable[118] = 202;
lookupTable[119] = 202;
lookupTable[120] = 203;
lookupTable[121] = 203;
lookupTable[122] = 204;
lookupTable[123] = 204;
lookupTable[124] = 205;
lookupTable[125] = 205;
lookupTable[126] = 206;
lookupTable[127] = 206;
lookupTable[128] = 207;
lookupTable[129] = 207;
lookupTable[130] = 208;
lookupTable[131] = 208;
lookupTable[132] = 209;
lookupTable[133] = 209;
lookupTable[134] = 210;
lookupTable[135] = 210;
lookupTable[136] = 211;
lookupTable[137] = 211;
lookupTable[138] = 212;
lookupTable[139] = 212;
lookupTable[140] = 213;
lookupTable[141] = 213;
lookupTable[142] = 213;
lookupTable[143] = 214;
lookupTable[144] = 214;
lookupTable[145] = 215;
lookupTable[146] = 215;
lookupTable[147] = 216;
lookupTable[148] = 216;
lookupTable[149] = 217;
lookupTable[150] = 217;
lookupTable[151] = 217;
lookupTable[152] = 218;
lookupTable[153] = 218;
lookupTable[154] = 219;
lookupTable[155] = 219;
lookupTable[156] = 220;
lookupTable[157] = 220;
lookupTable[158] = 220;
lookupTable[159] = 221;
lookupTable[160] = 221;
lookupTable[161] = 222;
lookupTable[162] = 222;
lookupTable[163] = 222;
lookupTable[164] = 223;
lookupTable[165] = 223;
lookupTable[166] = 224;
lookupTable[167] = 224;
lookupTable[168] = 224;
lookupTable[169] = 225;
lookupTable[170] = 225;
lookupTable[171] = 226;
lookupTable[172] = 226;
lookupTable[173] = 226;
lookupTable[174] = 227;
lookupTable[175] = 227;
lookupTable[176] = 228;
lookupTable[177] = 228;
lookupTable[178] = 228;
lookupTable[179] = 229;
lookupTable[180] = 229;
lookupTable[181] = 230;
lookupTable[182] = 230;
lookupTable[183] = 230;
lookupTable[184] = 231;
lookupTable[185] = 231;
lookupTable[186] = 231;
lookupTable[187] = 232;
lookupTable[188] = 232;
lookupTable[189] = 233;
lookupTable[190] = 233;
lookupTable[191] = 233;
lookupTable[192] = 234;
lookupTable[193] = 234;
lookupTable[194] = 234;
lookupTable[195] = 235;
lookupTable[196] = 235;
lookupTable[197] = 236;
lookupTable[198] = 236;
lookupTable[199] = 236;
lookupTable[200] = 237;
lookupTable[201] = 237;
lookupTable[202] = 237;
lookupTable[203] = 238;
lookupTable[204] = 238;
lookupTable[205] = 238;
lookupTable[206] = 239;
lookupTable[207] = 239;
lookupTable[208] = 239;
lookupTable[209] = 240;
lookupTable[210] = 240;
lookupTable[211] = 240;
lookupTable[212] = 241;
lookupTable[213] = 241;
lookupTable[214] = 241;
lookupTable[215] = 242;
lookupTable[216] = 242;
lookupTable[217] = 242;
lookupTable[218] = 243;
lookupTable[219] = 243;
lookupTable[220] = 243;
lookupTable[221] = 244;
lookupTable[222] = 244;
lookupTable[223] = 244;
lookupTable[224] = 245;
lookupTable[225] = 245;
lookupTable[226] = 245;
lookupTable[227] = 246;
lookupTable[228] = 246;
lookupTable[229] = 246;
lookupTable[230] = 247;
lookupTable[231] = 247;
lookupTable[232] = 247;
lookupTable[233] = 248;
lookupTable[234] = 248;
lookupTable[235] = 248;
lookupTable[236] = 249;
lookupTable[237] = 249;
lookupTable[238] = 249;
lookupTable[239] = 250;
lookupTable[240] = 250;
lookupTable[241] = 250;
lookupTable[242] = 251;
lookupTable[243] = 251;
lookupTable[244] = 251;
lookupTable[245] = 251;
lookupTable[246] = 252;
lookupTable[247] = 252;
lookupTable[248] = 252;
lookupTable[249] = 253;
lookupTable[250] = 253;
lookupTable[251] = 253;
lookupTable[252] = 254;
lookupTable[253] = 254;
lookupTable[254] = 254;
lookupTable[255] = 255;

I do not know if the code has introduced this delay and need to be redesigned.
Coming Wednessday I have an other evening planned for testing.
Also the deathband needs to be taken in account otherwise the first part of the curve starts to early as the trigger movement is not exactly from 0 to 255.

In meantime I have to see if I can adapt the current control panel VB program to add a graph that shows the way the curve is currently used.
After a lot of talking to these drivers they NEED a linear to exponential curve where the top is having the umbrella shape.
Other curves are not working they say.
So for the time being we have to listen to them and first make them happy!

Tip and tricks are welcome.

Paco

curve.jpg

Hi Paco,
Ok. Glad there is no delay. It is all about the feel. Regardless of the data put into the table, there should be no delay;
Perhaps the loop code was modified as well.

Regarding this person's exponential curve code, its beginning needs to exactly match the linear portion's end. No big jump at the switchpoint!
Also, it needs parens around the "int".
I'd change it to (adding your deadband)

int   deadbandXvalue = 25;  // or whatever
//...

if (i < deadbandXvalue)
     lookupTable[i] = 0;
else
      if (i < switchpointXValue)
             lookupTable[i] = map(i, deadbandXvalue, switchpointXValue, speedstartValue, switchpointYValue);
        else
             lookupTable[i] = switchpointYValue  + (int) (sqrt (map(i, switchpointXValue, 255, 0, 255 - switchpointYValue)) * 15.96934);

Also, I'd make the curve adjustable, by changing the last line to:

lookupTable[i] = (int) (0.5 + (switchpointYValue  + pow( map(i, switchpointXValue, 255, 0, 255 - switchpointYValue ) / 255.0, curvePower) * 255.0));

CurvePower of 2.0 is the same as sqrt. Raising curvePower up to 3,4, 5 or more increased the extremeness of the curve.
Bring curvePower down from 2.0 to 1.0 reduces the curviness.
As a test, CurvePower of 1.0 should be the same as a linear continuation past the switchPoint to (255, 255).

Also, you might like the following old trick to produce a quick and dirty graph view.
For each line "lookupTable[0] = 0;" also print before the CR a series of asterisks, their number (for 51 asterisks being 100%, or 255) being
numAsterisks = lookupTable [ i ] / 5;
The linear and curved portions should be readily apparent (when you tilt your head 90 deg clockwise. :slight_smile: )
Cheers!

Techylah,

Also, you might like the following old trick to produce a quick and dirty graph view.
For each line "lookupTable[0] = 0;" also print before the CR a series of asterisks, their number (for 51 asterisks being 100%, or 255) being
numAsterisks = lookupTable / 5;
The linear and curved portions should be readily apparent (when you tilt your head 90 deg clockwise. :slight_smile: )
Cheers!

I start with the graph function first and possible without turning the head CW :slight_smile:
So I can see what is happening first with Y and X switchpoint and later with expo curves.
I added the VB6 standard MSchart object to the VB6 project of the control panel.

Looked for some snippet code and cooked something like this.

Private Sub Timer1_Timer()
'Declare 2D array to store values for the chart
'Variant ----so that can store both text as well as numbers
Dim X(1 To 2, 1 To 2) As Variant
 
X(1, 2) = "Speed"
X(2, 2) = 0
X(2, 2) = TextStartSpeedValue.Text

X(2, 1) = "TRIGGER"
X(2, 2) = TextSwitchpointXValue.Text

MSChart1.ChartData = X
MSChart1.chartType = 3
End Sub

What I cant work out is creating the line from startspeed point at the Y-axis to the X/Y point to the 255,255 point in the rigth hand top corner.
So startspeed,deathbandvalue to switchpointYValue, switchpointXValue to 255,255
So there should be three datapoints plotted in the graph.
I know it is quite simple but working for 3 hours with try and error this is all it brought me.

Variable names differ from Arduino slightly but mean the same thing.

Paco