Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
Gunter HayesMarcus NeacsuJason Matthews
Published

Control of Electric Vehicle

Vehicle control scheme is redeisgned to include battery information and variable speed control

IntermediateShowcase (no instructions)5 hours237
Control of Electric Vehicle

Things used in this project

Hardware components

Jumper wires (generic)
Jumper wires (generic)
×10
Breadboard (generic)
Breadboard (generic)
×1
Argon
Particle Argon
×1
Pin Terminal, Crimp
Pin Terminal, Crimp
×8
power wheels car
×1
Dual H-Bridge motor drivers L298
SparkFun Dual H-Bridge motor drivers L298
×1
Hall Effect Sensor, Throttle Position
Hall Effect Sensor, Throttle Position
×1
Volt Meter, Mini 3-Wire
Volt Meter, Mini 3-Wire
×1
LED Current Meter 10A (Green)
DFRobot LED Current Meter 10A (Green)
×1
60W PCIe 12V 5A Power Supply
Digilent 60W PCIe 12V 5A Power Supply
×1

Software apps and online services

ThingSpeak API
ThingSpeak API
Particle Build Web IDE
Particle Build Web IDE

Hand tools and fabrication machines

Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires
Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires
Crimp Tool, Heavy-Duty
Crimp Tool, Heavy-Duty
Multitool, Screwdriver
Multitool, Screwdriver
Tape, Electrical
Tape, Electrical

Story

Read more

Schematics

Electrical Schematic

Wiring Schematic for the vehicle

Real Life wiring

Electrical Wiring Fritzing

Fritzing Wiring Diagram

Code

Code with Voltage/Current sensor and PWM peddle

Arduino
Program reads throttle, voltage, and current and varies motor speed accordingly.
// This #include statement was automatically added by the Particle IDE.
#include <ThingSpeak.h>

// This #include statement was automatically added by the Particle IDE.
#include <Adafruit_DHT.h>


//Things speak client setup
TCPClient client;
// Define the pins for the analog inputs and servo output
const int VOLTAGE_PIN = A0;
const int CURRENT_PIN = A1;
const int THROTTLE_PIN = A2;

// Define the ratios for the voltage divider and current sensor calibration
const float VOLTAGE_RATIO = 0.046;
const float CURRENT_CALIBRATION = 0.066;

// Define the variables to hold the raw analog readings
int rawVoltage;
int rawCurrent;
int rawThrottle;

int Voltage;
int Current;
int Throttle;

// Motor A connections
const int enA = D7;
const int in1 = D6;
const int in2 = D5;
// Motor B connections
const int in3 = D4;
const int in4 = D3;
const int enB = D2;

// Define the time interval for reading the analog inputs (in microseconds)
const unsigned long READ_INTERVAL = 20000;

// Define the time interval for outputting the filtered values (in milliseconds)
const unsigned long OUTPUT_INTERVAL = 10000;

// Define the filter coefficients for a first-order low-pass filter with a cutoff frequency of 5 Hz
const float FILTER_COEFFICIENT = 0.0183;

// Define the timer for outputting the filtered values
unsigned long outputTimer = 0;

// Define the servo object and the initial throttle value
int throttleValue = 0;

int PhotoValue;

// ThingSpeak client setting setup
unsigned long myChannelNumber = 2060933;
const char * myWriteAPIKey = "6EBZTLSYCCX2JMMD";

void setup() {
  // Initialize the serial communication
 Serial.begin(9600);
 //begin the ThingSpeak
ThingSpeak.begin(client);
Particle.variable("Voltage", Voltage);
Particle.variable("Current", Current);
Particle.variable("Throttle", rawThrottle);

//set all sensor pins to inputs
pinMode(VOLTAGE_PIN, INPUT);
pinMode(CURRENT_PIN, INPUT);
pinMode(THROTTLE_PIN, INPUT);

// Set all the motor control pins to outputs
pinMode(enA, OUTPUT);
pinMode(enB, OUTPUT);
pinMode(in1, OUTPUT);
pinMode(in2, OUTPUT);
pinMode(in3, OUTPUT);
pinMode(in4, OUTPUT);

// Turn off motors - Initial state
digitalWrite(in1, LOW);
digitalWrite(in2, LOW);
digitalWrite(in3, LOW);
digitalWrite(in4, LOW);
}

void loop() {
  // Read the analog inputs
  rawVoltage = analogRead(VOLTAGE_PIN);
  rawCurrent = analogRead(CURRENT_PIN);
  rawThrottle = analogRead(THROTTLE_PIN);
  
  //set motor direction to be forward
    digitalWrite(in1, LOW);
	digitalWrite(in2, HIGH);
	digitalWrite(in3, LOW);
	digitalWrite(in4, HIGH);

  // Convert the raw values to voltages and current
  float voltage = (rawVoltage * 16.5) / 4095.0;
  float current = (-(rawCurrent * 30.0) / 4095.0)+15.086;
  int motorSpeed = map(rawThrottle, 1048, 3100, 0, 255);
  
  ///use the PWM on the motor controller
    analogWrite(enA, motorSpeed);
    analogWrite(enB, motorSpeed);

  // Filter the values
  float filteredVoltage = (FILTER_COEFFICIENT * voltage + (1 - FILTER_COEFFICIENT) * filteredVoltage);
  float  filteredCurrent = (FILTER_COEFFICIENT * current + (1 - FILTER_COEFFICIENT) * filteredCurrent);

    //multiply by 1000 for more statiscal variance since we cant send floats
    int Voltage = voltage * 1000;
    int Current = current * 1000;
  // Check if it's time to output the filtered values
  if (millis() - outputTimer >= OUTPUT_INTERVAL) {
    // Output the filtered values
    Serial.print("Filtered voltage: ");
    Serial.print(Voltage);
    Serial.print(" V, Filtered current: ");
    Serial.print(Current);
    Serial.println(" A");

    
    //Publish all of the sensor readings via Particle Console
     Particle.publish("rawVoltage",String(rawVoltage), ALL_DEVICES);
     Particle.publish("rawCurrent",String(rawCurrent), ALL_DEVICES);;
     Particle.publish("rawThrottle",String(rawThrottle), ALL_DEVICES);
     Particle.publish("Voltage",String (Voltage), ALL_DEVICES);
     Particle.publish("Current",String (Current), ALL_DEVICES);
    
    //Publish all of the sensor readings via ThingSpeak Channela
    ThingSpeak.setField(1,Voltage);
    ThingSpeak.setField(2,Current);
    ThingSpeak.setField(3,rawThrottle);
    ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);

    // Reset the output timer
    outputTimer = millis();
  }
}
  

Slew rate traction control

Arduino
Same thing as before but now with traction control!
// This #include statement was automatically added by the Particle IDE.
#include <ThingSpeak.h>

// This #include statement was automatically added by the Particle IDE.
#include <Adafruit_DHT.h>


//Things speak client setup
TCPClient client;
// Define the pins for the analog inputs and servo output
const int VOLTAGE_PIN = A0;
const int CURRENT_PIN = A1;
const int THROTTLE_PIN = A2;

// Define the ratios for the voltage divider and current sensor calibration
const float VOLTAGE_RATIO = 0.046;
const float CURRENT_CALIBRATION = 0.066;

// Define the variables to hold the raw analog readings
int rawVoltage;
int rawCurrent;
int rawThrottle;

int Voltage;
int Current;
int Throttle;

// Motor A connections
const int enA = D7;
const int in1 = D6;
const int in2 = D5;
// Motor B connections
const int in3 = D4;
const int in4 = D3;
const int enB = D2;

// Define the time interval for reading the analog inputs (in microseconds)
const unsigned long READ_INTERVAL = 20000;

// Define the time interval for outputting the filtered values (in milliseconds)
const unsigned long OUTPUT_INTERVAL = 10000;

// Define the filter coefficients for a first-order low-pass filter with a cutoff frequency of 5 Hz
const float FILTER_COEFFICIENT = 0.0183;

// Define the timer for outputting the filtered values
unsigned long outputTimer = 0;

// Define the servo object and the initial throttle value
int throttleValue = 0;
int throttlerate = 50;
int prevThrottle = 0;
// ThingSpeak client setting setup
unsigned long myChannelNumber = 2060933;
const char * myWriteAPIKey = "6EBZTLSYCCX2JMMD";


void myHandler(const char *event, const char *data)
{
  throttlerate = String(data).toInt();
  //Log.info("%d: event=%s data=%s", i, event, (data ? data : "NULL"));
}


void setup() {
  // Initialize the serial communication
 Serial.begin(9600);
 //begin the ThingSpeak
ThingSpeak.begin(client);
Particle.variable("Voltage", Voltage);
Particle.variable("Current", Current);
Particle.variable("Throttle", rawThrottle);

 Particle.subscribe("Throttlerate", myHandler);

//set all sensor pins to inputs
pinMode(VOLTAGE_PIN, INPUT);
pinMode(CURRENT_PIN, INPUT);
pinMode(THROTTLE_PIN, INPUT);

// Set all the motor control pins to outputs
pinMode(enA, OUTPUT);
pinMode(enB, OUTPUT);
pinMode(in1, OUTPUT);
pinMode(in2, OUTPUT);
pinMode(in3, OUTPUT);
pinMode(in4, OUTPUT);

// Turn off motors - Initial state
digitalWrite(in1, LOW);
digitalWrite(in2, LOW);
digitalWrite(in3, LOW);
digitalWrite(in4, LOW);
}

void loop() {
  // Read the analog inputs
  rawVoltage = analogRead(VOLTAGE_PIN);
  rawCurrent = analogRead(CURRENT_PIN);
  rawThrottle = analogRead(THROTTLE_PIN);
  
  //set motor direction to be forward
    digitalWrite(in1, LOW);
	digitalWrite(in2, HIGH);
	digitalWrite(in3, LOW);
	digitalWrite(in4, HIGH);

  int throttle = min(rawThrottle, prevThrottle + throttlerate);
  delay(10);
  prevThrottle = throttle;
  // Convert the raw values to voltages and current
  float voltage = (rawVoltage * 16.5) / 4095.0;
  float current = (-(rawCurrent * 30.0) / 4095.0)+15.086;
  int motorSpeed = map(throttle, 1100, 3100, 0, 255);
  
  motorSpeed = constrain(motorSpeed, 0, 255);
  ///use the PWM on the motor controller
    analogWrite(enA, motorSpeed);
    analogWrite(enB, motorSpeed);

  // Filter the values
  float filteredVoltage = (FILTER_COEFFICIENT * voltage + (1 - FILTER_COEFFICIENT) * filteredVoltage);
  float  filteredCurrent = (FILTER_COEFFICIENT * current + (1 - FILTER_COEFFICIENT) * filteredCurrent);

    //multiply by 1000 for more statiscal variance since we cant send floats
    int Voltage = voltage * 1000;
    int Current = current * 1000;
  // Check if it's time to output the filtered values
  if (millis() - outputTimer >= OUTPUT_INTERVAL) {
    // Output the filtered values
    Serial.print("Filtered voltage: ");
    Serial.print(Voltage);
    Serial.print(" V, Filtered current: ");
    Serial.print(Current);
    Serial.println(" A");

    
    //Publish all of the sensor readings via Particle Console
     Particle.publish("rawVoltage",String(rawVoltage), ALL_DEVICES);
     Particle.publish("rawCurrent",String(rawCurrent), ALL_DEVICES);;
     Particle.publish("rawThrottle",String(rawThrottle), ALL_DEVICES);
     Particle.publish("Voltage",String (Voltage), ALL_DEVICES);
     Particle.publish("Current",String (Current), ALL_DEVICES);
    
    //Publish all of the sensor readings via ThingSpeak Channela
    ThingSpeak.setField(1,Voltage);
    ThingSpeak.setField(2,Current);
    ThingSpeak.setField(3,rawThrottle);
    ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);

    // Reset the output timer
    outputTimer = millis();
  }
}
  

Credits

Gunter Hayes

Gunter Hayes

1 project • 3 followers
Marcus Neacsu

Marcus Neacsu

3 projects • 2 followers
Jason Matthews

Jason Matthews

2 projects • 5 followers
Thanks to John Macalpine, Mohammed Alkhliwi, and Khalid Bedaiwi .

Comments