Maker.io main logo

Ambassador Moment: Building a Hardware Module for Electric Vehicle

2021-05-07 | By Robby Huang

License: See Original Project

This project was designed by one of Digi-Key’s own university ambassador students. Check out how it works in the video below!

 

Electric vehicles (EVs) are becoming increasingly common worldwide as the demand for safer, more reliable (and eco-friendly) cars grows. With the latest technology in EVs comes the need for intricate electrical designs capable of carrying out various tasks simultaneously.

This project will focus on the automation module for an electric vehicle, starting with an Arduino prototype and ending with a PCB that will allow the computer in an autonomous vehicle to steer or brake the car.

System Description

The system takes signals from the Jetson GPU for steering, throttling, and braking to the respective controlling system. All signals will first be inputted into the microcontroller. The steering signal tells us the steering angle. We will convert that to steps of the stepper motor through a quadruple half-h bridge driver in which the stepper motor interfaces with the steering column by gears. A feedback system is installed in place to make up the difference between the input steps and the actual steps. The throttling signal will be forwarded to a motor controller. The braking signal will control the other stepper motor, which interfaces with one of the master cylinders of the front brake.

Terminology

Stepper Motor: A brushless DC electric motor that divides a full rotation into a number of equal steps.

Rotary Encoder: Also called a shaft encoder, an electro-mechanical device that converts the angular position or motion of a shaft or axle to analog or digital output signals.

PID controller: A proportional–integral–derivative controller (PID controller or three-term controller) is a control loop mechanism employing feedback widely used in industrial control systems and a variety of other applications requiring continuously modulated control.

Closed-Loop Control System: A closed-loop control system is a set of mechanical or electronic devices that automatically regulates a process variable to the desired state or setpoint without human interaction.

Research and Requirements

This system’s main aspects are using a microcontroller, stepper motor, quadruple half-h bridge driver, and rotary encoder. Essentially, the heart of the system lies within the microcontroller, an integrated circuit chip dedicated to running a specific process. This system will use a microcontroller to communicate with the stepper motor and encoder to ensure the system works properly.

A stepper motor is a specific type of DC motor that moves in particular increments called "steps." This is achieved by having four separate groups of coils energized one at a time, moving the entire motor by one small step (shown below). More information on stepper motors can be found here.

steppermotor_1

The quadruple half-h bridge driver is an integrated circuit that consists of four separate switches that control the flow of current and switch the polarity of an input voltage (shown below). This allows for the motor’s direction to change from clockwise to counter-clockwise almost instantaneously when connected to a stepper motor. More information on h-bridge drivers can be found here.

h-bridge_2

A rotary encoder is a device that can take an angular position and convert it into an analog or digital signal to provide feedback. A microcontroller can then use this data to provide correction to the stepper motor.

Design Requirements

This system aims to receive signals from the motor controller to perform braking, steering, and throttling, creating a fully automated driving system. The main requirement is that the braking and steering mechanisms have a manual steering override, which the driver can engage/disengage completely. With this, the system’s speed must also be incredibly fast so that the time delay between the controlling signals is near-negligible; otherwise, the system will not work effectively. The background noise signals created by the motor must also be sent through a low-pass filter to prevent the system from operating when it shouldn't be. The overall design must also be condensed enough to be mounted on the bulkhead with the other equipment.

Key Parameters

The main parameters of this design include the steering angle, torque, speed, and resolution.

Steering Angle: The ideal steering angle values are ±21.5˚. This was determined by the safety parameters of the car to make sure it does not overturn while driving. The chosen range is comfortably within the anticipated steering limits and should not pose any safety concerns.

Torque: The ideal final torque value is 1 Nm. This parameter was calculated and provided by the Front Assembly Team. The primary constraint on the torque is the speed at which the stepper motor is running. This value is entirely dependent on the speed, which is discussed below.

Speed: The final chosen RPM for the stepper motor is around 5 RPM (30˚/sec). After the gear ratio, the final RPM should be approximately 15 RPM. This value was chosen based on the documentation given by the manufacturer (see below). The attached chart illustrates that lower RPMs will show higher torques, and 15 RPM provides a near-optimal torque while working with the gear ratio.

chart_3

Resolution: The resolution of the encoder was determined to be around 1-2˚. This value was chosen because it accounts for errors in the stepper motor at the speed it is being run. While the resolution can be made more precise, it would lead to round-off errors while processing and make the correction factor invalid.

System Diagram

SystemDiagram_4

Potential Designs

Two main potential designs were looked at when first designing the system. The first used an Arduino to control the stepper motors, while the other used a Raspberry Pi:

Arduino

Microcontroller

Ideal for repetitive tasks

16 MHz Arduino UNO

Easier to Program

Raspberry Pi

Single-board Computer

Ideal for multi-tasking

900 MHz Raspberry Pi 2

Much Harder to Program

The first design is to utilize the Arduino as a microcontroller that will provide a signal to tell the stepper motor to move a certain number of steps to throttle and brake the car. It will be run using a loop that will continuously provide signals when the system is engaged.

The second design will use the Raspberry Pi to communicate with the sensors in the car continuously. This will provide commands to move the car a certain way and essentially need a control hub that can be accessed remotely.

Both design options are relatively comparable in size and weight, so this is not a primary concern when determining the final design. However, the Raspberry Pi is slightly more expensive than the Arduino, which has been considered. The real difference is the feasibility and manufacturability between the two designs. The Arduino is much more realistic to design and implement while still providing an engaging experience. On the other hand, the Raspberry Pi requires much more time and attention and is much more complex than the Arduino. The Raspberry Pi will likely be better in later years when cars are entirely automated.

Selected Design and Justification

Ultimately, an Arduino was chosen for this design as it is open-source and, therefore, easier to implement on a PCB and is more cost-effective (at the time this was written, $20 for an Arduino vs. $35 for a Raspberry Pi). Although the Raspberry Pi is more powerful, its complexity is a significant drawback for implementing the system. Designing a custom PCB also makes it easier to communicate with the other systems on the car, such as the BMS and Motor Controller.

There are also two potential methods for implementing a feedback system: using a PID controller to provide a correction factor or a simple feedback algorithm. The feedback algorithm was chosen because the encoder can be easily implemented, and the code on the Arduino is relatively straightforward. The encoder chosen is also much cheaper than any PID controller that is suitable for this system.

If the desired implementation does not work, the open-source nature of the Arduino provides flexibility to debug and optimize the design.

Detailed Design (Schematic & Layout)

This system takes the analog signal sent from the Jetson computers and converts them to braking, steering, and throttling. A custom PCB schematic and layout were designed to accomplish this. The circuit is essentially a combination of two stepper motor control circuits. With this, the ATmega328p chip (with 32KB flash memory) was programmed to control two SN754410 Quadruple Half-H Bridge drivers. Each of these drivers is connected to one Geared Stepper Motor. One is for steering and the other for braking. An encoder was also connected to the ATmega chip to create a feedback system for the steering motor (which requires more accuracy).

In terms of my PCB layout, it is designed to be a two-layer PCB. The top layer is poured with a polygon pour connected with the 5 V net. The bottom layer is poured with GND. The top layer has all the connectors including two Molex connectors for the motor connections, one Molex connector for input power, a six-pin connector for the shaft encoder, and a four-pin header for the analog inputs. This is to be kept on the top so that they can be easily accessed. All the connections with the ATmega328p remain on the bottom layer because it is quite messy.

Schematic

schemeit1_5

Layout(Front)

schemeit2_6

Layout(Back)

schemeit3_7

Layout(3D)

schemeit4_8

Component Selection

The final components selected are as follows (prices were accurate at the time this was written):

componentcost_9

BOM

BOM_10

Analysis

Load Cases

According to the chips’ spec sheet, the maximum voltage is 5 V, and the current draw is 1 A. Mechanical load cases are included in the design parameter section.

Hand Calculations

Torque Calculation: Max Gear Ratio: 3 Min Torque Supplied From Motor: 3 Nm/3 = 1 Nm

Speed Calculation: 30 degrees/sec = 1800 degrees/min = 5 RPM: 5rpm * 3 (gear ratio) = 15 RPM

Testing Plan

Initial testing for this system was done mostly with a breadboard and prototyping board using the ATmega, SN754410, and stepper motors. A program was created using documentation provided by Arduino. Then, variable voltage inputs were placed throughout the system, and the resulting torque was measured at the required RPM. All of the primary data collection included input voltage, output torque, and RPM.

PCB Testing:

  1. Before soldering the board, test essential connections.
  2. During soldering, complete conductivity tests for all connections and possible shorts. Also, perform a resistance test for the resistors.
  3. Once populated, a sheet was created for a series of tasks that must be passed incrementally. Testing scripts are included below.

Testing Script

Blink.ino

Copy Code
/*
Blink
Turns on an LED on for one second, then off for one second, repeatedly.
This example code is in the public domain.
*/

// Pin 13 has an LED connected on most Arduino boards.
// Pin 11 has the LED on Teensy 2.0
// Pin 6 has the LED on Teensy++ 2.0
// Pin 13 has the LED on Teensy 3.0
// give it a name:
int led = 19;

// the setup routine runs once when you press reset:
void setup() {
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
}

// the loop routine runs over and over again forever:
void loop() {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}

Encoder.ino

Copy Code
#define encoder0PinA 19
#define encoder0PinB 20
int encoder0Pos = 0;
int led = 21;


void setup() {
Serial.begin(9600);
pinMode(encoder0PinA, INPUT_PULLUP);
pinMode(encoder0PinB, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(5), doEncoder, CHANGE);
pinMode(led, OUTPUT);
}
int valRotary,lastValRotary;
void loop() {
Serial.println(valRotary);
delay(100);
if (encoder0Pos>500){
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
delay(1000);
}

}
void doEncoder()
{
if (digitalRead(encoder0PinA) == digitalRead(encoder0PinB))
{
encoder0Pos++;
}
else
{
encoder0Pos--;
}

StepperMotorTest.ino

Copy Code
#include <Stepper.h>

const int stepsPerRevolution = 1036; // change this to fit the number of steps per revolution
// for your motor


// initialize the stepper library on pins 8 through 11:
Stepper steeringStepper(stepsPerRevolution, 2, 3, 5, 4);
Stepper brakingStepper(stepsPerRevolution, 12, 13, 15, 14);

int stepCount = 0; // number of steps the motor has taken

void setup() {
// put your setup code here, to run once:
steeringStepper.setSpeed(7);
brakingStepper.setSpeed(7);
}

void loop() {
steeringStepper.step(stepsPerRevolution);
//steeringStepper.step(-stepsPerRevolution);

brakingStepper.step(stepsPerRevolution);
//brakingStepper.step(-stepsPerRevolution);

}

TwoMotorSpiningCode.ino

Copy Code
#include <Stepper.h>

#define brakeInterrupt 6

const int stepsPerRevolution = 1036.3636; // change this to fit the number of steps per revolution
// for your motor
const int MAX_SPEED = 7;

// initialize the stepper library on pins 8 through 11:
Stepper steeringStepper(stepsPerRevolution, 2, 3, 5, 4);
Stepper brakingStepper(stepsPerRevolution, 12, 13, 15, 14);


void setup() {
// put your setup code here, to run once:
steeringStepper.setSpeed(MAX_SPEED);
brakingStepper.setSpeed(MAX_SPEED);
attachInterrupt(digitalPinToInterrupt(brakeInterrupt), doBrake, RISING);
}

void loop() {
steeringStepper.step(stepsPerRevolution);
//steeringStepper.step(-stepsPerRevolution);
}

void doBrake()
{
//braking motor steps
brakingStepper.step(stepsPerRevolution);
}

OneMotorWithEncoder.ino

Copy Code
#include <Stepper.h>

#define encoderPinA 2
#define encoderPinB 3

const int stepsPerRevolution = 1036; // change this to fit the number of steps per revolution
// for your motor
int steeringPin = 2;
int encoder; //encoder pin
int encoderPos = 0;
int lastPos;

// initialize the stepper library on pins 8 through 11:
Stepper steeringStepper(stepsPerRevolution, 2, 3, 5, 4);
Stepper brakingStepper(stepsPerRevolution, 12, 13, 15, 14);

int stepCount = 0; // number of steps the motor has taken

void setup() {
// put your setup code here, to run once:
steeringStepper.setSpeed(7);
brakingStepper.setSpeed(7);
pinMode(encoderPinA, INPUT_PULLUP);
pinMode(encoderPinB, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(2), doEncoder, RISING);
}

void loop() {
int sMotorStep = 1036;
steeringStepper.step(sMotorStep);
steeringStepper.setSpeed(7);
int actualSMotorStep = encoderPos*1036/2048;
int difference = sMotorStep - actualSMotorStep;
if (difference != 0) {

steeringStepper.step(difference);
}
}


void doEncoder()
{

if(encoderPos>lastPos) {

}
if(encoderPos>lastPos) {

}
lastPos = encoderPos;
if (digitalRead(encoderPinA) == digitalRead(encoderPinB)) {
encoderPos++;
}
else {
encoderPos--;
}
}

TwoMotorWithEncoder.ino

Copy Code
#include <Stepper.h>

#define encoderPinA 2
#define encoderPinB 3
#define brakeInterrupt 6

int encoder; //encoder pin
int encoderPos = 0;
int steeringPin = 2;
int brakingPin = 12;
int const MAX_SPEED = 7;

const int stepsPerRevolution = 1036; // change this to fit the number of steps per revolution
// for your motor
// initialize the stepper library on pins 8 through 11 for steering motor:
Stepper steeringStepper(stepsPerRevolution, 2, 3, 4, 5);
// initialize the stepper library on pins w through z for braking motor:
Stepper brakingStepper(stepsPerRevolution, 12, 13, 14, 15);

void setup() {
Serial.begin(9600);
pinMode(encoderPinA, INPUT_PULLUP);
pinMode(encoderPinB, INPUT_PULLUP);
pinMode(steeringPin, INPUT);
pinMode(brakingPin, INPUT);
attachInterrupt(digitalPinToInterrupt(2), doEncoder, RISING);
attachInterrupt(digitalPinToInterrupt(brakeInterrupt), doBraking, RISING );
}

void loop() {
//steering motor steps
int sMotorStep = 1036;
steeringStepper.step(sMotorStep);
steeringStepper.setSpeed(MAX_SPEED);
int actualSMotorStep = encoderPos*1036/2048;
//steering motor correction

int difference = sMotorStep - actualSMotorStep;
if (difference != 0) {

steeringStepper.step(difference);
}
}
void doBraking(){
//braking motor steps
int bMotorStep = analogRead(brakingPin);
brakingStepper.step(bMotorStep);
brakingStepper.setSpeed(MAX_SPEED);
}
int lastPos;
//position checking
void doEncoder()
{

if(encoderPos>lastPos) {

}
if(encoderPos>lastPos) {

}
lastPos = encoderPos;
if (digitalRead(encoderPinA) == digitalRead(encoderPinB)) {
encoderPos++;
}
else {
encoderPos--;
}
}
制造商零件编号 GRM188R60J474KA01D
CAP CER 0.47UF 6.3V X5R 0603
Murata Electronics
¥1.38
Details
制造商零件编号 LBM2016T2R2J
FIXED IND 2.2UH 340MA 540MOHM SM
Taiyo Yuden
¥0.90
Details
制造商零件编号 SN754410NE
IC HALF-H DRIVER 5.5V 16DIP
Texas Instruments
¥21.16
Details
制造商零件编号 LM3940IMPX-3.3/NOPB
IC REG LINEAR 3.3V 1A SOT223-4
Texas Instruments
¥13.27
Details
制造商零件编号 A000073
ARDUINO UNO SMD R3 ATMEGA328
Arduino
¥182.01
Details
Add all DigiKey Parts to Cart
TechForum

Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.

Visit TechForum