Arduino throttle code: amp limiting and cruise control

steelmesh

100 W
Joined
Jun 28, 2012
Messages
123
Location
Michigan
This is the working prototype code, for off-road use only ;)

Sensitivity = 40mV/A for the 50amp current transducer (hall), 20mV/A for 100amp is also available
ACS756 http://www.allegromicro.com/en/Products/Part_Numbers/0756/0756.pdf

Code:
// Alpha Motor Control program written by Steelmesh 2012
// Use any external motor controller with 0-5v throttle signal input
// ACS756 hall effect current sensor, two 0.1uf caps for VIN/VOUT, VIN = 5v
// ACS756 pins: (1)VCC- 5v Arduino, (2)GND- Ground Arduino, (3)VIOUT- Analog Input Arduino, (4) GND, (5) to Motor Controller - Battery Negative
// Common Ground: Arduino, Motor Controller, Batteries

//************REFERENCE IN/OUT******************
//  pinMode(throttleCmd, OUTPUT);
//  pinMode(brakeSwitch, INPUT);
//  pinMode(throttleSignal, INPUT);
//  pinMode(cruiseControl, INPUT);
//  pinMode(buzzer, OUTPUT);
//  pinMode(brakeLight, OUTPUT);

int throttleCmd = 3; //0-5v *PWM* output throttle signal to external motor controller
int hallIn = 2; //0-5v signal from Hall Sensor
int cruiseControl = 7; //Cruise control activate/deactivate
int throttleSignal = 4; //Throttle input; analog
int brakeSwitch = 12; //Safety, pulse and cruise kill
int brakeLight = 10; //out brake lamp transistor / relay
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; //resumePulse will be set after entering cruise and hitting resume
int toggleDebug = 0; //debugging
int ampDelta = 0; //change in amperage
int buzzer = 11; //startup buzzer
int buzzerCount = 0; //

//*******MANUAL INPUTS BEGIN*******
int ampLimit = 25; //manual input actual amp max set point, see also limitRamp above
int sensorCal = 531; //531 manual input raw input at zero amps for Hall Sensor, ~2.6v with 5v input to the ACS756
int sensorSpec = 40; //Hall Sensor spec = 40 mV per 1 Amp

int cruiseLimit = 20; //manual input for max amps during 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 = 300000; //number of processing loops before it toggles resume ability off

//"Turbo button"
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 dusk/dawn
//*******MANUAL INPUTS END*******
// Some unused ints are being declared above

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) //initialized buzzer, only happens once
  {
    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);

  int cruisePulse = pulse; //to maintain same throttle level when entering cruise
  
  if (pulse < 55) //to reset Reset rampLimit to zero at zero throttle, 55 chosen based on throttle output characteristics
  {
    limitRamp = 0;
  }
  
  if (pulse < ampSurgeThreshold) //Reset ampSurge counter if throttle falls below threshold
  {
    ampSurge = 0; 
  }
  
  int ampRead = analogRead(hallIn); //Read raw hall sensor output signal hallIn
  ampRead = constrain(ampRead, sensorCal, 1023); //constrain to sensor output range, sensorCal is zero amps
  int actualAmp = ampRead - sensorCal; //Declare new int for conversion, actualAmp is Delta signal change above sensorCal
  actualAmp = (actualAmp * 4.9) / sensorSpec; //Convert actualAmp to mV integer, divide by 40 "ACS756 = 40mV/1A" to get actual Amp integer
  
  int hallMv = analogRead(hallIn) * 4.9; //debugging to view mV, Serial.print(hallMv) is below
  
  // ***************CRUISE CONTROL BEGIN*****************
  
  //toggle Cruise
  if (digitalRead(cruiseControl) == HIGH && toggle == false) //Read cruise button input
  {
    delay(cruiseDebouncePre);
    if (digitalRead(cruiseControl) == HIGH && toggle == false) //debounce
    {
    toggle = !toggle;
      if (toggleCruise == false && pulse > 80) 
      {
        throttleIn = analogRead(throttleSignal);  //Grab throttle 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 throttle pulse value immediately
        pulse = constrain(throttleIn, 0, 1023);
        pulse = map(pulse, 0, 1022, 0, 254);
        limitRamp = 0;
      }
      //Cruise resume at saved pulse
      if (toggleCruise == true && pulse < 80) //No throttle threshold condition
      {
        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"); //Bingo
      }
    delay(cruiseDebouncePost);
    Serial.println("Cruise On"); 
    }
  }
  //toggle Cruise end

  //Cruise while loop begin
  while (toggle == true)
  {
    Serial.print("Cruise Running at "); //only prints when entering cruise
    Serial.print(pulse);
    Serial.print(" pulse");
    Serial.print(" ");
    Serial.print("Amps: ");
    Serial.print(actualAmp);
    Serial.println("");

  
    ampRead = analogRead(hallIn); // Monitor amps see above for comments
    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); //Here is where it hits the pavement

    
    int brakeRead = digitalRead(brakeSwitch); //BRAKE SWITCH
      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); //CRUISE BUTTON
      if (cruiseRead == HIGH && toggle == true)
         {
         delay(cruiseDebouncePre);
         if (cruiseRead == HIGH && toggle == true)
           {
           toggle = !toggle;
           resumePulse = pulse; //if user uses the cruise button 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****
   
  
  
  //^^^^^^^^^^^^^^^^^^^^^^^^^DO NOT ERASE^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  
  //^^^^^^^^^^^^^^^^^^^^^^BRAKE SAFETY CUTOFF^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    while (digitalRead(brakeSwitch) == LOW)
  {
    analogWrite(throttleCmd, 0);
    digitalWrite(brakeLight, HIGH);
    delay(1000);
    Serial.println("Brake Shut Down");
  }
  //^^^^^^^^^^^^^^^^^^^^^^^^^DO NOT ERASE^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  
  //^^^^^^^^^^^^^^^^^^^^^^BRAKE SAFETY CUTOFF^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  
  
  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("");
 
  
  //limitRamp is a modifier for the throttle output to the external controller, higher amps = continuously lowering throttle signal to external controller
  if (actualAmp > ampLimit) //Main current limiter function
  {
    limitRamp = limitRamp + 2;  //[actual throttle output signal] = [your intended throttle signal integer] - [limitRamp integer]
    limitRamp = constrain(limitRamp, 0, 254);
    Serial.println("AMP OVERLIMIT");
  }
  else
  {
    limitRamp = limitRamp - 2;
    limitRamp = constrain(limitRamp, 0, 254);
  }

  //REDUNDANT CODE
  //^^^^^^^^^^^^^^^^^^^^^^^^^DO NOT ERASE^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  
  //^^^^^^^^^^^^^^^^^^^^^^BRAKE SAFETY CUTOFF^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    while (digitalRead(brakeSwitch) == LOW)
  {
    analogWrite(throttleCmd, 0);
    digitalWrite(brakeLight, HIGH);
    delay(1000);
    Serial.println("2 Brake Shut Down 2");
  }
  //^^^^^^^^^^^^^^^^^^^^^^^^^DO NOT ERASE^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  
  //^^^^^^^^^^^^^^^^^^^^^^BRAKE SAFETY CUTOFF^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  if (ampSurge < ampSurgeMax && pulse > ampSurgeThreshold) //AMP SURGE MODE, Full Throttle, gives "ampSurgeMax cycles" of full pulse commands bypassing limitRamp, "TURBO BUTTON"
  {
    analogWrite(throttleCmd, pulse);
    ampSurge = ampSurge + 1;
    limitRamp = 0; //Prevent adding to limitRamp while in ampSurge mode, so when exiting ampSurge, limitRamp starts compensating
    Serial.println("SURGE MODE");
  }
  else
  {
    pulse = pulse - limitRamp; //The main outsignal to external controller, 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
}


//The End
 
I have just bought a Arduino and just about to start having a play with it, so this have come along at the right time. Have you done anything with the PID library for the Arduino ? looks very easy to setup and tune control loops with minimum code.
I have no experience with arduino so its all new to me, I played around with the picaxe but soon found some limitations, the speed was a major disadvantage.
What I want to do is not include cruise control but its main function will be on the fly current limiting.
 
gwhy! said:
I have just bought a Arduino and just about to start having a play with it, so this have come along at the right time. Have you done anything with the PID library for the Arduino ? looks very easy to setup and tune control loops with minimum code.
I have no experience with arduino so its all new to me, I played around with the picaxe but soon found some limitations, the speed was a major disadvantage.
What I want to do is not include cruise control but its main function will be on the fly current limiting.

I haven't used PID, but it does look applicable. Here is a great Arduino tutorial series, should help you since you're beginning: https://www.youtube.com/watch?v=fCxzA9_kg6s

Visit Arduino.cc to get language, syntax, and product help here: http://arduino.cc/en/Reference/HomePage

Here is the throttle input, amp input, then it will analogWrite 0-5v PWM to an external controller. "limitRamp" will ramp up or down the modified throttle signal to the external controller. So you may be holding full throttle at 4.8v going into the arduino from your hand throttle, but the arduino is sending a 3.1v signal to the external controller.
Code:
void loop()
{
  int throttleIn = analogRead(throttleSignal); //Main read throttle, declare pulse
  int pulse = constrain(throttleIn, 0, 1023);
  pulse = map(pulse, 0, 1022, 0, 254);
 
  int ampRead = analogRead(hallIn); //Read raw hall sensor output signal hallIn
  ampRead = constrain(ampRead, sensorCal, 1023); //constrain to sensor output range, sensorCal is zero amps
  int actualAmp = ampRead - sensorCal; //Declare new int for conversion, actualAmp is Delta signal change above sensorCal
  actualAmp = (actualAmp * 4.9) / sensorSpec; //Convert actualAmp to mV integer, divide by 40 "ACS756 = 40mV/1A" to get actual Amp integer

 
  //limitRamp is a modifier for the throttle output to the external controller, higher amps = continuously lowering throttle signal to external controller
  if (actualAmp > ampLimit) //Main current limiter function, int ampLimit manually set
  {
    limitRamp = limitRamp + 2;  //[actual throttle output signal] = [your intended throttle signal integer] - [limitRamp integer]
    limitRamp = constrain(limitRamp, 0, 254);
    Serial.println("AMP OVERLIMIT");
  }
  else
  {
    limitRamp = limitRamp - 2;
    limitRamp = constrain(limitRamp, 0, 254);
  }

    pulse = pulse - limitRamp; //The main outsignal to external controller, if not in ampSurge mode
    pulse = constrain(pulse, 0, 254);
    analogWrite(throttleCmd, pulse); //Main Throttle Command Line

}


//The End
 
Thanks SM,
I will have a play with the setup , watch some tutorials and see how I go.. Cheers.
I will let you know how I get on with the PID library.
 
Thank you so much for that, I am also planning a similar setup. I will stream the data like amps/volts over Bluetooth to my Android phone with a custom app.
 
I have managed to get my voltage divider working with my Arduino Nano, I am using a 22k and a 680k resistor. I needed a separate 5v regulated supply to use as a reference voltage. I have ordered some LM317's for this purpose.

I am going to have to etch a custom PCB to mount the Arduino Nano onto, I am nervous about this. Never done it before! I have some RJ45 jacks so that I can run some cat5e cable to the handlebars, this will transmit/receive push button and i2c lcd display data. The Bluetooth will interface with the SoftwareSerial interface of the Arduino, basically like a bridge.

I will open source plans to build this contraption when done too, but its a fair old way off. I am just riding bike in old school/low tech mode for time being! s

I hope to be able to provide some of the basic features of the cycle analyst at a much lower price point.

Oh and if you have any arduino circuit diagrams, please share them! I will try and knock one of my own up later.
 
steelmesh said:
This is the working prototype code, for off-road use only ;)

You are a hero! We do something similar. Also I2C display, current mode throttle etc... http://endless-sphere.com/forums/viewtopic.php?f=2&t=47124
Thx for sharing!

//initialized buzzer, only happens once
This should be run in "void setup" instead?
 
crossbreak said:
steelmesh said:
This is the working prototype code, for off-road use only ;)

You are a hero! We do something similar. Also I2C display, current mode throttle etc... http://endless-sphere.com/forums/viewtopic.php?f=2&t=47124
Thx for sharing!

//initialized buzzer, only happens once
This should be run in "void setup" instead?

I think you're right about the void setup buzzer
 
Okay before I'm flamed for being a total newbie, Yes I am. I am trying to use an Arduino board to convert a twist-throttle Hall effect output signal from 1-4v to 0-5v. I stole a lot of code from this forum in my attempt to make it work, but I am not making any headway. I'm new to Arduino and fairly recent to electric vehicles (made a hub-electric bike from a kit a few years back then played with the configuration, very simple task). This is going into a scooter. So I have the following Arduino code worked out but it appears to be hosed up somehow. Hoping someone here will throw me a lifeline.

int throttleCmd = 3; //0-5v PWM output throttle signal pin 3
int hallIn = 2; //1-4v signal from Hall Sensor // pin 2
float hallOut=1.66; //the slope needed to convert 1-4v to 0-5v
void setup()
{
Serial.begin(9600);
pinMode(throttleCmd, OUTPUT);
pinMode(hallIn, INPUT);
}
void loop()
{
int throttleIn = analogRead(hallIn); //Main read throttle, declare pulse
throttleIn = (hallOut * throttleIn) - hallOut;
int pulse = constrain(throttleIn, 0, 1023);
pulse = map(pulse, 0, 1022, 0, 254);
pulse = constrain(pulse, 0, 254);
analogWrite(throttleCmd, pulse); //Main Throttle Command Line
delay(2); //calm down
}

Note: I use 5v regulated from the controller into the 5v pin to save having to provide a separate voltage. On an Arduino forum I read from an Arduino spokesperson that should work as long as the voltage is properly regulated, which I believe it is. The project compiles okay so it's nothing obvious like syntax error.

Also note that since I ripped off much of the code (or "repurposed" it) I don't necessarily know exactly what is going on. For example, I used float instead of int for the Hall input earlier but it didn't seem to matter so I went back to int. That may be a mistake but not THE mistake.

Any suggestions?

Thanks!!
 
as long as you just connect a throttle and your arduino to the 5V rail, current consumption should not be a problem. You may want to turn of ADCs you dont need for reliability. Which arduino board do you use?

how about serial print some or all of your variables to see what goes on? Maybe you just chose the wrong pin or something like that

Code:
Serial.print("Measured Throttle Input in Volts: ");
Serial.println(throttleCmd );  //sends the throttle signal back to the PC for debugging
 
chuckgass said:
Okay before I'm flamed for being a total newbie, Yes I am. I am trying to use an Arduino board to convert a twist-throttle Hall effect output signal from 1-4v to 0-5v. I stole a lot of code from this forum in my attempt to make it work, but I am not making any headway. I'm new to Arduino and fairly recent to electric vehicles (made a hub-electric bike from a kit a few years back then played with the configuration, very simple task). This is going into a scooter. So I have the following Arduino code worked out but it appears to be hosed up somehow. Hoping someone here will throw me a lifeline.

int throttleCmd = 3; //0-5v PWM output throttle signal pin 3
int hallIn = 2; //1-4v signal from Hall Sensor // pin 2
float hallOut=1.66; //the slope needed to convert 1-4v to 0-5v
void setup()
{
Serial.begin(9600);
pinMode(throttleCmd, OUTPUT);
pinMode(hallIn, INPUT);
}
void loop()
{
int throttleIn = analogRead(hallIn); //Main read throttle, declare pulse
throttleIn = (hallOut * throttleIn) - hallOut;
int pulse = constrain(throttleIn, 0, 1023);
pulse = map(pulse, 0, 1022, 0, 254);
pulse = constrain(pulse, 0, 254);
analogWrite(throttleCmd, pulse); //Main Throttle Command Line
delay(2); //calm down
}

Note: I use 5v regulated from the controller into the 5v pin to save having to provide a separate voltage. On an Arduino forum I read from an Arduino spokesperson that should work as long as the voltage is properly regulated, which I believe it is. The project compiles okay so it's nothing obvious like syntax error.

Also note that since I ripped off much of the code (or "repurposed" it) I don't necessarily know exactly what is going on. For example, I used float instead of int for the Hall input earlier but it didn't seem to matter so I went back to int. That may be a mistake but not THE mistake.

Any suggestions?

Thanks!!

most hall throttles sit at around a DAC value of around 40 - 50 and max out at DAC value of around 840 - 860 ( this is with a 5v rail )

so all you need to do is use...
pulse = map(thottlecmd,40,840,0,1023); // where 40 is the initial offset and the 840 is th emax output from the hall throttle
-------------
int throttleCmd = 3; //0-5v PWM output throttle signal pin 3
int hallIn = 2; //1-4v signal from Hall Sensor // pin 2
// float hallOut=1.66; //the slope needed to convert 1-4v to 0-5v // not needed
void setup()
{
Serial.begin(9600);
pinMode(throttleCmd, OUTPUT);
pinMode(hallIn, INPUT);
}
void loop()
{
int throttleIn = analogRead(hallIn); //Main read throttle, declare pulse
// throttleIn = (hallOut * throttleIn) - hallOut;
// pulse = constrain(throttleIn, 0, 1023);
pulse = map(throttleIn,40,840,0,255); // this maps the hall range to 0 and 255..
// pulse = constrain(pulse, 0, 255);
analogWrite(throttleCmd, pulse); //Main Throttle Command Line
delay(2); //calm down
}

and You Could also do what crossbreak says to get the min and max actual dac values

Serial.print("Measured Throttle Input dac values: ");
Serial.println(throttleIn); //this will give the DAC values from the hall throttle to allow you to put in the correct values in your program


the output also needs to be digital ( D3 ) and the input needs to be a analog (A2)
 
First thanks to all who replied. Very good stuff there.

Next thanks to gwhy! for pointing out that the Hall input needed to come in on the Analog pins. Essentially that was my root problem. Duh! The program's still not exactly where I need it, but it's way closer and I know what I need to do next.

Thanks again!!!

Chuck
 
gwhy! said:
Thanks SM,
I will have a play with the setup , watch some tutorials and see how I go.. Cheers.
I will let you know how I get on with the PID library.

While I am here just thought I would give a update on my little project... The arduino PID library works very well :) and even better if you use different sets of pid settings depended on distance away from the setpoint of the pid. The crude way of adjusting the throttle output was not very good and caused all sorts of problems.

steelmesh said:
I haven't used PID, but it does look applicable. Here is a great Arduino tutorial series, should help you since you're beginning: https://www.youtube.com/watch?v=fCxzA9_kg6s

Visit Arduino.cc to get language, syntax, and product help here: http://arduino.cc/en/Reference/HomePage

Here is the throttle input, amp input, then it will analogWrite 0-5v PWM to an external controller. "limitRamp" will ramp up or down the modified throttle signal to the external controller. So you may be holding full throttle at 4.8v going into the arduino from your hand throttle, but the arduino is sending a 3.1v signal to the external controller.
Code:
void loop()
{
  int throttleIn = analogRead(throttleSignal); //Main read throttle, declare pulse
  int pulse = constrain(throttleIn, 0, 1023);
  pulse = map(pulse, 0, 1022, 0, 254);
 
  int ampRead = analogRead(hallIn); //Read raw hall sensor output signal hallIn
  ampRead = constrain(ampRead, sensorCal, 1023); //constrain to sensor output range, sensorCal is zero amps
  int actualAmp = ampRead - sensorCal; //Declare new int for conversion, actualAmp is Delta signal change above sensorCal
  actualAmp = (actualAmp * 4.9) / sensorSpec; //Convert actualAmp to mV integer, divide by 40 "ACS756 = 40mV/1A" to get actual Amp integer

 
  //limitRamp is a modifier for the throttle output to the external controller, higher amps = continuously lowering throttle signal to external controller
  if (actualAmp > ampLimit) //Main current limiter function, int ampLimit manually set
  {
    limitRamp = limitRamp + 2;  //[actual throttle output signal] = [your intended throttle signal integer] - [limitRamp integer]
    limitRamp = constrain(limitRamp, 0, 254);
    Serial.println("AMP OVERLIMIT");
  }
  else
  {
    limitRamp = limitRamp - 2;
    limitRamp = constrain(limitRamp, 0, 254);
  }

    pulse = pulse - limitRamp; //The main outsignal to external controller, if not in ampSurge mode
    pulse = constrain(pulse, 0, 254);
    analogWrite(throttleCmd, pulse); //Main Throttle Command Line

}


//The End

Also the PWM output needs to smoothed with a couple of RC filters as it was just unusable with a infineon controller but some other types of controllers the filters were not needed. I used a 2nd order filter that allows a faster response and also keeps the ripple down to a minimum.
 
I just finished modifying my buddy's Kidtrax Firetruck ("Power Wheels"). This also uses an Arduino so that I could more simply calibrate the servo steering system and custom modified variable throttle (using GM TPS sensor).
Mockup of electric steering: http://youtu.be/4vg9yUhAbuQ

Here is V4 of the code:
Code:
//Power Wheels Firetruck 
//Copyright Steelmesh

int maxSpeed = 255;
int throttleStepper = 0;
boolean throttleStartupSafety = LOW;
boolean govInputAa;
boolean govInputBb;
boolean reverseSwitch;
boolean reverseToggle = false;

//Analog Pin Assignments
int throttleInput = 0;
int steeringInput = 1;

//Digital Pin Assignments
int govInputA = 2;
int govInputB = 4;
int throttleOutput = 5; //PWM
int steeringCommand = 3; //1 ms to 2 ms PWM
int reverseRelay = 6;
int reversePin = 7;

void setup()
{
  Serial.begin(9600);
  
  pinMode(INPUT, govInputA);
  pinMode(INPUT, govInputB);
  pinMode(INPUT, reverseSwitch);
  
  pinMode(OUTPUT, throttleOutput);
  pinMode(OUTPUT, steeringCommand);
  pinMode(OUTPUT, reverseRelay);
  
  throttleStartupSafety = analogRead(throttleInput);
  while(throttleInput == HIGH)
  {
    Serial.println("Throttle Safety: do not hit throttle on startup");
    delay(200);
    throttleStartupSafety = analogRead(throttleInput);
  }
  
  Serial.println("Setup Complete");

}

void loop()
{
  
  //*************BEGIN THROTTLE CONTROL*******************
  
  int throttleMap = analogRead(throttleInput);
  throttleMap = map(throttleMap, 0, 232, 40, 255); //Calibrate
  
  govInputAa = digitalRead(govInputA);
  govInputBb = digitalRead(govInputB);
  
  if(govInputAa == LOW && govInputBb == LOW)
  {
    maxSpeed = 80; //lowest speed
  }
  if(govInputAa == HIGH && govInputBb == LOW)
  {
    maxSpeed = 110;
  }
  if(govInputAa == LOW && govInputBb == HIGH)
  {
    maxSpeed = 160;
  }
  if(govInputAa ==HIGH && govInputBb == HIGH)
  {
    maxSpeed = 255; //highest speed
  }
  
  if(throttleMap >= maxSpeed)
  {
    throttleMap = maxSpeed;
  }
  
  if(throttleMap > throttleStepper)
  {
    throttleStepper += 5; //throttle stepper amount
  }
  else if(throttleMap <= throttleStepper)
  {
    throttleStepper = throttleMap; //if lets off throttle, fast response
  }
  
  throttleStepper = constrain(throttleStepper, 0, 255);
  analogWrite(throttleOutput, throttleStepper);

  //*************END THROTTLE CONTROL*******************
  
  
  //++++++++++++++BEGIN STEERING CONTROL+++++++++++++
  
  int steeringMap = analogRead(steeringInput);
  steeringMap = map(steeringMap, 0, 1023, 255, 110); //CALIBRATE
  
  analogWrite(steeringCommand, steeringMap);
  
  //++++++++++++++END STEERING CONTROL+++++++++++++
  
  
  //^^^^^^^^^^^^^^^BEGIN REVERSE SWITCH^^^^^^^^^^^^^^^^
//Need to prevent short circuit adding throttle cut and delay's for the dual 30amp Auto relays used
  reverseSwitch = digitalRead(reversePin);
  
  if(reverseSwitch == LOW && reverseToggle == false)
  {
    digitalWrite(reverseRelay, LOW);
  }
  if(reverseSwitch == HIGH && reverseToggle == false)
  {
    analogWrite(throttleOutput, 0);
    throttleStepper = 0;
    delay(800);
    digitalWrite(reverseRelay, HIGH);
    reverseToggle = true;
    delay(500);
  }
  if(reverseSwitch == LOW && reverseToggle == true)
  {
    analogWrite(throttleOutput, 0);
    throttleStepper = 0;
    delay(800);
    digitalWrite(reverseRelay, LOW);
    reverseToggle = false;
    delay(500);
  }
//  Serial.print("Rev switch = ");
//  Serial.print(reverseSwitch);
//  Serial.print(" rev toggle = ");
//  Serial.println(reverseToggle);
  //^^^^^^^^^^^^^^^END REVERSE SWITCH^^^^^^^^^^^^^^^^
  
  
  //CALIBRATION SERIAL OUTPUT
  
  int throttleRaw = analogRead(throttleInput);
  int steeringRaw = analogRead(steeringInput);
  
  Serial.print("throttleRaw = ");
  Serial.print(throttleRaw);
  Serial.print(" steeringRaw = ");
  Serial.print(steeringRaw);
  Serial.print(" throttle out = ");
  Serial.print(throttleStepper);
  Serial.print(" steer out = ");
  Serial.print(steeringMap);
  Serial.print(" rev = ");
  Serial.print(reverseSwitch);
  Serial.print(" Speed Selector Pos A = ");
  Serial.print(govInputAa);
  Serial.print(" B = ");
  Serial.println(govInputBb);
  
  
}
 
Hi, I am doing some of the same thing but I really wounder about the brake high and brake low, Is this to signal the brake or to engage the brake in the wheel? Love tyhe code bte, Trying to do mine wireless doh ;)
 
Back
Top