//ES use with a e-bike throttle into a e-bike controller
// also added a pot to set max phase current and battery current.
// uses a hall Current sensor instead of shunt.
// This example code is in the public domain.
// set servo for 1.1ms min - 1.8ms max ( or auto range )
/********************************************************
* A7 (throttle input)
* A6 (current pot input)
* A5 (Isensor input)
* A4 (battery input )
* D2 - lcd backlight
* D3 - (control) (throttle output) , RC filter is required on output for e-bike controller,, no rc filter for rc esc
* D4 - Serial clock out (SCLK)
* D5 - Serial data out (DIN)
* D6 - Data/Command select (D/C)
* D7 - LCD chip select (CS)
* D8 - LCD reset (RST)
*******************************************************/
// #include <Servo.h> // (rc esc)
//******Display nokia config******
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#define BackLight 2
Adafruit_PCD8544 display = Adafruit_PCD8544(4, 5, 6, 7, 8);
//**********************************
const int Throttle_Input_pin = 7; // Throttle input A7
const int Pot_Input_pin = 6; //Pot input A6
const int Isensor_Input_pin = 5; //Isensor input A5
const int Voltage_Input_pin = 4; //battery voltage input A4
const int Throttle_Output_pin = 3; //Throttle output D3.. RC filter need is e-bike controller .. no RC filter for rcesc
//const int Set_Min_Servo = 1000; // esc start with this as min throttle // (rc esc)
//const int Set_Max_Servo = 1800; // esc end with this as max throttle // (rc esc)
//int Servo_time = 1000; // (rc esc)
long phaseCurrent = 0; // phase current variable;
const int currentGain = 25; // (25 default) proportional gain setting for current limiting
const int phaseGain = 6; // (6 default)proportional gain for phase current limiting
const int sensor_spec = 20.0; //20.0 = 200A sensor... 26.7 (27.0)= 150A sensor.... 10.0 = 100A sensor
//const float Current_pot = 512; // un-rem to use a hard codded current limit ( 0-1023 = 0A upto the value of current sensor)
int Sensor_Cal = 512; // grab real value of this is set in setup section
int throttleCurrent = 0; // throttle setting to achieve current limit
int throttlePhase = 0; // throttle setting to achieve phase current limit
int phaseMax = 0;
int max_throttleOut = 1023;
int Throttle_Value=0;
int Throttle_Pulse=0;
int Set_Throt_Min = 55; // this needs to be the min value to remove dead band from throttle output , around 55
int Set_Throt_Max = 180; // this needs to be the max value to achieve full throttle without cutting out , around 180
int Cal_Throt_Min = 176; // this needs to be set to the real value of the throttle when fully closed;
int Cal_Throt_Max = 842; // this needs to be set to the real value of the throttle when fully open;
float SensorRT=1023; // variable to store value of current sensor.
float Current_pot=0; // variable to store value that sets max current/phase limit. //rem out.. if using pot to set current limits
float Vcc;
float Voltage;
float Battery_Volts; // calculated value voltage reading from the main battery
const float battery_adj = 13; // this is the value from the PD R2/(R1+R2) , the pd should be calculated so appox 5v is across R2 with the max input voltage
float sensor_spec_adj = 0.0 ;
float Current=0;
//******** time variables
float time;
float ampSec;
float ampH;
float msec;
float amphours_time;
float msec_last = 0.0;
//***********************
void setup()
{ //--- initialize serial communication at 9600 bits per second:
Serial.begin(9600);
// initialize the variables we're linked to
pinMode(Throttle_Output_pin, OUTPUT); // sets the D3 pin as output // (e-bike)
analogWrite(Throttle_Output_pin,0); // (e-bike)
// Servo_Pulse.attach(3); // Attach Servo_Pulse to pin 3 // (rc esc)
// Servo_Pulse.writeMicroseconds(Servo_time); // (rc esc)
pinMode(BackLight,OUTPUT);
digitalWrite(BackLight,LOW); // back light ON
delay(1000);
Sensor_Cal = analogRead(Isensor_Input_pin); // grabs offset of current sensor that must be connected at power up or the code will not funtion corectly.
display.begin(60); // Initialize lcd (default contrast 50-60)
display.clearDisplay(); // clears the screen and buffer
display.setTextSize(1);
display.setCursor(4, 25);
display.println("DIY");
display.setCursor(4, 35);
display.println("INITIALIZING");
display.display();
delay(2000);
Vcc = readVcc()/1000.0; // read actual arduino supply voltage;
sensor_spec_adj = ((Vcc-5)*sensor_spec / 5) +sensor_spec; // cal error factor of current sensor
}
void loop()
{
// throttle, pot, raw current reading/offsetting
Throttle_Value = analogRead(Throttle_Input_pin);
Throttle_Pulse = constrain(map(Throttle_Value,Cal_Throt_Min,Cal_Throt_Max,0,1023),0,1023); // set range on throttle and zero's throttle value
Current_pot = constrain(analogRead(Pot_Input_pin),0,1023); // rem out.. if this value is hard coded to speed things up a bit and to free up a adc input
SensorRT = map(analogRead(Isensor_Input_pin)- Sensor_Cal ,0,1023-Sensor_Cal,0,1023);
SensorRT = max(0,SensorRT);
Current_pot = (Throttle_Pulse*Current_pot)/1023; // use current pot to set overall max power%
phaseMax = Current_pot*2;
Throttle_Pulse=max(Throttle_Pulse,120); // Throttle pulse uses highest value
if (Current_pot < 2) max_throttleOut=0; // stop jitter and reset throttle value
// this routine computes the throttle output required for current control
throttleCurrent = max_throttleOut - currentGain*(SensorRT - Current_pot)/100;
throttleCurrent = max(throttleCurrent,0);
// compute the phase current phase current = shunt current/throttle
phaseCurrent = SensorRT * 1023 /max(max_throttleOut,25); //set last term to be appx 2.5% of throttle max - throttle min
throttlePhase = max_throttleOut - phaseGain*(phaseCurrent - phaseMax)/100;
throttlePhase = max(throttlePhase,0);
throttleCurrent = min(throttleCurrent,throttlePhase); //choose lower of phase or current throttle
max_throttleOut = min(Throttle_Pulse,throttleCurrent); // use the lower of current-limited or user requested throttle value
Throttle_Pulse = map(max_throttleOut,0,1023, Set_Throt_Min, Set_Throt_Max);// scale throttle output limits
analogWrite(Throttle_Output_pin,Throttle_Pulse); // write throttle to controller // (e-bike)
//Servo_time = map(max_throttleOut,0,1023,Set_Min_Servo,Set_Max_Servo); // scale output // (rc esc)
//Servo_Pulse.writeMicroseconds(Servo_time); //output servo signal to controller // (rc esc)
// DEBUG!
Vcc = readVcc()/1000.0; // read actual arduino supply voltage;
Current = (SensorRT*Vcc) / sensor_spec_adj; // calc current to display
Battery_Volts = (( analogRead(Voltage_Input_pin) * Vcc )/1023)*battery_adj;
//------------ amp hour routine start
msec = (millis() - msec_last) ;
time = (float) msec / 1000.0;
ampSec = Current*time;
amphours_time = ampSec/3600;
ampH = ampH + amphours_time;
msec_last = millis();
//-----------------------------
display.clearDisplay(); // clears the screen and buffer
display.setTextSize(2);
display.setCursor(0, 0);
display.print(Current);
display.println("A");
display.setCursor(0, 17);
display.print(Battery_Volts);
display.println("V");
display.setCursor(0, 34);
display.print(ampH);
display.println("Ah");
display.display();
}
//--- read 5v supply voltage using the 1.1v reference
long readVcc()
{ long result;
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
delay(2); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Convert
while (bit_is_set(ADCSRA,ADSC));
result = ADCL;
result |= ADCH<<8;
result = 1125300L / result;
return result;
}