Introduction: Electric Arduino Go-kart

About: I love arduino and electronics in general. I enjoy tinkering and various other geeky activities. I also like studying Japanese.

Hello everyone! As the title says, I built an electric go kart which is powered by arduino! Here's a quick video to make you certain that this is the next thing you're going to build.

NEW VIDEO! Made for the Boca Bearings Innovation contest- please vote for me when it starts in September!

(Old video for reference: http://tinypic.com/player.php?v=w8x2s9&s=8)

My background: I'm a 15 year old high school student from California. My hobbies include building stuff, reading, and studying Japanese.

I've also entered into the Epilog Challenge contest, please vote for me!

A quick disclaimer: I take no responsibility for any injuries to yourself or anyone else. Electricity is DANGEROUS. Chain drives are EVEN MORE DANGEROUS. They could easily cut a finger off or worse. Wear a helmet when attempting things like this.

With that out of the way :)

Overview:

The drive setup uses a Hobbywing Xerun 150A brushless electronic speed controller to control a Savox BSM5065 450Kv motor. Batteries are 3x zippy lithium polymer - 5 cells, 5000mah. The motor has two large fans I pulled out of an old computer for cooling, mounted right over the motor. The chain drive is a 1:10 overall ratio, using a 15 tooth on the motor chained to a 30 tooth on the jackshaft, and a 9 tooth from the jackshaft to a 45 tooth on the wheel. The tires are 10" diameter so at 20 volts the top speed is around 30 mph. The ESC is controlled via PWM from the arduino. A throttle potentiometer on the steering wheel controls this. Constant current is around 40-50A, and the batteries last around 30 minutes with an average speed of 10-15mph. It requires a small push to get started (really, the motor just has to be rotating) and accelerates extremely fast. (and if anyone's wondering why it says FTL on the left control box, it's short for Faster than Light, which is the name I gave it.)

This is not going to be a guide to building this, because it's far too complex and every step wasn't documented, but rather detailed information for anyone who wants to make something similar.

I'm going to assume the reader has a decent understanding of electronics, Arduino, and radio control power systems.

Step 1: Drive System - Chains and Sprockets

(approximate) parts list:

(all sprockets are for #35 chain)

1x - 5/8" diameter jackshaft

2x - 5/8" bore pillow blocks with ball bearing

1x - 5/8" bore 45 tooth sprocket (Wheel)

1x - 5/8" bore 9 tooth sprocket (jackshaft #2, chained to wheel)

1x - 5/8" bore 30 tooth sprocket (jackshaft #1, chained to motor)

1x - (explained below) ? bore 15 tooth sprocket (motor)

3-4x - 5/8" bore shaft collars

red loctite - 1 small tube should be enough, I barely used half of it.

enough #35 chain

Just a quick note: This uses a sensorless brushless motor. They are not capable of starting under load. It may need a quick push before it can start. Don't try to start them under load. I already had one motor burn out because it stalled and the current burnt the coils' insulation. Sensored motors overcome this problem.

This is fairly straightforward. Select sprockets with the correct bore and chain size (which in my case was 5/8" and #35) and chain them together. The motor sprocket, however, will be harder. My motor's shaft was 6mm, a metric size. I found a bushing with an inner diameter of 6mm and an outer diameter of 3/4", effectively acting as a metric to imperial converter. I then attached a 3/4" bore sprocket to the bushing and put it onto the motor. Position the set screws of the sprocket in such a way as to clamp the bushing onto the motor's shaft, and add Loctite (unless you want to be able to remove it). Be careful to use the shaft already extending out of the motor instead of the (usually) included propeller adapter. Otherwise, the motor may bend from lateral stress, which it isn't designed for. (Mine was an rc airplane motor, so it's built for spinning propellers.) The motor mount I used was the Great Planes Large motor mount. However, I had to drill extra holes because the motor had a different mounting pattern.

Step 2: Power System

The 3 Lipo batteries supply a nominal 19-20V. This is routed through a Hella kill switch (big red switch in the photo) and a 120A fuse to the ESC and to a Battery Elimination Circuit (BEC). The power goes through a 3A fuse and a key switch before arriving at the BEC, which drops the 20V to a 12V suitable for the arduino and the rest of the electronics. The red LED in the image signifies 12V power and the green LED is 5V power from the arduino. The ESC has a small switch through which not much current passes to actually turn it on. The arduino has access to this through a relay, and it's controlled by the switch labelled ESC in the photo. The 3rd LED (grey in the pic, but red/green bicolor when on) is also controlled by this. The last switch in the back controls the fans.

Step 3: Lights

Just some replacement car 12V LED lights I got from ebay for $2 apiece. Controlled by the arduino through the PWM pins and a 2n7000 mosfet board I built. Contains 11 bulbs. 2 headlight, 2 taillight, 4 turn signal, 1 reverse, and 2 brake signal. The brake signals remain on as long as one of the following conditions is met: throttle is below the neutral point, esc is off, left joystick is NOT held down (The left joystick enables the throttle, as said in the next step). The turn signals are enabled by moving the left joystick in the respective direction. Headlights and taillights are controlled by the left three position toggle switch in the picture. Bottom is off, middle is 50% PWM, top is 100% PWM. The other toggle switch enables "hazards", that is, all turn signals flashing at the same time. The blue LED in the center is linked to the brake lights.

Step 4: Throttle Control System

This is handled by the right (1-axis) potentiometer on the steering wheel. The arduino maps the analog in from the throttle (0-1023) to the esc output (0-179). The throttle is only functional while the right joystick (2-axis) is held down, as a safety measure. In addition, the large clear joystick seen in the first picture allows for changing "gears" (actually just the ratio of the potentiometer to the output). This is reflected on the 7-segment display in the other picture. The gears are R - reverse, 1-8 (forward drive), N - neutral (simply outputs neutral PWM to the ESC), and P - park (outputs 0 PWM to the ESC, works like brake). The only brake available is the ESC's built-in function, which is triggered by moving the throttle below the neutral point. Additionally, if the arduino is powered on while the silver pushbutton labeled OVERRIDE is held down, it will start up into a "Basic Mode" where only the throttle and the ESC are functional. The throttle is mapped directly to the ESC, nothing else affects it.

Step 5: LCD

The LCD is a 320x240 led backlit model from ebay. It's controlled by an arduino shield that converts the 5V to the 3.3v required by the LCD. It displays throttle value, status of all the lights, and the voltage of the battery. It has a touch screen and SD card holder, but none of these have been implemented in the code.

Step 6: Additional Pictures + Code

The left and right control boxes which house all of the electronics,- and the battery holder. Yes, I know it's messy, but amazingly enough there are no short circuits.

Thanks! Feel free to ask any questions. If you want more specific pictures or schematics I can make those as well. The ino file is attached in case the code here isn't displaying properly.

Here's the code. It's really, really specific to my build, but snippets might useful to you guys. You can use it as much as you want but give credit if you want to distribute it.

#include <SimpleTimer.h> //   http://playground.arduino.cc/Code/SimpleTimer   
#include <FancyLED.h> //  http://playground.arduino.cc/Code/SimpleTimer 
#include <Servo.h> // default arduino servo library
#include <UTFT.h> //  http://playground.arduino.cc/Code/SimpleTimer >

extern uint8_t BigFont[];
const int throttlePin = A11; 
Servo esc;
const int escPWRSwitch=16;
const int escPWR=A13;
 volatile byte revolutions;
 unsigned int rpm;
 unsigned long timeold;
float voltage;
const int voltagePin=A9;
float current;
const int currentPin=A10;
UTFT myGLCD(ITDB32S,38,39,40,41);
long previousMillis = 0;  
long interval = 300;
SimpleTimer timer;
FancyLED left_1 = FancyLED(8, HIGH);
FancyLED left_2 = FancyLED(6, HIGH);
FancyLED right_1 = FancyLED(11, HIGH);
FancyLED right_2 = FancyLED(7, HIGH);
FancyLED brake_1 = FancyLED(3, HIGH);
FancyLED brake_2 = FancyLED(10, HIGH);
FancyLED brake_ind = FancyLED(44, HIGH);
const int joystick = A14;
int gear = 0;
int throttle = 34;
long indicatorInterval;
int leftIndicatorF;
int rightIndicatorF;
 // R - 11,7 (L - 8,6)
int indicatorState;
void setup()
{
esc.attach(45);
 pinMode(escPWR, OUTPUT);
 pinMode(A1, OUTPUT);
  pinMode(A2, OUTPUT);
 pinMode(A3, OUTPUT);
 pinMode(A4, OUTPUT);
 pinMode(A5, OUTPUT);
 pinMode(A6, OUTPUT);
 pinMode(A12, OUTPUT);</p><p> digitalWrite(escPWR, HIGH);
  myGLCD.InitLCD(PORTRAIT);
  myGLCD.setFont(BigFont);
left_1.turnOff();
left_2.turnOff();
right_1.turnOff();
right_2.turnOff();
leftIndicatorF = timer.setInterval(450, leftIndicatorFunct);
rightIndicatorF = timer.setInterval(450, rightIndicatorFunct);
timer.disable(rightIndicatorF);
timer.disable(leftIndicatorF);</p><p>  myGLCD.clrScr();
  myGLCD.fillScr(255, 0, 0);
  myGLCD.setColor(255, 255, 255);
  myGLCD.setBackColor(255, 0, 0);
  
  ///// If override button is held during startup, enter "basic mode" - only throttle and display are functional
  int basic_test = digitalRead(14);
  if (basic_test == HIGH)
  {
    myGLCD.print("BASIC MODE", CENTER, CENTER);
        pinMode(13, OUTPUT);</p><p>    digitalWrite(13, HIGH);
    basic();
  }
}
 
void loop()
{
//////////
  current = ((analogRead(currentPin)));
  /////////
  voltage = (analogRead(voltagePin)) * (0.02441)  ;
//////////
 if (digitalRead(escPWRSwitch) == HIGH) {
   digitalWrite(escPWR, LOW);
}
  else {
   digitalWrite(escPWR, HIGH);
}
///////////</p><p>throttle = analogRead(throttlePin);
throttle = map(throttle, 0, 1023, 0, 179);</p><p>if (gear > 0)
{
  if (throttle > 35)
  {
throttle = map(throttle, 0, 179, 35, ((140 / 8) * gear)+40);
  }
 
}
else if (gear == 0)
{
throttle = 34;
}
else if (gear == -1)
{
throttle = 34;</p><p>}
else if (gear == -2)
{
throttle = 0;
}</p><p>if (analogRead(A8) > 1000)
{
esc.write(throttle);
}
else
{
esc.write(34);
}</p><p>//////////////
    unsigned long currentMillis = millis();
 int joystick_val = analogRead(joystick);</p><p>  if(currentMillis - previousMillis > interval) {
if (joystick_val < 1000)
{
if (830 < joystick_val)
{
  //up
 
  
  
  if (gear < 8 && gear > 0)
  {
    
    gear++;
  }
      else if (gear != 8)
  {
    gear = 1;
  }</p><p>}
else if (680 < joystick_val)
{
  //down
  if (gear > 1)
  {
  gear--;
  }
}
else if (350 < joystick_val)
{
  //left (reverse)
  gear = -1;
}</p><p>else if (70 < joystick_val)
{
  //right
  if (gear == 0)
  {
  gear = -2;
  }
else {
  gear = 0;
}
}}
  }
//////////////
if (gear == 1)
{
   digitalWrite(A3, LOW);
  digitalWrite(A2, HIGH);
  digitalWrite(A6, LOW);
  digitalWrite(A4, HIGH);
  digitalWrite(A1, LOW);
  digitalWrite(A12, LOW);
  digitalWrite(A5, LOW);</p><p>}
else if (gear == 2)
{
    digitalWrite(A3, HIGH);
  digitalWrite(A2, LOW);
  digitalWrite(A6, HIGH);
  digitalWrite(A4, HIGH);
  digitalWrite(A1, HIGH);
  digitalWrite(A12, LOW);
  digitalWrite(A5, HIGH);</p><p>}
else if (gear == 3)
{
  digitalWrite(A3, HIGH);
  digitalWrite(A2, LOW);
  digitalWrite(A6, HIGH);
  digitalWrite(A4, LOW);
  digitalWrite(A1, HIGH);
  digitalWrite(A12, HIGH);
  digitalWrite(A5, HIGH);</p><p>}
else if (gear == 4)
{
  digitalWrite(A3, LOW);
  digitalWrite(A2, HIGH);
  digitalWrite(A6, HIGH);
  digitalWrite(A4, LOW);
  digitalWrite(A1, LOW);
  digitalWrite(A12, HIGH);
  digitalWrite(A5, HIGH);</p><p>}
else if (gear == 5)
{
  digitalWrite(A3, HIGH);
  digitalWrite(A2, HIGH);
  digitalWrite(A6, HIGH);
  digitalWrite(A4, LOW);
  digitalWrite(A1, HIGH);
  digitalWrite(A12, HIGH);
  digitalWrite(A5, LOW);</p><p>}
else if (gear == 6)
{
  digitalWrite(A3, HIGH);
  digitalWrite(A2, HIGH);
  digitalWrite(A6, HIGH);
  digitalWrite(A4, HIGH);
  digitalWrite(A1, HIGH);
  digitalWrite(A12, HIGH);
  digitalWrite(A5, LOW);</p><p>}
else if (gear == 7)
{
  digitalWrite(A3, HIGH);
  digitalWrite(A2, LOW);
  digitalWrite(A6, LOW);
  digitalWrite(A4, LOW);
  digitalWrite(A1, LOW);
  digitalWrite(A12, HIGH);
  digitalWrite(A5, HIGH);</p><p>}
else if (gear == 8)
{
  digitalWrite(A3, HIGH);
  digitalWrite(A2, HIGH);
  digitalWrite(A6, HIGH);
  digitalWrite(A4, HIGH);
  digitalWrite(A1, HIGH);
  digitalWrite(A12, HIGH);
  digitalWrite(A5, HIGH);</p><p>}
else if (gear == 0)
{
  digitalWrite(A3, LOW);
  digitalWrite(A2, LOW);
  digitalWrite(A6, HIGH);
  digitalWrite(A4, HIGH);
  digitalWrite(A1, LOW);
  digitalWrite(A12, HIGH);
  digitalWrite(A5, LOW);</p><p>}
else if (gear == -2)
{
  digitalWrite(A3, HIGH);
  digitalWrite(A2, HIGH);
  digitalWrite(A6, HIGH);
  digitalWrite(A4, HIGH);
  digitalWrite(A1, LOW);
  digitalWrite(A12, LOW);
  digitalWrite(A5, HIGH);</p><p>}
else if (gear == -1)
{
  digitalWrite(A3, HIGH);
  digitalWrite(A2, HIGH);
  digitalWrite(A6, HIGH);
  digitalWrite(A4, HIGH);
  digitalWrite(A1, LOW);
  digitalWrite(A12, HIGH);
  digitalWrite(A5, HIGH);</p><p>}</p><p>//////////////
if (analogRead(A15) > 1000)
{
  digitalWrite(12, HIGH);
    digitalWrite(4, HIGH);
  digitalWrite(5, HIGH);
  digitalWrite(9, HIGH);
}
else if (analogRead(A15) < 10)
{
  digitalWrite(12, LOW);
    digitalWrite(4, LOW);
  digitalWrite(5, LOW);
  digitalWrite(9, LOW);
}
else
{
  analogWrite(12, 128);
    analogWrite(4, 128);
  analogWrite(5, 128);
  analogWrite(9, 128);
}</p><p>//////////////
if (digitalRead(15) == HIGH)
{
  timer.enable(rightIndicatorF);
  timer.enable(leftIndicatorF);
  indicatorState = 1;
}
else if (timer.isEnabled(leftIndicatorF) && timer.isEnabled(rightIndicatorF) && digitalRead(15) == LOW)
{
    timer.disable(rightIndicatorF);
  timer.disable(leftIndicatorF);
  left_1.turnOff();
left_2.turnOff();
right_1.turnOff();
right_2.turnOff();
indicatorState = 0;
}
else if ((analogRead(A7) > 1000 || analogRead(A7) < 10) && indicatorInterval == 0)
{
  indicatorInterval = millis();
}</p><p>if (millis() - indicatorInterval > 250 && indicatorInterval != 0)
{
if (analogRead(A7) > 990)
{
  
  timer.toggle(leftIndicatorF);
  if (!timer.isEnabled(leftIndicatorF))
   {
    left_1.turnOff();
   left_2.turnOff();
   indicatorState = 0;
   }
   else
   {  indicatorState = 2;
   }
  timer.disable(rightIndicatorF);
right_1.turnOff();
right_2.turnOff();</p><p>}
else if (analogRead(A7) < 30)
{
 
  timer.toggle(rightIndicatorF);</p><p>   if (!timer.isEnabled(rightIndicatorF))
   {
    right_1.turnOff();
    right_2.turnOff();
      indicatorState = 0;</p><p>   }
     else
   {  indicatorState = 3;
   }
  timer.disable(leftIndicatorF);
    left_1.turnOff();
left_2.turnOff();</p><p>}
indicatorInterval = 0;
}
timer.run();
//////////////
if (throttle < 35 || digitalRead(16) == LOW || analogRead(A8) < 1000)
{
  brake_1.turnOn();
  brake_2.turnOn();
  brake_ind.turnOn();
}
else
{
    brake_1.turnOff();
  brake_2.turnOff();
    brake_ind.turnOff();</p><p>}
////////////</p><p>  if(currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;   
  myGLCD.printNumF(voltage, 3, CENTER, 10);
  if (digitalRead(16) == HIGH)
  {
  myGLCD.print("ESC ON ", CENTER, 40);
  }
  else
  {
      myGLCD.print("ESC OFF", CENTER, 40);
  }
  if (analogRead(A8) > 1000)
  {
      myGLCD.print("ACTIVE", CENTER, 70);
  }
  else
  {
      myGLCD.print("      ", CENTER, 70);
  }
  if (analogRead(A15) > 1000)
  {
      myGLCD.print("HEADLIGHTS 100%", CENTER, 100);
  }
  else if (analogRead(A15) < 10)
  {
   myGLCD.print("HEADLIGHTS OFF ", CENTER, 100);
  }
  else
  {
          myGLCD.print("HEADLIGHTS 50% ", CENTER, 100);
  }
  /////////
  if (indicatorState == 1)
  {
          myGLCD.print("HAZARDS", CENTER, 170);
          
  }
  else if (indicatorState == 2)
  {
          myGLCD.print("<------", CENTER, 170);
  }
  else if (indicatorState == 3)
  {
          myGLCD.print("------>", CENTER, 170);
  }
    else if (indicatorState == 0)
  {
          myGLCD.print("       ", CENTER, 170);
  }
  if (voltage < 18.5)
  {
              myGLCD.print("LV WARNING", CENTER, 200);
  }
  else
  {
                  myGLCD.print("          ", CENTER, 200);
  }
  
  myGLCD.printNumI(throttle, CENTER, 140, 3);
    myGLCD.printNumI(gear, CENTER, 240, 3);</p><p>  myGLCD.printNumF(current, 3, CENTER, 280);
  }
  ////////////
}</p><p>void leftIndicatorFunct() 
{
  left_1.toggle();
  left_2.toggle();
}</p><p>void rightIndicatorFunct() 
{
  right_1.toggle();
  right_2.toggle();
}</p><p>void basic() {
  //////basic mode for testing purpose
   digitalWrite(escPWR, LOW);</p><p>  while (true)
  {
    throttle = analogRead(throttlePin);</p><p>throttle = map(throttle, 0, 1023, 0, 179);
  myGLCD.printNumI(throttle, CENTER, 140, 3);</p><p>esc.write(throttle);
  }
}</p>
Epilog Challenge VI

Participated in the
Epilog Challenge VI