The vehicle control system has been revamped to incorporate battery status updates and adjustable speed control.
Things used in this project
Hardware components
Software apps and online services
Hand tools and fabrication machines
Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires
Crimp Tool, Heavy-Duty
Multitool, Screwdriver
Tape, Electrical
Story
According to the courses, "hardware, sensors, programming, performance, motor selection, regenerative braking, etc. A Budget of $300 per student is required. Students will be required to purchase used electric toytype ride on vehicles and electronic components. Students will implement their own control systems utilizing an Argon type device, various sensors and hardware."Currently using a voltmeter and current meter to gather battery load data with vehicle usage. Swapped throttle pedal out for variable sensor for variable motor speeds. Using a L298N motor driver for precise Dual motor control.
Attached Below is a picture of our live data acquisition that we are using Thingspeak for. https://thingspeak.com/channels/2060933
Live Data the spike at 12:35 is from pulling out the battery
PWM Video working below
Slew Rate Video
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();
}
}
The article was first published in hackster, April 25, 2023
cr: https://www.hackster.io/control-ev-team10/control-of-electric-vehicle-9f6c5f
author: Control-EV-Team10: Gunter Hayes, Marcus Neacsu, Jason Matthews