DIY mountain e-bike

My DIY mountain e-bike

1 Motivation:

Here are some of the motivations for pursuing this project ranked by personal preference:

1.1 Look and feel

I wanted a nice looking electric mountain bike not just a random ugly bike. Also front suspension and capabilities of a mountain bike, including nicer brakes etc. was the reason for this selection.

1.2 Weight

I wanted the bicycle to weigh not more than 15 kg to be easy to carry.

1.3 Power at disposal

Most of electric bikes use pedal assisted mechanism but I wanted to have the power whenever I want it no matter if I'm pedaling or not.

1.4 The joy of learning

This was my first Arduino project from which I learned a lot and that's priceless.

1.5 Price

Most of e-bikes cost a bunch and since there is always a chance for the bicycle to be stolen, I wanted to limit the amount of money I put on this and the potential to lose it. As you will see in section Bill of materials and final cost, this ended up with a fraction of money of a commercial e-bike.

2 Steps

Here is the bicycle before modifications:

IMG_20171206_101955_display.jpg

I started with ordering the following parts:

  • MINI USB Nano V3.0 ATmega328P CH340G/FT232 5V 16M Micro-controller Board Arduino
  • Mystery Firedragon 100A Max. 120A ESC BEC 5V/3A
  • RC Turnigy Aerodrive SK3 5065-236kv #3D Monster 6-10S
  • 6S 30C 22.2V 6200mAh LiPo Battery EC5
  • IMAX B6-AC+ B6AC Lipo NiMH 3S RC Akku Balance Charger Ladegerät DE Lieferung DY

First tests using and Arduino Uno:

IMG_20171217_172832_display.jpg

However, in the first try, not considering maximum current that the motor can put up with, I got a short-circuit in the motor due to over-heating which killed my motor controller and one cell in the battery.

IMG_20171224_121259_display.jpg

This forced me to rewind the motor which allowed me to use WYE configuration (in contrast to delta) for winding, providing higher torque. I also used thicker copper wires and a temperature sensor inside the motor to cut off the power before any over-heating. To achieve these, I had to order some new parts which were up to the job:

  • RC HobbyKing SS Series 190-200A ESC (Opto only)
  • 3A 5V Mini BEC UBEC DC converter module for LEDs Gimbal FPV 2-6S 4-6s Lipo (this provides 5V for Arduino since the new controller is Opto only = no 5V output)
  • Enamelled copper wire | 200g | ⌀0.9mm

This is the result of motor rewinding and adding a temperature sensor (using a 100k Thermistor):

IMG_20180127_101730_display.jpg

IMG_20180127_123956_Bokeh_display.jpg

Then I added a hall effect sensor and a magnet to the rear wheel to be able to check the speed. Here is the initial result of the control system that I had with three buttons (+, - and 0), very quick and very dirty:

IMG_20180128_155804_display.jpg

Later on, I 3D printed the whole control panel including a voltmeter-ammeter to be able to see how much current the system draws and how much juice is remained on my battery. For this I bought the following:

  • DC 100V 10A Voltmeter Ammeter Blue + Red LED Dual Digital Volt Amp Meter Gauge

And the reults:

IMG_20180507_234933_Bokeh_display.jpg

For connection to the motor controller and electronics on the rear side, I ran a lan cable with RS232 connectors on both sides. This is the V01 of the bike:

IMG_20180618_083632_display.jpg

And current version with 3D printed electronics box on the back and a rack in which everything is a bit neater:

photo_2018-10-30_09-48-14_display.jpg

I also 3D printed a fan (originally designed by Tom Stanton) for the motor to keep it cool (this motor is actually not designed for e-bikes and does not have enough cooling power by itself and relies on external cooling from quad's propeller).

3 Bill of materials and final cost

Desc Price(EUR)
MINI USB Nano V3.0 ATmega328P CH340G/FT232 5V 16M Micro-controller Board Arduino 2.92
3A 5V / 12V Mini BEC UBEC DC-Konverter-Modul für LEDs Gimbal FPV 2-6S 4-6s Lipo 1.59
RC HobbyKing SS Series 190-200A ESC (Opto only) 35.22
RC Turnigy Aerodrive SK3 5065-236kv #3D Monster 6-10S 49
6S 30C 22.2V 6200mAh LiPo Battery EC5 21.02
IMAX B6-AC+ B6AC Lipo NiMH 3S RC Akku Balance Charger Ladegerät DE Lieferung DY 22.98
Enamelled copper wire (KUPFERLACKDRAHT) 200g ⌀0.9 6.90
Misc (heat shrink, RS232 connectors, servo tester, 1602 LC panel, etc.) 30
DC 100V 10A Voltmeter Ammeter Blue + Red LED Dual Digital Volt Amp Meter Gauge 7.22
Sum 176.85

The bicycle itself was in the order of 200 EUR.

4 Performance and range

The maximum speed on a flat surface is ~1km/h/V, meaning that with a 6S LiPo battery (~24V), I get a maximum speed in the order of 25km/h. I was impressed by the amount of torque the system provides when going uphill. In most of the cases, I can rely only on the electric part without having to pedal. The only bottleneck is the discharge current of the battery. My current battery has 8Ah capacity with 10C discharge current which means the maximum constant current for long time is not recommended to exceed 8A. However, for quick boosts, one can ignore this. The place I live and use the e-bike around is not flat and therefore not perfect to get range records. Nevertheless, the range is almost 2km/V which means for an allowed charge state of my 6 cell (6S) battery (6x3 = 18V to 6x4.2 = 25.2V, difference = 7.2), I get almost 15km of range per charge which is not bad at all given the size and the weight of the battery. This e-bike is aimed to provide more torque than speed, but the winding type and configuration can be adjusted to change this.

5 Legal issues

The bike does not provide more than 250W at its peak which is below the legal threshold in most countries.

6 Conclusions

This project was a great pleasure to do. I learned a lot about micro-controllers and improved my electronics. I constantly improve the design whenever I find time to do so. The transmission system is the only flaw that I see in this design that ideally needs a complete redesign of the motor mount and rear wheel which I refused to step in since I am very happy with the current result and have no problem with changing the tires from time to time.

7 Source code for Arduino

I put my final code here if you are interested to take a look at or use:

#include <LiquidCrystal.h>
#include <Servo.h>//Using servo library to control ESC
Servo esc; //Creating a servo class with name as esc

// constants won't change. They're used here to set pin numbers:
const int hallSensor = 10;      // Hall Effect sensor
const int bBottom =  13;      // the number of the buttom button
const int bTop = 7;
const int bCenter = 10;
int bTopState = 0;         // variable for reading the pushbutton status
int bBottomState = 0;         // variable for reading the pushbutton status
int bCenterState = 0;         // variable for reading the pushbutton status
unsigned long lastTop, lastBottom = 0; //time variables for buttons

const int escStart = 1000;
const int escEnd = 2000;
const int escSteps = 10;

// variables will change:
int i = 0;
String thrState = "255";
String line1 = "Sp. Dis. T.  Th.";
String line2 = "";
int val = escStart;     //Creating a variable val
int valMap = 0;     //Creating a variable val

unsigned long lastturn, time_press; // time storage variables
float SPEED;     // the variable of storage of speed in the form of the decimal fraction
float DIST;     // distance storage variable in the form of decimal fractions
float w_length = 2.050;     // wheel circumference in meters

// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 3, d5 = 4, d6 =5, d7 = 6;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

// Thermistor variables
int ThermistorPin = 2;
int Vo;
float R1 = 10000;
float logR2, R2, T, Tc, Tf;
float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;

void setup() {
  esc.attach(8);     //Specify the esc signal pin,Here as D8
  esc.writeMicroseconds(escStart);     //initialize the signal to 1000
  // No pot for LCD backlight
  analogWrite(9,1);
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // initialize the buttons as input:
  pinMode(bBottom, INPUT);
  pinMode(bCenter, INPUT);
  pinMode(bTop, INPUT);
  //Thermistor
  pinMode(ThermistorPin, INPUT);
  // interrupt for hall effect sensor
  attachInterrupt(0,sens,RISING);     //number 2 on the board  
}

void loop() {
  while(1){
    i+=1;
    // Thermistor
    Vo = analogRead(ThermistorPin);
    R2 = R1 * (1023.0 / (float)Vo - 1.0);
    logR2 = log(R2);
    T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2));
    Tc = T - 273.15;
    Tf = (Tc * 9.0)/ 5.0 + 32.0; 
    // read the state of the pushbutton value:
    bTopState = digitalRead(bTop);
    bBottomState = digitalRead(bBottom);
    bCenterState = digitalRead(bCenter);
    if (bTopState == HIGH) {
      if (millis()-lastTop>150){
      if ((float)escEnd-val < ((float)escEnd-escStart)/escSteps){
        val = escEnd;
      }else{
        val+=((float)escEnd-escStart)/escSteps;
      }
    lastTop = millis();
      }
    } else if (bBottomState == HIGH) {
      if (millis()-lastBottom>150){
      if ((float)val-escStart < ((float)escEnd-escStart)/escSteps){
        val = escStart;
      }else{
        val-=((float)escEnd-escStart)/escSteps;
      }
      lastBottom = millis();
      }
    } else if (bCenterState == HIGH) {
      val = escStart;
    } else {
    line2 = "";
    }
    //val= analogRead(A0); //Read input from analog pin a0 and store in val
    // I use bottons instead:
    thrState= (int)((float)(val-escStart)/(float)(escEnd-escStart)*(float)100);
    if (Tc<110.){
      esc.writeMicroseconds(val);     //using val as the signal to esc 
    }else{
      esc.writeMicroseconds(escStart);
    }
    if (i==300){
      i = 0;
      lcd.setCursor(0, 0);
      lcd.print("                ");
      lcd.setCursor(0, 1);
      lcd.print("                ");
      // set the cursor to column 0, line 1
      lcd.setCursor(0, 0);
      // print the number of seconds since reset:
      lcd.print(line1);
      lcd.setCursor(0,1);
      if (line2.length()>0){lcd.print(line2);}else{
        lcd.print(SPEED, 0);
        lcd.setCursor(4,1);
        lcd.print(DIST,2);
        lcd.setCursor(9,1);
        lcd.print(Tc,0);
        lcd.setCursor(13,1);
        lcd.print(thrState);
      }
    }
  }
}
void sens() {
  if (millis()-lastturn > 80) {     //protection against random measurements (based on the fact that the bike will not go faster than 120 km / h)
    SPEED=w_length/((float)(millis()-lastturn)/1000)*3.6;     // calculation of speed, km / h
    lastturn=millis(); 
    DIST=DIST+w_length/1000; 
  }
}


Created: 2019-01-16 Mi 02:34

Validate