Go Down

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

backbone

This worked. :)

Code: [Select]
if (speedstartValue != speedstartValueold)
     {
     tempMillis = millis() + 3000;
     digitalWrite(led11Pin,HIGH);
     }
if (tempMillis != 0  &&  millis() > tempMillis)
{
     //EEPROM.write(2,speedstartValue);
     speedstartValueold = speedstartValue;
     tempMillis = 0;
     digitalWrite(led11Pin,LOW);
}

Never to old to learn and I learn every day

backbone

If I add the previous code snippet to other values I thougth it would perform with the same tempMillis lines OK.
Code: [Select]
  // +++++ Write values to EEPROM when they change after 3 seconds
  if (speedstartValue != speedstartValueold)
  {
    tempMillis = millis() + 3000;
    digitalWrite(led11Pin,HIGH);
  }
  if (tempMillis != 0  &&  millis() > tempMillis)
  {
    EEPROM.write(2,speedstartValue);
    speedstartValueold = speedstartValue;
    tempMillis = 0;
    digitalWrite(led11Pin,LOW);
  }

  if (speedcurveValue != speedcurveValueold)
  {
    tempMillis = millis() + 3000;
    digitalWrite(led11Pin,HIGH);
  }
  if (tempMillis != 0  &&  millis() > tempMillis)
  {
    EEPROM.write(3,speedcurveValue);
    speedcurveValueold = speedcurveValue;
    tempMillis = 0;
    digitalWrite(led11Pin,LOW);
  }   

  if (brakeNValue != brakeNValueold)
  {
    tempMillis = millis() + 3000;
    digitalWrite(led11Pin,HIGH);
  }
  if (tempMillis != 0  &&  millis() > tempMillis)
  {
    EEPROM.write(4,brakeNValue);
    brakeNValueold = brakeNValue;
    tempMillis = 0;
    digitalWrite(led11Pin,LOW);
  }

Although the led is ON the changed values are not saved except for the speedstartValue.

But I have to declare temp(Xnumber up)Millis for each extra value I like to save to memory.
Is this a correct behaviour? If these extra millis() are running 10 in total could the program freeze as a result of the large number of millis()
Free Sram 5389 still.
Any workaround if this is the case?

Code: [Select]
  // +++++ Write values to EEPROM when they change after 3 seconds
  if (speedstartValue != speedstartValueold)
  {
    tempMillis = millis() + 3000;
    digitalWrite(led11Pin,HIGH);
  }
  if (tempMillis != 0  &&  millis() > tempMillis)
  {
    EEPROM.write(2,speedstartValue);
    speedstartValueold = speedstartValue;
    tempMillis = 0;
    digitalWrite(led11Pin,LOW);
  }

  if (speedcurveValue != speedcurveValueold)
  {
    temp2Millis = millis() + 3000;
    digitalWrite(led11Pin,HIGH);
  }
  if (temp2Millis != 0  &&  millis() > temp2Millis)
  {
    EEPROM.write(3,speedcurveValue);
    speedcurveValueold = speedcurveValue;
    temp2Millis = 0;
    digitalWrite(led11Pin,LOW);
  }   

  if (brakeNValue != brakeNValueold)
  {
    temp3Millis = millis() + 3000;
    digitalWrite(led11Pin,HIGH);
  }
  if (temp3Millis != 0  &&  millis() > temp3Millis)
  {
    EEPROM.write(4,brakeNValue);
    brakeNValueold = brakeNValue;
    temp3Millis = 0;
    digitalWrite(led11Pin,LOW);
  }


Paco
Never to old to learn and I learn every day

Techylah

You do not need to keep reading the time with repeated calls to millis().
Read it once at the beginning of the loop and put the value in a variable.  Everything in the loop then references currentTime.
Also a separate, reasonably-named variable for each turn off time is a reasonable expense.
Code: [Select]

currentTime = millis();
....

if (brakeNValue != brakeNValueold)
{
      brakeOffTime = currentTime  + 3000;
      digitalWrite(led11Pin,HIGH);
}
if (brakeOffTime != 0  &&  currentTime   > brakeOffTime )
{
      EEPROM.write(4,brakeNValue);
      brakeNValueold = brakeNValue;
      brakeOffTime = 0;
      digitalWrite(led11Pin,LOW);
}

backbone

Techylah,

I declared in the init part:
long currentTime = millis();
long brakeOffTime = 0;

With your code after power up the led11Pin goes on and not off.
With serial monitor I chekced and see brakeOffTime stays 3000 what ever you do.
So I changed currentTime into millis() and then when I power on the led11Pin is on for 3 secs and after that when I press the key the led goes ON and OFF after the 3 secs. So that works then.....
So why putting millis() into the variable is not working and is of influence on the fact the led11Pin is high always?

Paco
Never to old to learn and I learn every day

Techylah

The declaration and setting of currentTime goes only in the loop routine, at the beginning.
Throughout that passage through the loop, that is the current time.
The beginning of each loop sets a new currentTime.

All of the turn off times, like long brakeOffTime need to be declared outside of of the loop routine, as global variables,
since they must remain the same for multiple passes of the loop.

So the loop routine starts with:
long currentTime = millis();

Outside both the init and loop routines, you have:
long brakeOffTime = 0;
long speedcurveOfftime = 0;
...



backbone

Techylah,

Sorry for no response.
Been busy to finalize the hardware so we can test drive the controller this coming friday evening at a track.
I put your recommendations in the code and that works fine now. Thanks again.

I checked all about the look up table discussions but still do not understand.
For my understanding I like to go back to an other version of the speedcurve which is more simple to understand for me I guess and progress from there.
See the attachement.
I also have to make the guys clear what they are doing when they set up speed curve.
Friday I receive a Android phone which I like to connect the controller to display the curve settings (and all other settings).
If the hardware is functioning fine I can always adapt the software settings.

Paco
Never to old to learn and I learn every day

backbone

Got some sort of working code.

Code: [Select]
   if (sensormappedValue < switchpointValue)
    speedValue = map(sensormappedValue, 0, 255, speedstartValue, 255); // can be switched off later stage when curve section works.
    else
  //  speedValue = (int) (0.5  +  speedstartValue + pow(sensormappedValue/127.0, gammaSValue) * ((speedfinalValue - speedstartValue) / 2.0) );   
    speedValue = (int) (0.5  +  speedfinalValue - pow((255 - sensormappedValue)/127.0, gammaSValue) * ((speedfinalValue  - speedstartValue) / 2.0));


I added switchpointValue variable instead of the fixed 128 to change the point on the trigger baseline where the linear line is starting to bend. Both options earlier supplied give a drop down in speedfinalvalue after switchpointValue is reached.
I tried to figure out how to change the line to linear climbing after the switchpointValue but I failed sofar.

Paco
Never to old to learn and I learn every day

backbone

Techylah and Rob,

The maiden trip of the controller was made yesterday evening.
It ran 3 hours without any electronic/mechanical hick up.
I had two fast club drivers trying the controller.
They were very content about the fact they could see what they adjusted for startspeed and break and now knew what they were doing in numbers.

They had only one remark  :~ at the end of the evening and that is that the controller is not following the trigger movement exactly.
As the controller was programmed for a linear line (curving not working yet) they say there was a lack in response when going from 0 to full speed.
They described it as a delay.
I can not confirm their FEELING but have to believe them.
These guys run rounds measured in 1/1000 of a second!
The difference with my controller and an other known one was 3 tenth of a second.  :smiley-red:

Could this be caused due to coding delaying the PWM to respond in this case?

Other thoughts and suggestions are welcome.

Paco
Never to old to learn and I learn every day

Techylah

Quote
They described it as a delay.
I can not confirm their FEELING but have to believe them.

I believe them, too!

I'm pretty sure it is because you are doing calculations on the fly instead of the lookup table.

Replace:
Code: [Select]
speedValue = (int) (0.5  +  speedfinalValue - pow((255 - sensormappedValue)/127.0, gammaSValue) * ((speedfinalValue  - speedstartValue) / 2.0));
with
Code: [Select]
speedValue = lookupTable[sensormappedValue];
and then, in your init code:
Code: [Select]
for (int i=0; i<256; i++)
   lookupTable[i] = (int) (0.5  +  speedfinalValue - pow((255 - i)/127.0, gammaSValue) * ((speedfinalValue  - speedstartValue) / 2.0));


speedValue will be exactly the same but practically instantaneous, instead of after slogging through the really slow floating point implementation of pow(), along with three also slow floating point multiply/divides.

robtillaart

Agree with TechyIah, a lookup table would improve speed, you might place it in PROGMEM to minimize using RAM.
That means you need to print it and make C-code of it ( make a small sketch that prints a C-array)
Rob Tillaart

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

backbone

Techylah,

Code: [Select]
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
Never to old to learn and I learn every day

Techylah

Yes,
Code: [Select]
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.

backbone

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.
Code: [Select]

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
Never to old to learn and I learn every day

backbone

Techylah,

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

Paco

Never to old to learn and I learn every day

Techylah

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

Yes.

Go Up