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

Soon I will put the more powerfull IGBTs in and crank it up some more!
that's what i'm talk'n about! :mrgreen:
 
Having some fun today

more power to come


[youtube]h5TEZhysam8[/youtube]
 
Got things near perfect today


[youtube]kXIR4wacB4U[/youtube]
 
2.93 And I have it running flawless now.
 
Awesome work Arlo, been following all your recent videos, amazing to see it progress to near-OEM level of experience!

So keen to see this hit the drag strip and push the limits, it's going to blow some minds for sure. Have you got a guess for what trap speeds are possible with the upgraded IGBTs and the wick turned up all the way? I ask about trap speeds because ET's are incredibly variable depending on rubber and chassis setup.

I managed to run a 12.73 years ago with a junkyard 1500cc motor and a stock turbo the size of a childs fist, despite trapping a measly 168km/h. Chassis setup and data driven decisions around shift timing plus a bunch of practice shaved a full two seconds off ET from the starting point with exactly the same power. Unfortunately some of those setup changes take away from the street car experience, wheel alignment and spring/shock rates for one. Ended up running 18kg/mm springs in the rear (off the shelf coilovers were *4kg/mm* for comparison)
 
fechter said:
I want to go for a ride!

Amazing what you've gotten that Leaf motor to do.


Thanks,

More to come. My brother wants to try the 100$ bill trick again... Lol So I will add 100 phase amps just to be safe.


But I do plan to drive it down the coast in time when I get charging sorted out. I have 8 meanwells on there now but thats only 3kw of charging so I need more charging for longer trips. I am working on my own charger but its quite challenging.
 
Arlo1 said:
Thanks,

More to come. My brother wants to try the 100$ bill trick again... Lol So I will add 100 phase amps just to be safe.


But I do plan to drive it down the coast in time when I get charging sorted out. I have 8 meanwells on there now but thats only 3kw of charging so I need more charging for longer trips. I am working on my own charger but its quite challenging.

Will you fix the windsceen for the trip? :mrgreen:
(obviously just the jealousy talking here)
 
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
 
XLR8 said:
Arlo1 said:
Working on some gauges as well. :)
Can you tell us about your gauges? They look very good.


Thanks. The background is a picture taken here in Nanaimo last summer during a lightning storm. I purchased a Nextion touch screen and programmed it and and arduino to run it.Nextion is a touch screen which comes with a driver built on to the back and you download free software to make your own gauges then you just flash it from a SD card. The code from arduino is simple it just sends the values over the rs232 to the touch screen and the touch screen does the rest. Its actually not hard. I have had some help from Tony as well going over the code as I am not proficient in code yet.
But so far I have the voltage for the 12v battery and the traction pack as well as the temp for the motor and this morning at 1am I added controller temp and now I am making a current sensor so I can know the Amps and watts. Then I will figure out how to work maths for Wh and wh/km!

All in time ;)

https://nextion.itead.cc/

Here is my current code
Edited to add current and KW calculations.

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

// Tempreture constants
#define THERMISTORPIN A3 // which analog pin to connect
#define THERMISTORPIN2 A4  //  anlog pin for controller temp
#define THERMISTORNOMINAL 15000  // resistance at 25 degrees C
#define THERMISTORNOMINAL2 10000  // resisatance at 25 deg C for controller 
#define TEMPERATURENOMINAL 25    // temp. for nominal resistance (almost always 25 C)
#define TEMPERATURENOMINAL2 25   // temp. for second therminstor resistance
#define BCOEFFICIENT 3950       // The beta coefficient of the thermistor (usually 3000-4000)
#define BCOEFFICIENT2 3950       //  Teh bete coefficient for therminstor 2
#define SERIESRESISTOR 9950     // the value of the 'other' resistor
#define SERIESRESISTOR2 9950   // the value for the second other resistor 
#define NUMSAMPLES 3             // how many samples to take and average, more takes longer but is more 'smooth'
#define SAMPLEDELAY 10          // how many millis to wait for new sample

// 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
#define HIGHVOLT 480          // Maximum pack voltage
#define LOWVOLT 340           // minimum pack voltage
#define PRECHARGEPERCENT 0.95 //  precharge complete percentage
#define PULSEPERROT 4.8         // pulses per rotation of speed sensor
#define WHEELCIRC .1835       // circumference of wheel in meters


// display setup
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
int kmh2 = 0;
int Amp2 = 0;
float PrechargeVolt=0, SystemVolt=0, BatteryAmp=0, PackVolt=0, temp=0, temp2=0, KW=0;
unsigned long timeold; 
unsigned long millisecsPerHour = 3600000;
unsigned int wheelcirc = .001835;
/*
 * 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, RISING);  // 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)
{
  // Read voltages and currents
  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 = (analogRead(AMPPIN)*1.710655-890);     // Bidirectional current sensor 2.5v at middle
  KW = (BatteryAmp*PrechargeVolt/1000);
    Amp2 = (BatteryAmp+100)/2.8676470;   
      if(Amp2<66)
   Amp2 = 295 + Amp2;
   else
   Amp2 = Amp2 - 66;
  
  // 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);
  }

  if (millis() - timeold >= 100)  
  {   
    detachInterrupt(0);
    kmh = (WHEELCIRC / 1000 * (pulses/PULSEPERROT))  * millisecsPerHour / (millis() - timeold);
    timeold = millis();
    pulses = 0;
    attachInterrupt(0, irspeed, FALLING);
    kmh2 = kmh*1.25;
     if(kmh2<60)
   kmh2 = 300 + kmh2;
  else  
  kmh2 = kmh2  - 60; // get the needle to start at 0 which is 300 deg in nextion
  }

    
  //Write it out to serial port
  Serial.print("Speed: ");
  Serial.println(kmh, DEC);

  
  temp = readThermistor();
  temp2 = readThermistor2 ();
  Serial.print("Temperature "); 
  Serial.print(temp);
  Serial.println(" *C");
}

/*
 * Update the display with all the values
 */
void updateDash(void)
{
   int (speed[0]);
   myNextion.setComponentValue("n4", temp);
   myNextion.setComponentText("t12", String(PrechargeVolt));  // update text using original sensor value
   myNextion.setComponentValue("z2", kmh2);
   myNextion.setComponentText("t13", String(SystemVolt));  //12v battery gauge
   myNextion.setComponentValue("n0", BatteryAmp);
   myNextion.setComponentValue("n1", kmh);
   myNextion.setComponentValue("n5", temp2);
   myNextion.setComponentValue("n6", KW);
   myNextion.setComponentValue("z1", Amp2);
} 

/*
 * Utility function to get the tempreture in degrees C from the thermister
 */
float readThermistor() 
{

  float reading = 0;
    
  // take N samples in a row, with a slight delay
  for (int i=0; i< NUMSAMPLES; i++) {
   reading += analogRead(THERMISTORPIN);
   delay(10);
  }
 
  reading /= NUMSAMPLES;
 
  //Serial.println("Average analog reading "); 
  //Serial.println(reading);
 
  // convert the value to resistance
  reading = 1023 / reading - 1;
  reading = SERIESRESISTOR / reading;
  //Serial.print("Thermistor resistance "); 
  //Serial.println(reading);
 
  float steinhart;
  steinhart = reading / 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
  
  return steinhart;
  
}
/*
 * Utility function to get the tempreture in degrees C from the thermister
 */
float readThermistor2() 
{

  float reading = 0;
    
  // take N samples in a row, with a slight delay
  for (int i=0; i< NUMSAMPLES; i++) {
   reading += analogRead(THERMISTORPIN2);
   delay(10);
  }
 
  reading /= NUMSAMPLES;
 
  //Serial.println("Average analog reading "); 
  //Serial.println(reading);
 
  // convert the value to resistance
  reading = 1023 / reading - 1;
  reading = SERIESRESISTOR2 / reading;
  //Serial.print("Thermistor2 resistance "); 
  //Serial.println(reading);
 
  float steinhart;
  steinhart = reading / THERMISTORNOMINAL2;          // (R/Ro)
  steinhart = log(steinhart);                       // ln(R/Ro)
  steinhart /= BCOEFFICIENT2;                        // 1/B * ln(R/Ro)
  steinhart += 1.0 / (TEMPERATURENOMINAL2 + 273.15); // + (1/To)
  steinhart = 1.0 / steinhart;                      // Invert
  steinhart -= 273.15;                              // convert to C
  
  return steinhart;
  
}
 
You should add some digital filtering to stabilise the readings a bit.

Lets say the signal (or reading) you want to filter is x . Then

filtered_x = filtered_x + alpha * ( x - filtered_x )

here alpha determines how much filtering there is, valid range is between 0 and 1 with 0 being an infinite amount of filtering and 1 being no filtering.
I would start with alpha = 0.1 and then try some different values.
 
Lebowski said:
You should add some digital filtering to stabilise the readings a bit.

Lets say the signal (or reading) you want to filter is x . Then

filtered_x = filtered_x + alpha * ( x - filtered_x )

here alpha determines how much filtering there is, valid range is between 0 and 1 with 0 being an infinite amount of filtering and 1 being no filtering.
I would start with alpha = 0.1 and then try some different values.

Thanks Lebowski and I agree. I have been adding caps and RC filters to most circuits but some digital filtering would be wise.
 
I found this.
http://playground.arduino.cc/Main/DigitalSmooth

I will try to work it into mine.

I got the Amp gauge and KW gauge working and I would like to add some smoothing. I have 2 caps on the input and its not quite smooth enough.
Its tricky because I am using a 800a current sensor.
I also need to find a way to make sure it Zeros at startup everytime.

Code:
/* digitalSmooth
 Paul Badger 2007
 A digital smoothing filter for smoothing sensor jitter 
 This filter accepts one new piece of data each time through a loop, which the 
 filter inputs into a rolling array, replacing the oldest data with the latest reading.
 The array is then transferred to another array, and that array is sorted from low to high. 
 Then the highest and lowest %15 of samples are thrown out. The remaining data is averaged
 and the result is returned.

 Every sensor used with the digitalSmooth function needs to have its own array to hold 
 the raw sensor values. This array is then passed to the function, for it's use.
 This is done with the name of the array associated with the particular sensor.
 */

#define SensorPin1      0
#define SensorPin2      0
#define filterSamples   13              // filterSamples should  be an odd number, no smaller than 3
int sensSmoothArray1 [filterSamples];   // array for holding raw sensor values for sensor1 
int sensSmoothArray2 [filterSamples];   // array for holding raw sensor values for sensor2 

int rawData1, smoothData1;  // variables for sensor1 data
int rawData2, smoothData2;  // variables for sensor2 data

void setup(){
  Serial.begin(9600);
}
void loop(){       // test the digitalSmooth function
  rawData1 = analogRead(SensorPin1);                        // read sensor 1
  smoothData1 = digitalSmooth(rawData1, sensSmoothArray1);  // every sensor you use with digitalSmooth needs its own array

    Serial.print(rawData1);
    Serial.print("   ");
    Serial.println(smoothData1);

  rawData2 = analogRead(SensorPin2);                        // read sensor 2
  smoothData2 = digitalSmooth(rawData2, sensSmoothArray2);  // every sensor you use with digitalSmooth needs its own array

}

int digitalSmooth(int rawIn, int *sensSmoothArray){     // "int *sensSmoothArray" passes an array to the function - the asterisk indicates the array name is a pointer
  int j, k, temp, top, bottom;
  long total;
  static int i;
 // static int raw[filterSamples];
  static int sorted[filterSamples];
  boolean done;

  i = (i + 1) % filterSamples;    // increment counter and roll over if necc. -  % (modulo operator) rolls over variable
  sensSmoothArray[i] = rawIn;                 // input new data into the oldest slot

  // Serial.print("raw = ");

  for (j=0; j<filterSamples; j++){     // transfer data array into anther array for sorting and averaging
    sorted[j] = sensSmoothArray[j];
  }

  done = 0;                // flag to know when we're done sorting              
  while(done != 1){        // simple swap sort, sorts numbers from lowest to highest
    done = 1;
    for (j = 0; j < (filterSamples - 1); j++){
      if (sorted[j] > sorted[j + 1]){     // numbers are out of order - swap
        temp = sorted[j + 1];
        sorted [j+1] =  sorted[j] ;
        sorted [j] = temp;
        done = 0;
      }
    }
  }

/*
  for (j = 0; j < (filterSamples); j++){    // print the array to debug
    Serial.print(sorted[j]); 
    Serial.print("   "); 
  }
  Serial.println();
*/

  // throw out top and bottom 15% of samples - limit to throw out at least one from top and bottom
  bottom = max(((filterSamples * 15)  / 100), 1); 
  top = min((((filterSamples * 85) / 100) + 1  ), (filterSamples - 1));   // the + 1 is to make up for asymmetry caused by integer rounding
  k = 0;
  total = 0;
  for ( j = bottom; j< top; j++){
    total += sorted[j];  // total remaining indices
    k++; 
    // Serial.print(sorted[j]); 
    // Serial.print("   "); 
  }

//  Serial.println();
//  Serial.print("average = ");
//  Serial.println(total/k);
  return total / k;    // divide by number of samples
}
 
Arlo1 said:
I found this.
http://playground.arduino.cc/Main/DigitalSmooth

I will try to work it into mine.

I got the Amp gauge and KW gauge working and I would like to add some smoothing. I have 2 caps on the input and its not quite smooth enough.
Its tricky because I am using a 800a current sensor.
I also need to find a way to make sure it Zeros at startup everytime.

this is a digital averager which is not that good a filter
View attachment 1
the one I described is a 1st order lowpass filter which typically has better high frequency supression (plus you don't need to remember the signals history)
 
Lebowski said:
You should add some digital filtering to stabilise the readings a bit.

Lets say the signal (or reading) you want to filter is x . Then

filtered_x = filtered_x + alpha * ( x - filtered_x )

here alpha determines how much filtering there is, valid range is between 0 and 1 with 0 being an infinite amount of filtering and 1 being no filtering.
I would start with alpha = 0.1 and then try some different values.


Nice bit of code. so it allows a maximum rate of change compared to the previous filtered value.
I assume you set filtered x to zero to start. I might add that to the code Arlo is using
 
Arlo1 said:
XLR8 said:
Arlo1 said:
Working on some gauges as well. :)
Can you tell us about your gauges? They look very good.


Thanks. The background is a picture taken here in Nanaimo last summer during a lightning storm. I purchased a Nextion touch screen and programmed it and and arduino to run it.Nextion is a touch screen which comes with a driver built on to the back and you download free software to make your own gauges then you just flash it from a SD card. The code from arduino is simple it just sends the values over the rs232 to the touch screen and the touch screen does the rest. Its actually not hard. I have had some help from Tony as well going over the code as I am not proficient in code yet.
But so far I have the voltage for the 12v battery and the traction pack as well as the temp for the motor and this morning at 1am I added controller temp and now I am making a current sensor so I can know the Amps and watts. Then I will figure out how to work maths for Wh and wh/km!

All in time ;)

https://nextion.itead.cc/

Here is my current code
Edited to add current and KW calculations.

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.

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

// Tempreture constants
#define THERMISTORPIN A3 // which analog pin to connect
#define THERMISTORPIN2 A4  //  anlog pin for controller temp
#define THERMISTORNOMINAL 15000  // resistance at 25 degrees C
#define THERMISTORNOMINAL2 10000  // resisatance at 25 deg C for controller 
#define TEMPERATURENOMINAL 25    // temp. for nominal resistance (almost always 25 C)
#define TEMPERATURENOMINAL2 25   // temp. for second therminstor resistance
#define BCOEFFICIENT 3950       // The beta coefficient of the thermistor (usually 3000-4000)
#define BCOEFFICIENT2 3950       //  Teh bete coefficient for therminstor 2
#define SERIESRESISTOR 9950     // the value of the 'other' resistor
#define SERIESRESISTOR2 9950   // the value for the second other resistor 
#define NUMSAMPLES 3             // how many samples to take and average, more takes longer but is more 'smooth'
#define SAMPLEDELAY 10          // how many millis to wait for new sample

// 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
#define HIGHVOLT 480          // Maximum pack voltage
#define LOWVOLT 340           // minimum pack voltage
#define PRECHARGEPERCENT 0.95 //  precharge complete percentage
#define PULSEPERROT 4.8         // pulses per rotation of speed sensor
#define WHEELCIRC .1835       // circumference of wheel in meters
#define FILTER_ALPHA 0.1      // filter co-efficient valid range 0 -> 1  0 = infinite filtering   1 = no filtering


// display setup
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, temp=0, temp2=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 voltages and currents
  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_ALPHA*((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);
  }

  if (millis() - timeold >= 100)  
  {   
    detachInterrupt(0);
    kmh = (WHEELCIRC / 1000 * (pulses/PULSEPERROT))  * millisecsPerHour / (millis() - timeold);  // raw calculation
    //kmh = kmh + FILTER_ALPHA*(calc -kmh);  // filtered speed
    timeold = millis();
    pulses = 0;
    attachInterrupt(0, irspeed, FALLING);
  }
    
  //Write it out to serial port
  Serial.print("Speed: ");
  Serial.println(kmh, DEC);

  temp = temp + FILTER_ALPHA * (readThermistor(THERMISTORPIN) - temp);     // filtered read
  temp2 = temp2 + FILTER_ALPHA * (readThermistor(THERMISTORPIN2) - temp2); // filtered read
  
  Serial.print("Temperature 1 "); 
  Serial.print(temp);
  Serial.println(" *C");
  Serial.print("Temperature 2 "); 
  Serial.print(temp2);
  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", temp);
   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", temp2);
   myNextion.setComponentValue("n6", KW);
   myNextion.setComponentValue("z1", displayAMPS);
} 

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

  float reading = 0;
    
  // take N samples in a row, with a slight delay
  //for (int i=0; i< NUMSAMPLES; i++) {
  // reading += analogRead(thermPin);
  // delay(10);
  //}
 
  //reading /= NUMSAMPLES;
  reading = analogRead(thermPin);
 
  //Serial.println("Average analog reading "); 
  //Serial.println(reading);
 
  // convert the value to resistance
  reading = 1023 / reading - 1;
  reading = SERIESRESISTOR / reading;
  //Serial.print("Thermistor resistance "); 
  //Serial.println(reading);
 
  float steinhart;
  steinhart = reading / 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
  
  return steinhart;
  
}
 
Awesome Thanks so much Tony. I am stoked for you to run one of these setups! This thing is getting brutally fast.

Slicks on and settings are about as high as I plan to run the 600a igbts!
 

Attachments

  • 079.jpg
    079.jpg
    56.2 KB · Views: 2,995
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.

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

// Tempreture constants
#define THERMISTORPIN A3 // which analog pin to connect
#define THERMISTORPIN2 A4  //  anlog pin for controller temp
#define THERMISTORNOMINAL 15000  // resistance at 25 degrees C
#define THERMISTORNOMINAL2 10000  // resisatance at 25 deg C for controller 
#define TEMPERATURENOMINAL 25    // temp. for nominal resistance (almost always 25 C)
#define TEMPERATURENOMINAL2 25   // temp. for second therminstor resistance
#define BCOEFFICIENT 3950       // The beta coefficient of the thermistor (usually 3000-4000)
#define BCOEFFICIENT2 3950       //  Teh bete coefficient for therminstor 2
#define SERIESRESISTOR 9950     // the value of the 'other' resistor
#define SERIESRESISTOR2 9950   // the value for the second other resistor 
#define NUMSAMPLES 3             // how many samples to take and average, more takes longer but is more 'smooth'
#define SAMPLEDELAY 10          // how many millis to wait for new sample

// 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
#define HIGHVOLT 480          // Maximum pack voltage
#define LOWVOLT 340           // minimum pack voltage
#define PRECHARGEPERCENT 0.95 //  precharge complete percentage
#define PULSEPERROT 4.8         // pulses per rotation of speed sensor
#define WHEELCIRC .1835       // circumference of wheel in meters
#define FILTER_ALPHA 0.1      // filter co-efficient valid range 0 -> 1  0 = infinite filtering   1 = no filtering


// display setup
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, temp=0, temp2=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 voltages and currents
  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_ALPHA*((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);
  }

  if (millis() - timeold >= 100)  
  {   
    detachInterrupt(0);
    kmh = (WHEELCIRC / 1000 * (pulses/PULSEPERROT))  * millisecsPerHour / (millis() - timeold);  // raw calculation
    //kmh = kmh + FILTER_ALPHA*(calc -kmh);  // filtered speed
    timeold = millis();
    pulses = 0;
    attachInterrupt(0, irspeed, FALLING);
  }
    
  //Write it out to serial port
  Serial.print("Speed: ");
  Serial.println(kmh, DEC);

  temp = temp + FILTER_ALPHA * (readThermistor(THERMISTORPIN) - temp);     // filtered read
  temp2 = temp2 + FILTER_ALPHA * (readThermistor(THERMISTORPIN2) - temp2); // filtered read
  
  Serial.print("Temperature 1 "); 
  Serial.print(temp);
  Serial.println(" *C");
  Serial.print("Temperature 2 "); 
  Serial.print(temp2);
  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", temp);
   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", temp2);
   myNextion.setComponentValue("n6", KW);
   myNextion.setComponentValue("z1", displayAMPS);
} 

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

  float reading = 0;
    
  // take N samples in a row, with a slight delay
  //for (int i=0; i< NUMSAMPLES; i++) {
  // reading += analogRead(thermPin);
  // delay(10);
  //}
 
  //reading /= NUMSAMPLES;
  reading = analogRead(thermPin);
 
  //Serial.println("Average analog reading "); 
  //Serial.println(reading);
 
  // convert the value to resistance
  reading = 1023 / reading - 1;
  reading = SERIESRESISTOR / reading;
  //Serial.print("Thermistor resistance "); 
  //Serial.println(reading);
 
  float steinhart;
  steinhart = reading / 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
  
  return steinhart;
  
}

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.
 
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.
 
Back
Top