From linear to exponential PWM output

Hi Paco,
It looks like the dimension declaration is wrong for the graph.
The Variant business just complicates things.
There is very little about line graphs in VB.
I found this slightly lower level code:

You have to scale the 0-255 coordinates to be graph values (use map) before drawing them.
You have only 3 pairs of XY data:
0, 0
switchPointX, switchPointY
255, 255

After that you could add drawing the hor speedstart line and vertical deadband lines (dotted).
You could also add some of the lookuptable points between the switchpoint and (255, 255) to see the curve.
Sorry I haven't done Visual Basic.

Techylah,

Graph only in basic form is working with your suggestion of the VB6 picturebox drawing lines.
I am now looking in the 2DNTgraph.ocx to see if I can get this to work too as it more fancy and has more features.
But for the time being the simpel graph exactly shows what we are doing with X and Y points although it is not using the curvePower yet ;-).

I just tested the curvePower line.

//lookupTable[i] = map(i, switchpointXValue, 255, switchpointYValue, 255 );       // this could get replaced by a curve after all is working
             lookupTable[i] = (int) (0.5 + (switchpointYValue  + pow( map(i, switchpointXValue, 255, 0, 255 - switchpointYValue ) / 255.0, curvePower/10) * 255.0));

As soon as CP value is 1 I can reach 255 as maximum
When I raise CP to 2,4 value the maximum is getting lower. The higher CP the lower the maximum.
Hum.

Paco

Soemtimes thing go quicker then expected.
With the help from VB forum guys I got the NTgraph.ocx working too.

Paco

Excellent, Paco. Nice to see the better graph.
I changed this post because the math was wrong. (perhaps that's considered bad form)

As you move the switchPoint around, this curve will automatically adjust, always starting where the linear part ends.

The curved part will approach 100% very slowly with the fastest change happening near the switchpoint.
endCurvePower adjusts this (from 1.0 for none to 4.0 or more, for very steeply curved)

The slope, or trigger sensitivity, changes right at the switchpoint.
Your graphing app is now really helpful to visualize this.
In order to really see and verify this, you should add to your graph all the points of the lookuptable that have X greater than switchpointX.

float endCurvePower = 2.5;
for (i=0; i<255: i++)
{
   if (i < deadbandXvalue)
        lookupTable[i] = 0;
   else
         if (i < switchpointXValue)
                lookupTable[i] = map(i, deadbandXvalue, switchpointXValue, speedstartValue, switchpointYValue);
           else
                lookupTable[i] = (int)(0.5 + switchpointYValue + (255-switchpointYValue) * ( 1.0 - pow( (255-x)/(255-switchpointXValue), endCurvePower) ));
}

Paco,
I completely changed the math so my last post is correct for the curve part.
I graphed it as a check. Sorry for the inconvenience.

If you implement and graph it I'd like to see your plot.
Best,
Mitch (Techylah)

graph.php.png

graph3.png

graph2.png

The near 0 slope at the end is wasteful of trigger range.
You might want to add one more linear section, say at the last 20% of the curve range,
and use map to go from that point to full.

Mitch,

With full confidend I went with the equipment to the race track yesterday evening.
All prepaired well and tested at home.

Hooked up the controller to do some DRY testing on the power adapter.
All worked fine.
Then started the laptop and connected the USB cable for the communication.
When I looked back at the display of the controller all digits were fully lighted.
I unhooked the USB cable to the controller and switched back on but it seems the MEGA 2560 has died :0

So the start was not what I and the other guy expected. But S happens and we then started to concentrate on progrmaming.
At the end of the evening we can retrieve the lookuptable from the MEGA and show it at the Visual Basic CONTROL PANEL side!

As the controller was out of order we could not test your curve lines.
Will discuss your new power curve witht he guy (Gabe) whether or not it is useable.
He was already happy with the fact we can now show what the controller is doing in real time and not guess how the curve exactly is.
He still dreams of drawing his own curve on his smart phone to be used. :slight_smile:
In meantime I checked on programming Android app but at this moment out of my league
Have ordered a new MEGA but that will take some time to arrive 2 weeks from China.
Have to check the display this evening with an UNO and if that has gone south too I have to order that one too.

Will add your code in the sketch and add and rework to get the variables adjusted by the menu buttons.

Keep you posted.

Thanks sofar, Paco

Yep, your control panel is kinda cool.
I'd change the labels "Switch Point X" and "Switch Point Y"
to "Switch Point Trigger" and "Switch Point Speed" to be consistent with and more intuitive.
Good Luck!
Mitch

I think I should have perhaps explained the curve part definition. I appreciate it when others comment their equations and code.

lookupTable[i] = (int)(0.5 + switchpointYValue + (255-switchpointYValue) * ( 1.0 - pow( (255-x)/(255-switchpointXValue), endCurvePower) ));

The curves of y=x^2, y=x^3, y=x^4 ..... (including the non integer numbers inbetween 2, 3, 4, etc) represent curves that start from (0, 0) on the left, and curve upward up to (1.0, 1.0) as they go to the right.

The above code implements that same set of curves, but starting at the top right, and curving increasingly downward as x goes to the left, until it reaches the switchPoint.
The expression (255-x)/255-switchpointXValue) represents how far along (in a fraction between 0 and 1) a point is to the left from the upper right corner on its way left to the switchPoint.

Raising that to a power, curves it upward.
(1.0 minus that) curves it downward.

To get it to meet vertically at the switch point, that result, 0 to 1, is scaled by the amount it has to cover, which is the distance from the top down to the switchPoint.
That factor is (255-switchpointYValue).

Finally, that scaled amount gets added to the switchpointY value, as it represents an amount higher than that Y value.

I don't know if this made it any clearer, but I thought I'd explain my math the way I like others to explain their's!
Cheers!

Good morning Mitch,

Well explained.
A lot of people are following the thread (1800+ reads) but for what reason? :slight_smile:
The speedcontroller itself or the curve equations passing by?

Still waiting for the new parts to get starting again. :frowning:

Paco

Mitch,

New Mega is in and running.
To make sure the lookuptable at the MEGA is the same we send it as string to the Serial.print
Unfortunenatly if the lookuptable is put in the serial.print the serial monitor shows only square blocks.
When I replace lookuptable for X it nicely fills the string with numbers from 0 to 255.
Am I running into limitations or did I (we) misused a string for this?
As long as the arduino side is not sending the right info I cant get it at the VB pc side not receive and decode propperly.
Any thoughts?

void fillLookupTable()
{

/* write lookupTable to stream so it can be used at the PC side to show the exact lookuptable curve used in the graph */
  Serial.print("Y,");
  for (int i=0; i<256; i++)
  {
    Serial.print(lookupTable[i]);
    //Serial.print(i); //test to see if string is filled with numbers from 0 to 255
    if (i<255)
    {
      Serial.print("|"); //delimiter
    }
  }       
  Serial.println();
}

Paco

Hi Paco,
Yes. Use Serial.print(lookupTable [ i ] , HEX) or Serial.print(lookupTable [ i ] , DEC);
The whole 256 set of 8-bit characters includes control characters and other unprintable ones.
In general you don't put binary data into a string since any 0 will terminate it at that point.
You can put a space or return after each 2-digit hex or decimal number to help you read each one
on the VB pc side and, with a loop, put that number into an array of chars again.
Best,
Mitch

Actually, I think the problem is how you are interpreting the incoming bytes on the PC side.
They are not supposed to be printable or viewable; they are binary.

The better way to send the lookuptable is as an array of bytes.
Serial.write(buf, len) or specifically,
Serial.write(lookupTable, 256);

This also will appear to be unprintable box characters; That is proper.
When your VB code is expecting a lookuptable it should read, not a string, but an array of bytes 256 long.
It should read them right into the array of 256 chars.
This link might help.
http://snipplr.com/view/2012/
Keep us posted!

Mitch,

Got it working at VB6 side. (with some help)
Final problem was
0 to255 = 256 values where 0 to 254 = 255 values.
And if you send only 255 and you tell it to expect 256 you have a problem.... :grin:

I am now able this code to be shown in VB6 in the graph.

if (i < switchpointXValue)
                lookupTable[i] = map(i, deadbandXvalue, switchpointXValue, speedstartValue, switchpointYValue);

But this curve code is not yet visible.
Have to check if Arduino sends this also in serial monitor first, as I forgot whether it does or not.

else
                lookupTable[i] = (int)(0.5 + switchpointYValue + (255-switchpointYValue) * ( 1.0 - pow( (255-x)/(255-switchpointXValue), endCurvePower) ));

Still busy to get the shield working properly and also redesigned the buttons for the MENUWIZ(ard)
So some large rewrite of the program too.

Keep you U all posted.

Paco

That code works only for those X values greater or = to switchPointX value, so you can't make that the whole lookuptable.
You have to leave it as just the upper part, as in response #93.

VB6 should alway display the whole lookuptable as a connected set of points, i.e. a line graph, or if that's too may points,
then only every N of them.

Hi Mitch and others,

OK after a long radio silence I report back again.
Worked on the code to get the menu navigation by analog port and 10 switches.
Finally I got it to work.
Happy with it I checked the working of the controller then found out some other code was not working.
Had to sort that out too. To much time taken sofar but learned a lot again.
Have to check this week if the look up table and the connection (by bluetooth) is working with the PC.
Then the guys have to do some more testing t the track.

Keep you informed about the progress.

Paco

Great! I'm still tuned in.
Mitch

Hum,

Still debugging code (nemu navigation still working fine :slight_smile: )
While moving the speed trigger I suddenly see the deaband led coming ON and OFF even if we are not in the deadband range.
Never seen this behavior before.
It looks like the constrain function is not working.
MIN = 48 MAX = 212 are calibrated for the full throw of the trigger.
As soon as sensorRawValue passes the 212 the sensorValue jumps to "0" I can see on the display.

Hum again.

Do I overlook something basic?

void loop()
{
sensorRawValue = analogRead(sensorspeedPin); // read the raw value from the linear hall sensor / potentio meter:
sensorValue = map(sensorRawValue, sensorMin, sensorMax, 0, 255);// map the calibration to the sensor reading from the hall sensor / potentiometer
}

Hi!
I think you did.
Add the constrain line in between, to make it:

sensorRawValue = analogRead(sensorspeedPin); // read the raw value from the linear hall sensor / potentiometer
sensorRawValue = constrain(sensorRawValue, sensorMin, sensorMax);
sensorValue = map(sensorRawValue, sensorMin, sensorMax, 0, 255);// map the calibration to the sensor reading from the hall sensor / potentiometer

The problem is that analogRead is returning values outside the range MIN to MAX
Mitch

Mitch,

Your on the spot. Thanks
Moving the constrain upwards did the trick.
Due to the fact the speed trigger potentiometer is giving eratic values I am converting to neodyne magnet and linear hall sensor.
Hope to have it ready at the end of the week.
From now on I use an original slot race controller body (with the magnet) instead of the custom made white controller handle.
To be continued.

paco