// Alpha Motor Control program written by Steelmesh
// IR2110 Driver
// 75321 N-mosfet
// ACS756 hall effect current sensor, two 0.1uf caps for VIN/VOUT
// Hall Sensor pins: (1)VCC- 5v Arduino, (2)GND- Ground Arduino, (3)VIOUT- Analog Input Arduino, (4) from power source, (5) to load
int throttleCmd = 3; //Low PWM to IR2110 LIN; digital
int hallIn = 2; //signal from Hall Sensor
int cutOff = 0; //manual limit input pulse amount 0-255
int cruiseControl = 7; //Cruise control
int throttleSignal = 4; //Throttle input; analog
int brakeSwitch = 12; //Safety, pulse and cruise kill
int brakeLight = 10;
int brakeBlink = 0;
int photoSensor = 8;
boolean toggle = false; //toggle for cruise control
boolean toggleCruise = false; //toggling resume
boolean ampReducer = false; //toggle for ampDelta change reading
int limitRamp = 0; //Starting pulse adder is 0, if over limit, this value increase (pulse - this higher value = lowering pulse)
int ampSurge = 0; //Counter for amp surge sequence
int cruiseCount = 0;
int resumePulse = 0;
int toggleDebug = 0;
int ampDelta = 0;
int buzzer = 11;
int buzzerCount = 0;
//*******MANUAL INPUTS BEGIN*******
int ampLimit = 25; //manual input actual amps, see also limitRamp above
int sensorCal = 531; //531 manual input raw input at zero amps for Hall Sensor
int sensorSpec = 40; //Hall Sensor, 40 mV per Amp
int cruiseLimit = 20; //manual input for amps, cruise economy
int cruiseDebouncePre = 10; //Actual ms to re-read button
int cruiseDebouncePost = 300; //Actual ms to wait for operator to release button
int cruiseCycles = 300; //number of processing loops before it toggles resume off
int ampSurgeMax = 5; //A loop-counter value to allow the amp surge mode, it will bypass limitRamp for "ampSurgeMax loop cycles"
int ampSurgeThreshold = 240; //pulse value for minimum throttle pulse to kick in ampSurge, see ampSurge above
int ampSmoothing = 2; //Actual amps to kick in ampDelta smoothing
int ampReducerCount = 0;
int duskDawnSet = 300; //photoSensor actual value
//*******MANUAL INPUTS END*******
void setup()
{
Serial.begin(9600);
pinMode(throttleCmd, OUTPUT);
pinMode(brakeSwitch, INPUT);
pinMode(throttleSignal, INPUT);
pinMode(cruiseControl, INPUT);
pinMode(buzzer, OUTPUT);
pinMode(brakeLight, OUTPUT);
}
void loop()
{
if(buzzerCount < 1) //initial buzzer
{
digitalWrite(buzzer, HIGH);
delay(130);
digitalWrite(buzzer, LOW);
buzzerCount = 1;
}
int throttleIn = analogRead(throttleSignal); //Main read throttle, declare pulse
int pulse = constrain(throttleIn, 0, 1023);
pulse = map(pulse, 0, 1022, 0, 254);
//pulse smoothing
int cruisePulse = pulse;
if (pulse < 55)
{
limitRamp = 0; //Reset rampLimit to zero at zero throttle
}
if (pulse < ampSurgeThreshold)
{
ampSurge = 0; //Reset ampSurge counter if throttle falls below threshold
}
int ampRead = analogRead(hallIn); //Read hall sensor output
ampRead = constrain(ampRead, sensorCal, 1023); //constrain to manual sensor calibration
int actualAmp = ampRead - sensorCal; //Declare new int for conversion
actualAmp = (actualAmp * 4.9) / sensorSpec; //4.9 * Analog signal =~ mV, divide by example: "ACS756 spec: 40mV/1A"
int hallMv = analogRead(hallIn) * 4.9; //debugging to view mV
// ***************CRUISE CONTROL BEGIN*****************
//toggle Cruise
if (digitalRead(cruiseControl) == HIGH && toggle == false)
{
delay(cruiseDebouncePre);
if (digitalRead(cruiseControl) == HIGH && toggle == false) //debounce
{
toggle = !toggle;
if (toggleCruise == false && pulse > 80)
{
throttleIn = analogRead(throttleSignal); //Grab pulse value immediately
pulse = constrain(throttleIn, 0, 1023);
pulse = map(pulse, 0, 1022, 0, 254);
limitRamp = 0;
}
if (toggleCruise == true && pulse > 80)
{
throttleIn = analogRead(throttleSignal); //Grab pulse value immediately
pulse = constrain(throttleIn, 0, 1023);
pulse = map(pulse, 0, 1022, 0, 254);
limitRamp = 0;
}
if (toggleCruise == true && pulse < 80)
{
pulse = resumePulse; //If shut down was via braking, this saves cruise...resumePulse can only initially be set by entering cruise loop first with toggleCruise false
pulse = constrain(pulse, 0, 254);
Serial.println("Resume Saved");
}
delay(cruiseDebouncePost);
Serial.println("Cruise On");
}
}
//toggle Cruise end
//Cruise loop begin
while (toggle == true)
{
Serial.print("Cruise Running at ");
Serial.print(pulse);
Serial.print(" pulse");
Serial.print(" ");
Serial.print("Amps: ");
Serial.print(actualAmp);
Serial.println("");
ampRead = analogRead(hallIn);
ampRead = constrain(ampRead, sensorCal, 1023);
actualAmp = ampRead - sensorCal;
actualAmp = (actualAmp * 4.9) / sensorSpec;
int cruiseOnSmoothing = cruiseLimit; //smooth out amp surge when cruise resuming
cruiseOnSmoothing = cruiseOnSmoothing * 1.5;
if (actualAmp > cruiseOnSmoothing)
{
limitRamp = limitRamp + 30;
limitRamp = constrain(limitRamp, 0, 254);
}
//current limiter function under cruise
if (actualAmp > cruiseLimit)
{
limitRamp = limitRamp + 2;
limitRamp = constrain(limitRamp, 0, 254);
}
if (actualAmp < cruiseLimit)
{
limitRamp = limitRamp - 2;
limitRamp = constrain(limitRamp, 0, 254);
}
cruisePulse = pulse - limitRamp;
cruisePulse = constrain(cruisePulse, 0, 254);
analogWrite(throttleCmd, cruisePulse);
int brakeRead = digitalRead(brakeSwitch);
if (brakeRead == LOW)
{
toggle = !toggle;
toggleCruise = false; //reset resume pulse number by toggling it off for next command
analogWrite(throttleCmd, 0);
pulse = 0;
Serial.println("Cruise OFF brake");
delay(cruiseDebouncePost);
}
int cruiseRead = digitalRead(cruiseControl);
if (cruiseRead == HIGH && toggle == true)
{
delay(cruiseDebouncePre);
if (cruiseRead == HIGH && toggle == true)
{
toggle = !toggle;
resumePulse = pulse; //if user uses the brake switch to cut off cruise, it will save this value as resumePulse for cruiseCycles cycles
toggleCruise = true; //toggle on cruise resume pulse
cruiseCount = 0; //reset timer (timer to deactivate resume)
analogWrite(throttleCmd, 0);
Serial.println("Cruise OFF button");
Serial.println("Cruise Pulse Saved");
Serial.println(resumePulse);
delay(cruiseDebouncePost);
}
}
}
//********************CRUISE CONTROL END**************************
while (digitalRead(brakeSwitch) == LOW)
{
analogWrite(throttleCmd, cutOff);
digitalWrite(brakeLight, HIGH);
delay(200);
Serial.println("Brake Shut Down");
}
int lightSwitch = analogRead(photoSensor);
lightSwitch = constrain(lightSwitch, 0, 800);
if (brakeBlink <= 2 && lightSwitch <= duskDawnSet)
{
digitalWrite(brakeLight, HIGH);
brakeBlink = brakeBlink + 1;
}
if (brakeBlink > 2 && brakeBlink <= 15 && lightSwitch <= duskDawnSet)
{
digitalWrite(brakeLight, LOW);
brakeBlink = brakeBlink + 1;
}
if (brakeBlink >= 16)
{
brakeBlink = 0;
}
if (lightSwitch > duskDawnSet)
{
digitalWrite(brakeLight, LOW);
}
Serial.print("Pulse: ");
Serial.print(pulse);
Serial.print(" ");
Serial.print("Amps: ");
Serial.print(actualAmp);
Serial.print(" ");
Serial.print("Hall mv: ");
Serial.print(hallMv);
Serial.print(" ");
// Serial.print("ActualV: ");
// Serial.print(actualVolt);
// Serial.print(" ");
Serial.print("Surge Count: ");
Serial.print(ampSurge);
Serial.print(" ");
Serial.print("BrakeSw: ");
Serial.print(digitalRead(brakeSwitch));
Serial.print(" ");
Serial.print("Resume: ");
Serial.print(resumePulse);
if (toggleCruise == false)
{
toggleDebug = 0;
}
else
{
toggleDebug = 1;
}
Serial.print(" ");
Serial.print("Cruise: ");
Serial.print(toggleDebug);
Serial.println("");
if (actualAmp > ampLimit) //Main current limiter function
{
limitRamp = limitRamp + 2;
limitRamp = constrain(limitRamp, 0, 254);
Serial.println("OVERLIMIT");
}
else
{
limitRamp = limitRamp - 2;
limitRamp = constrain(limitRamp, 0, 254);
}
//if (ampReducer == false && ampReducerCount < 1) //grab amp reading into ampDelta
//{
// ampDelta = actualAmp;
// ampDelta = ampDelta + ampSmoothing;
// ampReducer = true;
// Serial.println("AmpReadGrab");
//}
//
//ampReducerCount = ampReducerCount + 1;
//
//if (ampReducer == true && ampReducerCount > 3) //wait for ampReducerCount counter to reset toggle
//{
// ampReducer = false;
// ampReducerCount = 0;
//}
if (ampSurge < ampSurgeMax && pulse > ampSurgeThreshold) //AMP SURGE MODE, Full Throttle, gives "ampSurgeMax cycles" of full pulse commands bypassing limitRamp
{
analogWrite(throttleCmd, pulse);
ampSurge = ampSurge + 1;
limitRamp = 0; //Prevent adding to limitRamp while in ampSurge mode, so when exiting ampSurge, limitRamp starts changing
Serial.println("SURGE MODE");
}
// else if (ampDelta < actualAmp)
// {
// pulse = pulse - 30;
// pulse = constrain(pulse, 0, 254);
// analogWrite(throttleCmd, pulse);
// Serial.println("Amp Reducer");
// }
else
{
pulse = pulse - limitRamp; //Current ramping equation, if not in ampSurge mode
pulse = constrain(pulse, 0, 254);
analogWrite(throttleCmd, pulse); //Main Throttle Command Line
}
int lastPulse = pulse; //grabs what the last pulse was for pulse smoothing
//delay(50); //Serial.print sake
}