Hi power inverter for Nissan leaf motor. Dyno's 302.3hp p15

SplinterOz said:
kiwifiat said:
SplinterOz said:
Hey Arlo I have tidied your code again. The reason for functions is so you don't have to copy and paste code, so I have modified the temperature function.
I have also used Lebowski's filter code on the temperature (rather than average) and the speedo.
Note again I have moved the calculations for the Nextion display into the function to the display function.

I see you also corrected the "attachInterrupt" rising/falling issue and now that you have a single Steinhart–Hart function you can cull the redundant set of identical defines defines BCOEFFICIENT2 3950, TEMPERATURENOMINAL2 25, SERIESRESISTOR2 9950 . Also since you have dropped the averaging function NUMSAMPLES 3 can also be commented out. I expect that the compiler may optimize those away in any case but I'm not certain. Given that the two thermistors have different resistance at 25 degrees you should pass thermistornominal as a parameter to the Steinhart–Hart function or you will get incorrect results when you calculate temperature for thermistor 2. I'm curious as to why both thermistors have identical beta coefficients when they have different nominal resistances at 25C?

I'm doing the similar project but sending the data to an android tablet via bluetooth and rather than interrupt the processor every speed transducer pulse I setup timer0 as a counter that triggers an interrupt every three wheel rotations which reduces the interrupt overhead on the processor. Any how nice work and interesting to see that our approaches are more or less the same.

That Nextion device is cool, I wish I had known about it before I started down the Android path.

Thanks it was a quick tidy up. Will remove all the extra code soon.


Hold on. The number of samples 3 (or what ever number we want) is there for the speedo its a number of samples to average the speed from on the toothed wheel I have on the rear wheel. I want that to stay. As I want a fast but clean speedo for acceleration measurements.
I use a 48 tooth wheel and averageing from 3 teeth or 4 teeth is clean but also fast!
 
kiwifiat said:
I see you also corrected the "attachInterrupt" rising/falling issue and now that you have a single Steinhart–Hart function you can cull the redundant set of identical defines defines BCOEFFICIENT2 3950, TEMPERATURENOMINAL2 25, SERIESRESISTOR2 9950 . Also since you have dropped the averaging function NUMSAMPLES 3 can also be commented out. I expect that the compiler may optimize those away in any case but I'm not certain. Given that the two thermistors have different resistance at 25 degrees you should pass thermistornominal as a parameter to the Steinhart–Hart function or you will get incorrect results when you calculate temperature for thermistor 2. I'm curious as to why both thermistors have identical beta coefficients when they have different nominal resistances at 25C?

I'm doing the similar project but sending the data to an android tablet via bluetooth and rather than interrupt the processor every speed transducer pulse I setup timer0 as a counter that triggers an interrupt every three wheel rotations which reduces the interrupt overhead on the processor. Any how nice work and interesting to see that our approaches are more or less the same.

That Nextion device is cool, I wish I had known about it before I started down the Android path.

The OEM leaf thermistor is 15k but I ordered a bunch of 10k thermistors. So there are not the same.
I still need to adjust the BCOEFFICIENT2 for the 10k thermistor on the controller. A lot of this gets added over time.

And number of samples is for the speedo sensor as I posted above.
 
Arlo1 said:
Hold on. The number of samples 3 (or what ever number we want) is there for the speedo its a number of samples to average the speed from on the toothed wheel I have on the rear wheel. I want that to stay. As I want a fast but clean speedo for acceleration measurements.
I use a 48 tooth wheel and averageing from 3 teeth or 4 teeth is clean but also fast!

Well as the code stands NUMSAMPLES is only used in the thermistor routines and since the averaging routine has gone NUMSAMPLES is now redundant. I am using a similar averaging routine on all my analog pin reads but will take Lebowski's advice and use the method he posted for digital filtering. The speed routine counts wheel transducer pulses for 100mS more or less and calculates speed from there which should give you very good instantaneous speed accuracy.

You can be sure that the Beta coefficient will be different for thermistors with different R25 values. I characterize the thermistors I use at three temperatures and use the calculator found here :

http://www.thinksrs.com/downloads/programs/Therm%20Calc/NTCCalibrator/NTCcalculator.htm

The model calculates Steinhart–Hart and Beta model coefficients and you can see graphically what errors are introduced with the wrong beta value. Since you are using the Beta NTC model you only need to characterize at two temperatures which is a piece of cake.
 
Hmm ok the number of samples was from the code snipit I originally found for the speedo

As for the temp sensors yes. I will make a small adjustment to the controller temp sensor.

Most of these things have been a get the gauge working then calibrate it later kind of thing.
 
Clint at Roadrunner Glass has been changing my windshields for years in the driveway. $230-$250. Vans, Buicks, Miata, etc.

Arlo1 said:
marcexec said:
Will you fix the windsceen for the trip? :mrgreen:
(obviously just the jealousy talking here)

Working on that now.

Here in BC we are allowed to insure windshields and because of this any standard windshield costs $525 installed If I go to Alberta where you are not allowed to insure a windshield its ~$200 installed.

I am trying to find a place to order one and do it my self or someone who isn't corrupt from ICBC
 
Gordo said:
Clint at Roadrunner Glass has been changing my windshields for years in the driveway. $230-$250. Vans, Buicks, Miata, etc.


Yes he is coming Friday to my shop I got a-hold of him and he used to OWN a CRX and is stoked to check out what I have done. I plan to take him out for a rip ;)

Its 325 all said and done with Tax and the molding. That's a realistic price. Another guy offered to let me buy it for 195 all in and I do it my self. But I will pay 325 for Clint to come to my shop and do it.

Plus he will be in the market for an electric when I am done with him ;)
 
Arlo1 said:
Gordo said:
Clint at Roadrunner Glass has been changing my windshields for years in the driveway. $230-$250. Vans, Buicks, Miata, etc.


Yes he is coming Friday to my shop I got a-hold of him and he used to OWN a CRX and is stoked to check out what I have done. I plan to take him out for a rip ;)

Its 325 all said and done with Tax and the molding. That's a realistic price. Another guy offered to let me buy it for 195 all in and I do it my self. But I will pay 325 for Clint to come to my shop and do it.

Plus he will be in the market for an electric when I am done with him ;)

I was trying to find a windshield for a Subaru Forester I scooped out from under Clint and found one in the "Pick-n-Pull" in WA for $40. Something to keep in mind vs our crazy prices. Shoot me an email or pm with your current schedule and I will make a visit to you?
 
Gordo said:
I was trying to find a windshield for a Subaru Forester I scooped out from under Clint and found one in the "Pick-n-Pull" in WA for $40. Something to keep in mind vs our crazy prices. Shoot me an email or pm with your current schedule and I will make a visit to you?

About 15 years ago. Dad and I took a roll of twine to pick a part in Calgary and we got it thought the urathane in one spot he was on the outside and me inside we found the twine wore fast so we did about 5 strokes then pulled fresh twine though and kept going it took about 40 min to get out but the windshield was $25

I wanted new pretty bad because a big part of why I am replacing it is its pitted.
I don't run heat in the car often so keeping good visibility is very important.
 
kiwifiat said:
Arlo1 said:
Hold on. The number of samples 3 (or what ever number we want) is there for the speedo its a number of samples to average the speed from on the toothed wheel I have on the rear wheel. I want that to stay. As I want a fast but clean speedo for acceleration measurements.
I use a 48 tooth wheel and averageing from 3 teeth or 4 teeth is clean but also fast!

Well as the code stands NUMSAMPLES is only used in the thermistor routines and since the averaging routine has gone NUMSAMPLES is now redundant. I am using a similar averaging routine on all my analog pin reads but will take Lebowski's advice and use the method he posted for digital filtering. The speed routine counts wheel transducer pulses for 100mS more or less and calculates speed from there which should give you very good instantaneous speed accuracy.

You can be sure that the Beta coefficient will be different for thermistors with different R25 values. I characterize the thermistors I use at three temperatures and use the calculator found here :

http://www.thinksrs.com/downloads/programs/Therm%20Calc/NTCCalibrator/NTCcalculator.htm

The model calculates Steinhart–Hart and Beta model coefficients and you can see graphically what errors are introduced with the wrong beta value. Since you are using the Beta NTC model you only need to characterize at two temperatures which is a piece of cake.

Ok updated the code to take in the good feedback from the people here....
Changes include:
  • More parameters to the readThermistor function to allow any model of thermistor to be read
  • Constant changes to support the above
  • Variable name changes from temp and temp2 to tempMotor and tempController (just more usable)
  • Removal of the NUMSAMPLES and SAMPLESDELAY that were used in the readThermmistor previsously
  • Note PULSEPERROT are used for the speed sensor
  • Different low pass filter variables for Battery Amps reading, speed and temperature to allow for fine tuning
  • Ensuring calculations used to show the right output on the Nextion are in the updateDash function


Hopefully the comments helps people follow the code.

Code:
#include <Nextion.h>
#include <SoftwareSerial.h>

// Tempreture constants
// Motor Temp ???
#define THERMISTORPIN A3          // which analog pin to connect
#define THERMISTORNOMINAL 15000  // resistance at 25 degrees C
#define TEMPERATURENOMINAL 25    // temp. for nominal resistance (almost always 25 C)
#define BCOEFFICIENT 3950       // The beta coefficient of the thermistor (usually 3000-4000)
#define SERIESRESISTOR 9950     // the value of the 'other' resistor
// Controller Temp
#define THERMISTORPIN2 A4         //  anlog pin for controller temp
#define THERMISTORNOMINAL2 10000  // resisatance at 25 deg C for controller 
#define TEMPERATURENOMINAL2 25   // temp. for second therminstor resistance
#define BCOEFFICIENT2 3950       //  Teh bete coefficient for therminstor 2
#define SERIESRESISTOR2 9950   // the value for the second other resistor 

// Pin constants
#define PACKVOLTPIN A0         // pack voltage sensor
#define PREVOLTPIN A1          // system voltage sensor
#define SYSVOLTPIN A2          // precharge voltage sensor
#define AMPPIN A5              // current sensor
#define SPEEDPIN 2             // The pin the encoder is connected     
#define CONTACTORPIN 12        // control the contactor 

// Vehicle Constants
//Battery
#define HIGHVOLT 480          // Maximum pack voltage
#define LOWVOLT 340           // minimum pack voltage
#define PRECHARGEPERCENT 0.95 //  precharge complete percentage
//Speed 
#define PULSEPERROT 4.8       // pulses per rotation of speed sensor
#define WHEELCIRC .1835       // circumference of wheel in meters

// Smoothing Constants        // filter co-efficient valid range 0 -> 1  0 = infinite filtering   1 = no filtering
#define FILTER_BATTERY 0.1      
#define FILTER_SPEED 0.4
#define FILTER_TEMP 0.1

// display variables
SoftwareSerial nextion(10, 11); // Nextion TX to pin 2 and RX to pin 3 of Arduino
Nextion myNextion(nextion, 9600); //create a Nextion object named myNextion using the nextion serial port @ 9600bps

// Interrupt variables
volatile byte pulses = 0; 

// normal variables
int kmh = 0;               // speed reading

float PrechargeVolt=0, SystemVolt=0, BatteryAmp=0, PackVolt=0, tempMotor=0, tempController=0, KW=0;
unsigned long timeold; 
unsigned long millisecsPerHour = 3600000;

/*
 * Setup function... 
 *    start serial devices and dash
 *    set pinmodes
 *    attach interrupts
 *    set start timer
 */
void setup() {
  Serial.begin(9600);   // initialize serial communication at 9600 bits per second:
  myNextion.init();
  
  pinMode(CONTACTORPIN, OUTPUT);  //
  digitalWrite(CONTACTORPIN, LOW); //Makes contactor outout LOW initially (zero)

  //Use statusPin to flash along with interrupts
  pinMode(SPEEDPIN, INPUT_PULLUP);  // using INPUT_PULLUP means no need for a external pullup resisitor.
  
  //Interrupt 0 is digital pin 2, so that is where the IR detector is connected
  attachInterrupt(0, irspeed, FALLING);  // change to falling as standard state is high

  timeold = millis();
}

/*
 * Interrupt handling 
 */
void irspeed()
{
  //Update count
  pulses++;    
}

/*
 * Main loop really simple and easy to follow
 */
void loop()
{
  readVehicle();
  updateDash();
}


/*
 * Get the values from all the sensors and calculate the "real" values
 */
void readVehicle(void)
{

  int calc = 0;
  
  // Read battery information
  PackVolt = (analogRead(PACKVOLTPIN)/2.048);       //Outputs values from 0-1023, so 2.048 will make the maximum voltage 500V.  Set appropriate voltage divider!
  PrechargeVolt = (analogRead(PREVOLTPIN)/2.048);   //Outputs values from 0-1023, so 2.048 will make the maximum voltage 500V.  Set appropriate voltage divider!
  SystemVolt = (analogRead(SYSVOLTPIN)/47.34);      //Outputs values from 0-1023 so 63.94 is 16v with a 5v input
  BatteryAmp = BatteryAmp + FILTER_BATTERY*((analogRead(AMPPIN)*1.710655-890) - BatteryAmp);     // Bidirectional current sensor 2.5v at middle
  KW = (BatteryAmp*PrechargeVolt/1000);
  
  // Enable the contactor if the pack and precharge are ok
  if  (PackVolt > LOWVOLT && PackVolt < HIGHVOLT            // pack voltage within correct parameters
        && PackVolt * PRECHARGEPERCENT <= PrechargeVolt)    // 95% precharge, change 0.95 to whatever to get you want your precharge to be
  {
    digitalWrite(CONTACTORPIN, HIGH);
  }

  // calculate speed
  if (millis() - timeold >= 100)  
  {   
    detachInterrupt(0);
    kmh = (WHEELCIRC / 1000 * (pulses/PULSEPERROT))  * millisecsPerHour / (millis() - timeold);  // raw calculation
    kmh = kmh + FILTER_SPEED*(calc -kmh);  // filtered speed
    timeold = millis();
    pulses = 0;
    attachInterrupt(0, irspeed, FALLING);
  }

  // read and calculate tempretures  
  tempMotor = tempMotor + FILTER_TEMP * (readThermistor(THERMISTORPIN, THERMISTORNOMINAL, TEMPERATURENOMINAL, 
                                                BCOEFFICIENT, SERIESRESISTOR) - tempMotor);     // filtered read
  tempController = tempController + FILTER_TEMP * (readThermistor(THERMISTORPIN2, THERMISTORNOMINAL2,TEMPERATURENOMINAL2, 
                                                BCOEFFICIENT2, SERIESRESISTOR2) - tempController); // filtered read
  
  //Write it out to serial port
  Serial.print("Speed: ");
  Serial.println(kmh, DEC);
  Serial.print("Temperature 1 "); 
  Serial.print(tempMotor);
  Serial.println(" *C");
  Serial.print("Temperature 2 "); 
  Serial.print(tempController);
  Serial.println(" *C");

}

/*
 * Update the display with all the values
 * ALL logic around display including calculations are here
 */
void updateDash(void)
{
   int displayKMH, displayAMPS;
  
   displayKMH = kmh*1.25;
   if(displayKMH<60) displayKMH += 300 ;
   else displayKMH -= 60;                 // get the needle to start at 0 which is 300 deg in nextion

   displayAMPS = (BatteryAmp+100)/2.8676470;   
   if(displayAMPS<66)  displayAMPS = 295 + displayAMPS;
   else  displayAMPS = displayAMPS - 66;
   
   myNextion.setComponentValue("n4", tempMotor);
   myNextion.setComponentText("t12", String(PrechargeVolt));  // update text using original sensor value
   myNextion.setComponentValue("z2", displayKMH);
   myNextion.setComponentText("t13", String(SystemVolt));  //12v battery gauge
   myNextion.setComponentValue("n0", BatteryAmp);
   myNextion.setComponentValue("n1", kmh);
   myNextion.setComponentValue("n5", tempController);
   myNextion.setComponentValue("n6", KW);
   myNextion.setComponentValue("z1", displayAMPS);
} 

/*
 * Utility function to get the tempreture in degrees C from the thermister
 */
float readThermistor(int thermPin, int nomResistance, int nomTemp, int seriesRes, int bCoefficient) 
{

  float reading = 0;
    
  reading = analogRead(thermPin);
  
  // convert the value to resistance
  reading = 1023 / reading - 1;
  reading = seriesRes / reading;
 
  float steinhart;
  steinhart = reading / nomResistance;              // (R/Ro)
  steinhart = log(steinhart);                       // ln(R/Ro)
  steinhart /= bCoefficient;                        // 1/B * ln(R/Ro)
  steinhart += 1.0 / (nomTemp + 273.15);            // + (1/To)
  steinhart = 1.0 / steinhart;                      // Invert
  steinhart -= 273.15;                              // convert to C
  
  return steinhart;
  
}
 
Awesome thanks Tony.

I will try that tomorrow.
 
Arlo1 said:
About 15 years ago. Dad and I took a roll of twine to pick a part in Calgary and we got it thought the urathane in one spot he was on the outside and me inside we found the twine wore fast so we did about 5 strokes then pulled fresh twine though and kept going it took about 40 min to get out but the windshield was $25

I wanted new pretty bad because a big part of why I am replacing it is its pitted.
I don't run heat in the car often so keeping good visibility is very important.

This is a little better than "binder twine" http://www.harborfreight.com/professional-windshield-removal-kit-96339.html
 
SplinterOz said:
kiwifiat said:
Arlo1 said:
Hold on. The number of samples 3 (or what ever number we want) is there for the speedo its a number of samples to average the speed from on the toothed wheel I have on the rear wheel. I want that to stay. As I want a fast but clean speedo for acceleration measurements.
I use a 48 tooth wheel and averageing from 3 teeth or 4 teeth is clean but also fast!

Well as the code stands NUMSAMPLES is only used in the thermistor routines and since the averaging routine has gone NUMSAMPLES is now redundant. I am using a similar averaging routine on all my analog pin reads but will take Lebowski's advice and use the method he posted for digital filtering. The speed routine counts wheel transducer pulses for 100mS more or less and calculates speed from there which should give you very good instantaneous speed accuracy.

You can be sure that the Beta coefficient will be different for thermistors with different R25 values. I characterize the thermistors I use at three temperatures and use the calculator found here :

http://www.thinksrs.com/downloads/programs/Therm%20Calc/NTCCalibrator/NTCcalculator.htm

The model calculates Steinhart–Hart and Beta model coefficients and you can see graphically what errors are introduced with the wrong beta value. Since you are using the Beta NTC model you only need to characterize at two temperatures which is a piece of cake.

Ok updated the code to take in the good feedback from the people here....
Changes include:
  • More parameters to the readThermistor function to allow any model of thermistor to be read
  • Constant changes to support the above
  • Variable name changes from temp and temp2 to tempMotor and tempController (just more usable)
  • Removal of the NUMSAMPLES and SAMPLESDELAY that were used in the readThermmistor previsously
  • Note PULSEPERROT are used for the speed sensor
  • Different low pass filter variables for Battery Amps reading, speed and temperature to allow for fine tuning
  • Ensuring calculations used to show the right output on the Nextion are in the updateDash function


Hopefully the comments helps people follow the code.

Code:
#include <Nextion.h>
#include <SoftwareSerial.h>

// Tempreture constants
// Motor Temp ???
#define THERMISTORPIN A3          // which analog pin to connect
#define THERMISTORNOMINAL 15000  // resistance at 25 degrees C
#define TEMPERATURENOMINAL 25    // temp. for nominal resistance (almost always 25 C)
#define BCOEFFICIENT 3950       // The beta coefficient of the thermistor (usually 3000-4000)
#define SERIESRESISTOR 9950     // the value of the 'other' resistor
// Controller Temp
#define THERMISTORPIN2 A4         //  anlog pin for controller temp
#define THERMISTORNOMINAL2 10000  // resisatance at 25 deg C for controller 
#define TEMPERATURENOMINAL2 25   // temp. for second therminstor resistance
#define BCOEFFICIENT2 3950       //  Teh bete coefficient for therminstor 2
#define SERIESRESISTOR2 9950   // the value for the second other resistor 

// Pin constants
#define PACKVOLTPIN A0         // pack voltage sensor
#define PREVOLTPIN A1          // system voltage sensor
#define SYSVOLTPIN A2          // precharge voltage sensor
#define AMPPIN A5              // current sensor
#define SPEEDPIN 2             // The pin the encoder is connected     
#define CONTACTORPIN 12        // control the contactor 

// Vehicle Constants
//Battery
#define HIGHVOLT 480          // Maximum pack voltage
#define LOWVOLT 340           // minimum pack voltage
#define PRECHARGEPERCENT 0.95 //  precharge complete percentage
//Speed 
#define PULSEPERROT 4.8       // pulses per rotation of speed sensor
#define WHEELCIRC .1835       // circumference of wheel in meters

// Smoothing Constants        // filter co-efficient valid range 0 -> 1  0 = infinite filtering   1 = no filtering
#define FILTER_BATTERY 0.1      
#define FILTER_SPEED 0.4
#define FILTER_TEMP 0.1

// display variables
SoftwareSerial nextion(10, 11); // Nextion TX to pin 2 and RX to pin 3 of Arduino
Nextion myNextion(nextion, 9600); //create a Nextion object named myNextion using the nextion serial port @ 9600bps

// Interrupt variables
volatile byte pulses = 0; 

// normal variables
int kmh = 0;               // speed reading

float PrechargeVolt=0, SystemVolt=0, BatteryAmp=0, PackVolt=0, tempMotor=0, tempController=0, KW=0;
unsigned long timeold; 
unsigned long millisecsPerHour = 3600000;

/*
 * Setup function... 
 *    start serial devices and dash
 *    set pinmodes
 *    attach interrupts
 *    set start timer
 */
void setup() {
  Serial.begin(9600);   // initialize serial communication at 9600 bits per second:
  myNextion.init();
  
  pinMode(CONTACTORPIN, OUTPUT);  //
  digitalWrite(CONTACTORPIN, LOW); //Makes contactor outout LOW initially (zero)

  //Use statusPin to flash along with interrupts
  pinMode(SPEEDPIN, INPUT_PULLUP);  // using INPUT_PULLUP means no need for a external pullup resisitor.
  
  //Interrupt 0 is digital pin 2, so that is where the IR detector is connected
  attachInterrupt(0, irspeed, FALLING);  // change to falling as standard state is high

  timeold = millis();
}

/*
 * Interrupt handling 
 */
void irspeed()
{
  //Update count
  pulses++;    
}

/*
 * Main loop really simple and easy to follow
 */
void loop()
{
  readVehicle();
  updateDash();
}


/*
 * Get the values from all the sensors and calculate the "real" values
 */
void readVehicle(void)
{

  int calc = 0;
  
  // Read battery information
  PackVolt = (analogRead(PACKVOLTPIN)/2.048);       //Outputs values from 0-1023, so 2.048 will make the maximum voltage 500V.  Set appropriate voltage divider!
  PrechargeVolt = (analogRead(PREVOLTPIN)/2.048);   //Outputs values from 0-1023, so 2.048 will make the maximum voltage 500V.  Set appropriate voltage divider!
  SystemVolt = (analogRead(SYSVOLTPIN)/47.34);      //Outputs values from 0-1023 so 63.94 is 16v with a 5v input
  BatteryAmp = BatteryAmp + FILTER_BATTERY*((analogRead(AMPPIN)*1.710655-890) - BatteryAmp);     // Bidirectional current sensor 2.5v at middle
  KW = (BatteryAmp*PrechargeVolt/1000);
  
  // Enable the contactor if the pack and precharge are ok
  if  (PackVolt > LOWVOLT && PackVolt < HIGHVOLT            // pack voltage within correct parameters
        && PackVolt * PRECHARGEPERCENT <= PrechargeVolt)    // 95% precharge, change 0.95 to whatever to get you want your precharge to be
  {
    digitalWrite(CONTACTORPIN, HIGH);
  }

  // calculate speed
  if (millis() - timeold >= 100)  
  {   
    detachInterrupt(0);
    kmh = (WHEELCIRC / 1000 * (pulses/PULSEPERROT))  * millisecsPerHour / (millis() - timeold);  // raw calculation
    kmh = kmh + FILTER_SPEED*(calc -kmh);  // filtered speed
    timeold = millis();
    pulses = 0;
    attachInterrupt(0, irspeed, FALLING);
  }

  // read and calculate tempretures  
  tempMotor = tempMotor + FILTER_TEMP * (readThermistor(THERMISTORPIN, THERMISTORNOMINAL, TEMPERATURENOMINAL, 
                                                BCOEFFICIENT, SERIESRESISTOR) - tempMotor);     // filtered read
  tempController = tempController + FILTER_TEMP * (readThermistor(THERMISTORPIN2, THERMISTORNOMINAL2,TEMPERATURENOMINAL2, 
                                                BCOEFFICIENT2, SERIESRESISTOR2) - tempController); // filtered read
  
  //Write it out to serial port
  Serial.print("Speed: ");
  Serial.println(kmh, DEC);
  Serial.print("Temperature 1 "); 
  Serial.print(tempMotor);
  Serial.println(" *C");
  Serial.print("Temperature 2 "); 
  Serial.print(tempController);
  Serial.println(" *C");

}

/*
 * Update the display with all the values
 * ALL logic around display including calculations are here
 */
void updateDash(void)
{
   int displayKMH, displayAMPS;
  
   displayKMH = kmh*1.25;
   if(displayKMH<60) displayKMH += 300 ;
   else displayKMH -= 60;                 // get the needle to start at 0 which is 300 deg in nextion

   displayAMPS = (BatteryAmp+100)/2.8676470;   
   if(displayAMPS<66)  displayAMPS = 295 + displayAMPS;
   else  displayAMPS = displayAMPS - 66;
   
   myNextion.setComponentValue("n4", tempMotor);
   myNextion.setComponentText("t12", String(PrechargeVolt));  // update text using original sensor value
   myNextion.setComponentValue("z2", displayKMH);
   myNextion.setComponentText("t13", String(SystemVolt));  //12v battery gauge
   myNextion.setComponentValue("n0", BatteryAmp);
   myNextion.setComponentValue("n1", kmh);
   myNextion.setComponentValue("n5", tempController);
   myNextion.setComponentValue("n6", KW);
   myNextion.setComponentValue("z1", displayAMPS);
} 

/*
 * Utility function to get the tempreture in degrees C from the thermister
 */
float readThermistor(int thermPin, int nomResistance, int nomTemp, int seriesRes, int bCoefficient) 
{

  float reading = 0;
    
  reading = analogRead(thermPin);
  
  // convert the value to resistance
  reading = 1023 / reading - 1;
  reading = seriesRes / reading;
 
  float steinhart;
  steinhart = reading / nomResistance;              // (R/Ro)
  steinhart = log(steinhart);                       // ln(R/Ro)
  steinhart /= bCoefficient;                        // 1/B * ln(R/Ro)
  steinhart += 1.0 / (nomTemp + 273.15);            // + (1/To)
  steinhart = 1.0 / steinhart;                      // Invert
  steinhart -= 273.15;                              // convert to C
  
  return steinhart;
  
}

Damn The speed with this was about 1/2 of the real speed.
There is no filter on the amps? I need filtering on the amps more then anything...
I am experimenting with it now.

:EDIT this code doesnt work for speedo at all the higher the filter number the lower the speedo display is.
 
Arlo1 said:
Damn The speed with this was about 1/2 of the real speed.
There is no filter on the amps? I need filtering on the amps more then anything...
I am experimenting with it now.

:EDIT this code doesnt work for speedo at all the higher the filter number the lower the speedo display is.

Comment out the filter on the speed reading here:
Code:
// calculate speed
  if (millis() - timeold >= 100) 
  {   
    detachInterrupt(0);
    kmh = (WHEELCIRC / 1000 * (pulses/PULSEPERROT))  * millisecsPerHour / (millis() - timeold);  // raw calculation
  -->  kmh = kmh + FILTER_SPEED*(calc -kmh);  // filtered speed  
    timeold = millis();
    pulses = 0;
    attachInterrupt(0, irspeed, FALLING);
  }

Given that you are essentially counting wheel rotations I can't see that there will be any "noise" in the count that needs filtering. You could always scope the output from the pickup to see what the signal looks like. How high did you try the speed filer?

Do you want an odometer? If so I have some suggestions for the speed calc routine.

Yes there is filtering on the amps reading but you will probably have to tune the filter parameter which for amps is FILTER_BATTERY.
 
Arlin took me for a ride today and my back is still a little tender. When he punches the throttle, it pushes you so hard in the seat if feels like someone just rear-ended you and you can feel every bone in your spine. :shock: :shock:
 
Gordo said:
Arlin took me for a ride today and my back is still a little tender. When he punches the throttle, it pushes you so hard in the seat if feels like someone just rear-ended you and you can feel every bone in your spine. :shock: :shock:


So glad to hear that!!!! I gotta drive that beast!
 
I also just solved the cutout while the wheels were breaking loose at 100kn/h :)

I had to change the field weakening settings for how early it adds Fweak and how early it starts to reduce it as you reach full back emf

Turning up the power some more :)
 
kiwifiat said:
Arlo1 said:
Damn The speed with this was about 1/2 of the real speed.
There is no filter on the amps? I need filtering on the amps more then anything...
I am experimenting with it now.

:EDIT this code doesnt work for speedo at all the higher the filter number the lower the speedo display is.

Comment out the filter on the speed reading here:
Code:
// calculate speed
  if (millis() - timeold >= 100) 
  {   
    detachInterrupt(0);
    kmh = (WHEELCIRC / 1000 * (pulses/PULSEPERROT))  * millisecsPerHour / (millis() - timeold);  // raw calculation
  -->  kmh = kmh + FILTER_SPEED*(calc -kmh);  // filtered speed  
    timeold = millis();
    pulses = 0;
    attachInterrupt(0, irspeed, FALLING);
  }

Given that you are essentially counting wheel rotations I can't see that there will be any "noise" in the count that needs filtering. You could always scope the output from the pickup to see what the signal looks like. How high did you try the speed filer?

Do you want an odometer? If so I have some suggestions for the speed calc routine.

Yes there is filtering on the amps reading but you will probably have to tune the filter parameter which for amps is FILTER_BATTERY.
Ok thanks

I found I put the speedo filtering at 0 and it was good till 110km/h then the reading goes to shit. Testing more now.
By the way yes i want an odometer

here is what I modded the code to get the temp sensors working. I will look more at this soon. I used a laser temp gun on the motor case after it was at rest to equalize for a bit and the temp gun right on the controller temp sensor. Then changed the beta values to make them read what the temp gun showed me then heated the controller temp sensor up up 10deg and checked again.
This is the 10k thermister I am using for the controller temp digikey # BC2380-ND
https://www.digikey.ca/product-detail/en/vishay-bc-components/NTCALUG01A103J/BC2380-ND/2230708
It doesn't have to be really accurate just close. As the controller it self uses 8 digital temp sensors to keep an eye on things and cut power when needed. As long as its within a couple deg its good enough for the gauges. If I see it go up like 20 deg all the sudden I will know my cooling quit or something is very wrong. As a rule the controller and motor stay about 15 deg above ambient that's just with the natural air flow though the rad and the fan is not hooked up yet.
Code:
#include <Nextion.h>
#include <SoftwareSerial.h>

// Tempreture constants
// Motor Temp ???
#define THERMISTORPIN A3          // which analog pin to connect
#define THERMISTORNOMINAL 15000  // resistance at 25 degrees C
#define TEMPERATURENOMINAL 25    // temp. for nominal resistance (almost always 25 C)
#define BCOEFFICIENT 6850       // The beta coefficient of the thermistor (usually 3000-4000)
#define SERIESRESISTOR 10000     // the value of the 'other' resistor
// Controller Temp
#define THERMISTORPIN2 A4         //  anlog pin for controller temp
#define THERMISTORNOMINAL2 10000  // resisatance at 25 deg C for controller 
#define TEMPERATURENOMINAL2 25   // temp. for second therminstor resistance
#define BCOEFFICIENT2 9550       //  Teh bete coefficient for therminstor 2
#define SERIESRESISTOR2 10000   // the value for the second other resistor 

// Pin constants
#define PACKVOLTPIN A0         // pack voltage sensor
#define PREVOLTPIN A1          // system voltage sensor
#define SYSVOLTPIN A2          // precharge voltage sensor
#define AMPPIN A5              // current sensor
#define SPEEDPIN 2             // The pin the encoder is connected     
#define CONTACTORPIN 12        // control the contactor 

// Vehicle Constants
//Battery
#define HIGHVOLT 480          // Maximum pack voltage
#define LOWVOLT 340           // minimum pack voltage
#define PRECHARGEPERCENT 0.95 //  precharge complete percentage
//Speed 
#define PULSEPERROT 4.8       // pulses per rotation of speed sensor
#define WHEELCIRC .1835       // circumference of wheel in meters

// Smoothing Constants        // filter co-efficient valid range 0 -> 1  0 = infinite filtering   1 = no filtering
#define FILTER_BATTERY 0.8      
#define FILTER_SPEED .0
#define FILTER_TEMP 0.7

// display variables
SoftwareSerial nextion(10, 11); // Nextion TX to pin 2 and RX to pin 3 of Arduino
Nextion myNextion(nextion, 9600); //create a Nextion object named myNextion using the nextion serial port @ 9600bps

// Interrupt variables
volatile byte pulses = 0; 

// normal variables
int kmh = 0;               // speed reading

float PrechargeVolt=0, SystemVolt=0, BatteryAmp=0, PackVolt=0, tempMotor=0, tempController=0, KW=0;
unsigned long timeold; 
unsigned long millisecsPerHour = 3600000;

/*
 * Setup function... 
 *    start serial devices and dash
 *    set pinmodes
 *    attach interrupts
 *    set start timer
 */
void setup() {
  Serial.begin(9600);   // initialize serial communication at 9600 bits per second:
  myNextion.init();
  
  pinMode(CONTACTORPIN, OUTPUT);  //
  digitalWrite(CONTACTORPIN, LOW); //Makes contactor outout LOW initially (zero)

  //Use statusPin to flash along with interrupts
  pinMode(SPEEDPIN, INPUT_PULLUP);  // using INPUT_PULLUP means no need for a external pullup resisitor.
  
  //Interrupt 0 is digital pin 2, so that is where the IR detector is connected
  attachInterrupt(0, irspeed, FALLING);  // change to falling as standard state is high

  timeold = millis();
}

/*
 * Interrupt handling 
 */
void irspeed()
{
  //Update count
  pulses++;    
}

/*
 * Main loop really simple and easy to follow
 */
void loop()
{
  readVehicle();
  updateDash();
}


/*
 * Get the values from all the sensors and calculate the "real" values
 */
void readVehicle(void)
{

  int calc = 0;
  
  // Read battery information
  PackVolt = (analogRead(PACKVOLTPIN)/2.048);       //Outputs values from 0-1023, so 2.048 will make the maximum voltage 500V.  Set appropriate voltage divider!
  PrechargeVolt = (analogRead(PREVOLTPIN)/2.048);   //Outputs values from 0-1023, so 2.048 will make the maximum voltage 500V.  Set appropriate voltage divider!
  SystemVolt = (analogRead(SYSVOLTPIN)/47.34);      //Outputs values from 0-1023 so 63.94 is 16v with a 5v input
  BatteryAmp = BatteryAmp + FILTER_BATTERY*((analogRead(AMPPIN)*1.710655-890) - BatteryAmp);     // Bidirectional current sensor 2.5v at middle
  KW = (BatteryAmp*PrechargeVolt/1000);
  
  // Enable the contactor if the pack and precharge are ok
  if  (PackVolt > LOWVOLT && PackVolt < HIGHVOLT            // pack voltage within correct parameters
        && PackVolt * PRECHARGEPERCENT <= PrechargeVolt)    // 95% precharge, change 0.95 to whatever to get you want your precharge to be
  {
    digitalWrite(CONTACTORPIN, HIGH);
  }

  // calculate speed
  if (millis() - timeold >= 100)  
  {   
    detachInterrupt(0);
    kmh = (WHEELCIRC / 1000 * (pulses/PULSEPERROT))  * millisecsPerHour / (millis() - timeold);  // raw calculation
    kmh = kmh + FILTER_SPEED*(calc -kmh);  // filtered speed
    timeold = millis();
    pulses = 0;
    attachInterrupt(0, irspeed, FALLING);
  }

  // read and calculate tempretures  
  tempMotor = tempMotor + FILTER_TEMP * (readThermistor(THERMISTORPIN, THERMISTORNOMINAL, TEMPERATURENOMINAL, 
                                                BCOEFFICIENT, SERIESRESISTOR) - tempMotor);     // filtered read
  tempController = tempController + FILTER_TEMP * (readThermistor(THERMISTORPIN2, THERMISTORNOMINAL2,TEMPERATURENOMINAL2, 
                                                BCOEFFICIENT2, SERIESRESISTOR2) - tempController); // filtered read
  
  //Write it out to serial port
  Serial.print("Speed: ");
  Serial.println(kmh, DEC);
  Serial.print("Temperature 1 "); 
  Serial.print(tempMotor);
  Serial.println(" *C");
  Serial.print("Temperature 2 "); 
  Serial.print(tempController);
  Serial.println(" *C");

}

/*
 * Update the display with all the values
 * ALL logic around display including calculations are here
 */
void updateDash(void)
{
   int displayKMH, displayAMPS;
  
   displayKMH = kmh*1.25;
   if(displayKMH<60) displayKMH += 300 ;
   else displayKMH -= 60;                 // get the needle to start at 0 which is 300 deg in nextion

   displayAMPS = (BatteryAmp+100)/2.8676470;   
   if(displayAMPS<66)  displayAMPS = 295 + displayAMPS;
   else  displayAMPS = displayAMPS - 66;
   
   myNextion.setComponentValue("n4", tempMotor);
   myNextion.setComponentText("t12", String(PrechargeVolt));  // update text using original sensor value
   myNextion.setComponentValue("z2", displayKMH);
   myNextion.setComponentText("t13", String(SystemVolt));  //12v battery gauge
   myNextion.setComponentValue("n0", BatteryAmp);
   myNextion.setComponentValue("n1", kmh);
   myNextion.setComponentValue("n5", tempController);
   myNextion.setComponentValue("n6", KW);
   myNextion.setComponentValue("z1", displayAMPS);
} 

/*
 * Utility function to get the tempreture in degrees C from the thermister
 */
float readThermistor(int thermPin, int nomResistance, int nomTemp, int seriesRes, int bCoefficient) 
{

  float reading = 0;
    
  reading = analogRead(thermPin);
  
  // convert the value to resistance
  reading = 1023 / reading - 1;
  reading = seriesRes / reading;
 
  float steinhart;
  steinhart = reading / nomResistance;              // (R/Ro)
  steinhart = log(steinhart);                       // ln(R/Ro)
  steinhart /= bCoefficient;                        // 1/B * ln(R/Ro)
  steinhart += 1.0 / (nomTemp + 273.15);            // + (1/To)
  steinhart = 1.0 / steinhart;                      // Invert
  steinhart -= 273.15;                              // convert to C
  
  return steinhart;
  
}
 
Arlo1 said:
Ok thanks

I found I put the speedo filtering at 0 and it was good till 110km/h then the reading goes to shit. Testing more now.
By the way yes i want an odometer

here is what I modded the code to get the temp sensors working. I will look more at this soon. I used a laser temp gun on the motor case after it was at rest to equalize for a bit and the temp gun right on the controller temp sensor. Then changed the beta values to make them read what the temp gun showed me then heated the controller temp sensor up up 10deg and checked again.
This is the 10k thermister I am using for the controller temp digikey # BC2380-ND
https://www.digikey.ca/product-detail/en/vishay-bc-components/NTCALUG01A103J/BC2380-ND/2230708
It doesn't have to be really accurate just close. As the controller it self uses 8 digital temp sensors to keep an eye on things and cut power when needed. As long as its within a couple deg its good enough for the gauges. If I see it go up like 20 deg all the sudden I will know my cooling quit or something is very wrong. As a rule the controller and motor stay about 15 deg above ambient that's just with the natural air flow though the rad and the fan is not hooked up yet.

Smart move adjusting the Beta to get the reading to match the IR Thermometer. If you want to add watt hour counting to monitor battery SOC and a trip/Odometer to the dash you will need to make a few changes to the structure of the program.

How did the change in filter coefficient change the speedo reading? The way I read Lobowski's post was that coefficient of 1 was no filtering and 0 was filtered to death.
 
kiwifiat said:
How did the change in filter coefficient change the speedo reading? The way I read Lobowski's post was that coefficient of 1 was no filtering and 0 was filtered to death.

Correct. Values of 0.7 and 0.8 are really high, if the update rate allows it 0.01 to 0.1 will give very nice filtering. You really want at least 100 data captures per second... If the screen
is slow to update, you still want at least 100 sensor readings (and filter calculations) per second, and then only display a few a second...
 
Lebowski said:
kiwifiat said:
How did the change in filter coefficient change the speedo reading? The way I read Lobowski's post was that coefficient of 1 was no filtering and 0 was filtered to death.

Correct. Values of 0.7 and 0.8 are really high, if the update rate allows it 0.01 to 0.1 will give very nice filtering. You really want at least 100 data captures per second... If the screen
is slow to update, you still want at least 100 sensor readings (and filter calculations) per second, and then only display a few a second...

Filtering of 1 was filtering to death and at 100km/h it said about 2km/h
But filtering of 0 was no filtering at all......

Unfortunately its worse then it was before lebowski suggested filtering.
I don't think this is the right style of filter for the speedo.
 
Arlo1 said:
Lebowski said:
kiwifiat said:
How did the change in filter coefficient change the speedo reading? The way I read Lobowski's post was that coefficient of 1 was no filtering and 0 was filtered to death.

Correct. Values of 0.7 and 0.8 are really high, if the update rate allows it 0.01 to 0.1 will give very nice filtering. You really want at least 100 data captures per second... If the screen
is slow to update, you still want at least 100 sensor readings (and filter calculations) per second, and then only display a few a second...

Filtering of 1 was filtering to death and at 100km/h it said about 2km/h
But filtering of 0 was no filtering at all......

Unfortunately its worse then it was before lebowski suggested filtering.
I don't think this is the right style of filter for the speedo.

I agree 100%, the speedo is a counter not an a/d conversion so provided the interrupt is being triggered correctly there is no need to digitally filter the calculated speed. And if the interrupt is not being triggered you would use an r/c filter on the input rather than a digital filter on the dodgy count. But for the a/d reads I'm sure increasing the read frequency and digital filtering will work well.
 
kiwifiat said:
I agree 100%, the speedo is a counter not an a/d conversion so provided the interrupt is being triggered correctly there is no need to digitally filter the calculated speed. And if the interrupt is not being triggered you would use an r/c filter on the input rather than a digital filter on the dodgy count. But for the a/d reads I'm sure increasing the read frequency and digital filtering will work well.
Before I had this filter is was not perfect. Watch the $100 video
It was usable but not perfect. If I could have a filter that ignored noise then it would be perfect.
What I mean is say the time between pulses is .02 sec at 200km/h ( I need to work that math)
and say there was a little noise every .0001 seconds it would be able to ignore that knowing its to early for a new pulse.

I think that was how the original code was. Sort of.

Here is what it was back then.

Code:
   //Gauges for electric crx
#include <SoftwareSerial.h>
#include <Nextion.h>
SoftwareSerial nextion(10, 11);// Nextion TX to pin 2 and RX to pin 3 of Arduino
int speedSensorpin = 2;  // The pin the encoder is connected           
unsigned int kmh;     // speed reading
volatile uint16_t pulses;  // number of pulses
unsigned long timeold; 
unsigned int pulsePerRotation = 1;
// which analog pin to connect
#define THERMISTORPIN A3         
// resistance at 25 degrees C
#define THERMISTORNOMINAL 15000      
// temp. for nominal resistance (almost always 25 C)
#define TEMPERATURENOMINAL 25   
// how many samples to take and average, more takes longer
// but is more 'smooth'
#define NUMSAMPLES 5
// The beta coefficient of the thermistor (usually 3000-4000)
#define BCOEFFICIENT 3950
// the value of the 'other' resistor
#define SERIESRESISTOR 9950
// speed calculation 
 
int samples[NUMSAMPLES];
Nextion myNextion(nextion, 9600); //create a Nextion object named myNextion using the nextion serial port @ 9600bps
int old_sensor_value = 0;

 void irspeed()
 {
    //Update count
      pulses++;    
 }
void setup() {
Serial.begin(9600); // initialize serial communication at 9600 bits per second:
myNextion.init();
pinMode(12, OUTPUT);//
digitalWrite(1, LOW);//Makes contactor outout LOW initially (zero)
int contactorstatus = 000;
    //Use statusPin to flash along with interrupts
   pinMode(speedSensorpin, INPUT);
   
   //Interrupt 0 is digital pin 2, so that is where the IR detector is connected
   //Triggers on FALLING (change from HIGH to LOW)
   attachInterrupt(0, irspeed, FALLING);
   // Initialize
   pulses = 0;
   kmh = 0;
   timeold = 0;

 }

 void loop()
 {
 // read the input on analog pin 0:
  float Packvolt = (analogRead(A0)/2.048);//Outputs values from 0-1023, so 2.048 will make the maximum voltage 500V.  Set appropriate voltage divider!
  float Prechargevolt = (analogRead(A1)/2.048);//
  float Systemvolt = (analogRead(A2)/47.34);//Outputs values from 0-1023 so 63.94 is 16v with a 5v input
  float BatteryAmp = (analogRead(A3)*1.85-511.5);// Bidirectional current sensor 2.5v at middle
  int contactorstatus = 000;
  int value = Prechargevolt;
  int (speed[0]);
  if  (Packvolt>340&&Packvolt<480&&Packvolt*0.965<=Prechargevolt)// 95% precharge, change 0.95 to whatever to get you want your precharge to be
 
{
  digitalWrite(12, HIGH);
  int contactorstatus = 111;
}
  { 
   if (pulses >= 2) {
 if (millis() - timeold >= 100){  //Uptade every one tenth second     
 kmh = (6607.1234 / pulsePerRotation)/ (millis() - timeold)* pulses; // This should give a speed with a 23 inch od wheel
 timeold = millis();
 pulses = 0;
  }
   //Write it out to serial port
   //Serial.print("RPM = ");
   Serial.println(kmh,DEC);
  }
  }
  {
  uint8_t i;
  float average;
 
  // take N samples in a row, with a slight delay
  for (i=0; i< NUMSAMPLES; i++) {
   samples[i] = analogRead(THERMISTORPIN);
   delay(10);
  }
 
  // average all the samples out
  average = 0;
  for (i=0; i< NUMSAMPLES; i++) {
     average += samples[i];
  }
  average /= NUMSAMPLES;
 
  Serial.print("Average analog reading "); 
  Serial.println(average);
 
  // convert the value to resistance
  average = 1023 / average - 1;
  average = SERIESRESISTOR / average;
  Serial.print("Thermistor resistance "); 
  Serial.println(average);
 
  float steinhart;
  steinhart = average / THERMISTORNOMINAL;     // (R/Ro)
  steinhart = log(steinhart);                  // ln(R/Ro)
  steinhart /= BCOEFFICIENT;                   // 1/B * ln(R/Ro)
  steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
  steinhart = 1.0 / steinhart;                 // Invert
  steinhart -= 273.15;                         // convert to C

  
  Serial.print("Temperature "); 
  Serial.print(steinhart);
  Serial.println(" *C");
  myNextion.setComponentValue("n4", steinhart);

 } 
{
   myNextion.setComponentText("t12", String(Prechargevolt));  // update text using original sensor value
   myNextion.setComponentValue("z2", speed);
   myNextion.setComponentText("t13", String(Systemvolt));  //12v battery gauge
   myNextion.setComponentValue("n0", BatteryAmp);
   myNextion.setComponentValue("n1", kmh);

   
   delay(100);        // delay in between reads for stability
 }
 }
  void magnet_detect()//This function is called whenever a magnet/interrupt is detected by the arduino
 {
   pulses++;
   Serial.println("detect");
 }
 
Arlo1 said:
kiwifiat said:
I agree 100%, the speedo is a counter not an a/d conversion so provided the interrupt is being triggered correctly there is no need to digitally filter the calculated speed. And if the interrupt is not being triggered you would use an r/c filter on the input rather than a digital filter on the dodgy count. But for the a/d reads I'm sure increasing the read frequency and digital filtering will work well.
Before I had this filter is was not perfect. Watch the $100 video
It was usable but not perfect. If I could have a filter that ignored noise then it would be perfect.
What I mean is say the time between pulses is .02 sec at 200km/h ( I need to work that math)
and say there was a little noise every .0001 seconds it would be able to ignore that knowing its to early for a new pulse.

I think that was how the original code was. Sort of.

Here is what it was back then.

Code:
   //Gauges for electric crx
#include <SoftwareSerial.h>
#include <Nextion.h>
SoftwareSerial nextion(10, 11);// Nextion TX to pin 2 and RX to pin 3 of Arduino
int speedSensorpin = 2;  // The pin the encoder is connected           
unsigned int kmh;     // speed reading
volatile uint16_t pulses;  // number of pulses
unsigned long timeold; 
unsigned int pulsePerRotation = 1;
// which analog pin to connect
#define THERMISTORPIN A3         
// resistance at 25 degrees C
#define THERMISTORNOMINAL 15000      
// temp. for nominal resistance (almost always 25 C)
#define TEMPERATURENOMINAL 25   
// how many samples to take and average, more takes longer
// but is more 'smooth'
#define NUMSAMPLES 5
// The beta coefficient of the thermistor (usually 3000-4000)
#define BCOEFFICIENT 3950
// the value of the 'other' resistor
#define SERIESRESISTOR 9950
// speed calculation 
 
int samples[NUMSAMPLES];
Nextion myNextion(nextion, 9600); //create a Nextion object named myNextion using the nextion serial port @ 9600bps
int old_sensor_value = 0;

 void irspeed()
 {
    //Update count
      pulses++;    
 }
void setup() {
Serial.begin(9600); // initialize serial communication at 9600 bits per second:
myNextion.init();
pinMode(12, OUTPUT);//
digitalWrite(1, LOW);//Makes contactor outout LOW initially (zero)
int contactorstatus = 000;
    //Use statusPin to flash along with interrupts
   pinMode(speedSensorpin, INPUT);
   
   //Interrupt 0 is digital pin 2, so that is where the IR detector is connected
   //Triggers on FALLING (change from HIGH to LOW)
   attachInterrupt(0, irspeed, FALLING);
   // Initialize
   pulses = 0;
   kmh = 0;
   timeold = 0;

 }

 void loop()
 {
 // read the input on analog pin 0:
  float Packvolt = (analogRead(A0)/2.048);//Outputs values from 0-1023, so 2.048 will make the maximum voltage 500V.  Set appropriate voltage divider!
  float Prechargevolt = (analogRead(A1)/2.048);//
  float Systemvolt = (analogRead(A2)/47.34);//Outputs values from 0-1023 so 63.94 is 16v with a 5v input
  float BatteryAmp = (analogRead(A3)*1.85-511.5);// Bidirectional current sensor 2.5v at middle
  int contactorstatus = 000;
  int value = Prechargevolt;
  int (speed[0]);
  if  (Packvolt>340&&Packvolt<480&&Packvolt*0.965<=Prechargevolt)// 95% precharge, change 0.95 to whatever to get you want your precharge to be
 
{
  digitalWrite(12, HIGH);
  int contactorstatus = 111;
}
  { 
   if (pulses >= 2) {
 if (millis() - timeold >= 100){  //Uptade every one tenth second     
 kmh = (6607.1234 / pulsePerRotation)/ (millis() - timeold)* pulses; // This should give a speed with a 23 inch od wheel
 timeold = millis();
 pulses = 0;
  }
   //Write it out to serial port
   //Serial.print("RPM = ");
   Serial.println(kmh,DEC);
  }
  }
  {
  uint8_t i;
  float average;
 
  // take N samples in a row, with a slight delay
  for (i=0; i< NUMSAMPLES; i++) {
   samples[i] = analogRead(THERMISTORPIN);
   delay(10);
  }
 
  // average all the samples out
  average = 0;
  for (i=0; i< NUMSAMPLES; i++) {
     average += samples[i];
  }
  average /= NUMSAMPLES;
 
  Serial.print("Average analog reading "); 
  Serial.println(average);
 
  // convert the value to resistance
  average = 1023 / average - 1;
  average = SERIESRESISTOR / average;
  Serial.print("Thermistor resistance "); 
  Serial.println(average);
 
  float steinhart;
  steinhart = average / THERMISTORNOMINAL;     // (R/Ro)
  steinhart = log(steinhart);                  // ln(R/Ro)
  steinhart /= BCOEFFICIENT;                   // 1/B * ln(R/Ro)
  steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
  steinhart = 1.0 / steinhart;                 // Invert
  steinhart -= 273.15;                         // convert to C

  
  Serial.print("Temperature "); 
  Serial.print(steinhart);
  Serial.println(" *C");
  myNextion.setComponentValue("n4", steinhart);

 } 
{
   myNextion.setComponentText("t12", String(Prechargevolt));  // update text using original sensor value
   myNextion.setComponentValue("z2", speed);
   myNextion.setComponentText("t13", String(Systemvolt));  //12v battery gauge
   myNextion.setComponentValue("n0", BatteryAmp);
   myNextion.setComponentValue("n1", kmh);

   
   delay(100);        // delay in between reads for stability
 }
 }
  void magnet_detect()//This function is called whenever a magnet/interrupt is detected by the arduino
 {
   pulses++;
   Serial.println("detect");
 }

At the moment with a tire circumference of 1.835 m and a 48 tooth wheel you are interrupting the cpu to tell it the car has moved 38.229 mm. For the purpose of calculating speed and distance that is overkill so I would suggest if you want to stick with the current method of driving an interrupt on every tooth that you reduce the tooth count down to something like 12. The other significant difference with the old code is that after the nextion is updated you have a 100ms delay which restricts the screen update to 10Hz which is more than adequate. Your current code is dumping data up to the nextion in the void loop{} as fast as it can and that is a recipe for buffer overflows and display issues. If you want robust serial communications to avoid data corruption and data loss it is best to setup a timer event on the nextion at say 10 - 15Hz to request from the Arduino a new set of data to display. As a quick fix you could limit the nextion update frequency which may be enough to solve the glitches, use a thisMillis-lastMillis rather than a delay. I'm running 15Hz updates and the gauges move smoothly and text fields update without any noticeable jitter. I'll post a short YT vid if you like. I like your idea of sanity checking the data before updating the display, that could be done at either end of the chain.

I'll endeavor to setup a hall sensor on an RC motor to replicate your 48 tooth interrupt frequency and see if I can debug the issue.
And hats off to you and SplinterOz, thanks to the excellent commenting the code is very easy to read and understand.
 
kiwifiat said:
At the moment with a tire circumference of 1.835 m and a 48 tooth wheel you are interrupting the cpu to tell it the car has moved 38.229 mm. For the purpose of calculating speed and distance that is overkill so I would suggest if you want to stick with the current method of driving an interrupt on every tooth that you reduce the tooth count down to something like 12. The other significant difference with the old code is that after the nextion is updated you have a 100ms delay which restricts the screen update to 10Hz which is more than adequate. Your current code is dumping data up to the nextion in the void loop{} as fast as it can and that is a recipe for buffer overflows and display issues. If you want robust serial communications to avoid data corruption and data loss it is best to setup a timer event on the nextion at say 10 - 15Hz to request from the Arduino a new set of data to display. As a quick fix you could limit the nextion update frequency which may be enough to solve the glitches, use a thisMillis-lastMillis rather than a delay. I'm running 15Hz updates and the gauges move smoothly and text fields update without any noticeable jitter. I'll post a short YT vid if you like. I like your idea of sanity checking the data before updating the display, that could be done at either end of the chain.

I'll endeavor to setup a hall sensor on an RC motor to replicate your 48 tooth interrupt frequency and see if I can debug the issue.
And hats off to you and SplinterOz, thanks to the excellent commenting the code is very easy to read and understand.

I just noticed you are in Vancouver. when do you want to go for a ride?

I used a motorcycle sprocket and cut the middle out. Its 48tooth If I can make 110km/h ok with 48 I might make it 24 tooth. But I want to be sure I can read at 210-220 km/h. I will try to get time to test this as well. I have a new code splinter has given me I will test a bit more and share.
I would say splinter gets the credit for the code. I just did a bunch of digging on online and found snipits and put them together till I saw the gauges working ;) Then I asked for help when I found that was not good enough. :)
 
Back
Top