RC motor and ESC on an ebike - handy arduino solution

bobc

10 kW
Joined
Jan 20, 2011
Messages
993
Location
Knutsford England
A while ago I built an ebike control solution using a custom PCB with an AVR tiny10 micro. This works fine (I'm using it on my current 'hack' bike. But nobody else has the PCB, and the programming/development/debug solution is somewhat tortuous, so it's not a solution available to everybody. (or in fact anybody at all else....)
Recently I've been using an arduino nano in a battery balancer, and it occurs to me that it represents an uncannily perfect solution to the RC motor control conundrum. The nano board costs £1.50 (less than $2), the development environment is user friendly and free off the web, the programming interface is USB (it's universal) and the facilities are all there to make a nice, user friendly, LEGAL ebike power system when combined with $12 ESC and a $35 outrunner.
As an when the thing develops I'll post updates on here. I plan to put it on the cycloidal mid-drive (it solves the otherwise insoluble problem of engineering a speed limit at 25kph and motor voltage control on a thru-the-gears mid drive)
 
Even with the high reduction provided by the cycloidal, RC motors can still struggle when starting from a stop. I would recommend a mid drive that allows the motor to use the bikes gears, rather than a one-speed, and I'd further recommend adding at least two low-ESR capacitors to the ESC power input.

Best of luck...
 
I don't expect it to haul away from stationary, you really need halls in the motor to do that.....
I set off with 1/2 a turn of the pedals, then twist & go. It's not a great hardship for me.....:)
 
Made a start: using the 3rd party PWM library I get the 20ms pulse rate dead easy, and with the "analogWrite()" control (PWM from pin 9) I can control pulsewidth from 1ms to 2ms by writing 125 to 250. That's plenty enough resolution. If I feed the PWM back into another input I can time the main loop to 20ms cycles. The built in millis() function gives me 1ms resolution on the time for a wheel revolution and a gearbox output revolution (for speed limits and motor control respectively)
I'm pondering the power supply; a BEC ESC would directly give me 5V but they only seem to be available up to 6s capable ESCs. The linear reg on the nano is limited to 20V max. I could tap off using a balance port but I'd like to make the thing applicable to anything, and I want full battery volts input both for LVC and for compensation. I guess tapping off a balance port for control system power is not too bad, it's only a few milliamps after all, but that means a separate switch. Damn - the only thing that makes sense is to have an extra linear regulator to reduce battery volts to between 20 and 12V. Maybe simply a resistor...
 
Thinking about this on the way to work this morning. I can make instruments with needles (like they used to be...) by using RC servos. I am so tempted to buy 3 of the £2 servos from hobbyking to make a dashboard.....

Now thinking about what to display: speed, battery volts, battery amps. I could do a "gas gauge" but I think volts says it better
 
bobc said:
... Damn - the only thing that makes sense is to have an extra linear regulator to reduce battery volts to between 20 and 12V. Maybe simply a resistor...
If I remember correctly the Nano has on board regulator. You could use a zener diode to limit the incoming voltage (and that would allow it to work with ANY battery pack).
 
bobc said:
Thinking about this on the way to work this morning. I can make instruments with needles (like they used to be...) by using RC servos.
That's basically how the mechanical cockpit displays work in airplanes, AFAICR.
 
I just bought 3 servos (£1.50 each) Less than a fiver, unbelievable. Now got to think about a nice little box to mount on the handlebars. And a pretty dash. And cute little needles that will nevertheless be visible.
Whatever, before I make a dash, these things are dead handy for debugging code that talks to an ESC.....
I'll use a 3 terminal regulator Lew2, least lossy & most widely applicable solution, cheap & simple too. I'll share the losses with the built in one, probably get a to220 lm340-15 or 7815 - I'll see what's cheapest.
 
Problem I ran into with the regulators was that most of the ones I looked at had a 40VDC upper limit for incoming power.

I played around with the nano a bit. See my website if you want/need a DWG of the nano.
http://www.keywild.com/cad_library/KeyWild_Cad_Library_index.htm Breadboard section
image004.png
 
Started building version 1 on veroboard tonight. This is going on an ESC with BEC so no supply issues :) I bought a metre of 0.7mm constantan off ebay to make a shunt (I'll use 2cm of it...) - try to buy a shunt & the prices are ridiculous! So the veroboard has 7 resistors and 4 capacitors on (+ that shunt....)... and an arduinonano of course :)
It will have an old fashioned speedo with a needle, switchable to show battery volts and amps instead of mph. (so far I've only been able to make 2 "servo drive" PWM outputs work on pins 9 & 10)
 
A week on, I have cabling & 2 small veroboad prototypes working (so far so good). A proper PCB solution would be the same size as the nano, but the veroboard "overhangs" quite a bit on each side.
OK the main board has the following connections:
1) 3 pins to gearbox output hall sensor
2) 3 pins to wheel sensor (or just use 2 to a reed switch)
3) 3 pins to ESC standard interface - if BEC this supplies 5V
4) 5 pins to handlebars
5) 2 "bolt holes" either side of shunt in battery -ve
6) 1 pin to battery +ve

the 5 connections to the handlebars are
1] servo pulses output to gauge servo
2] 5V
3] 0V
4] hall effect throttle input
5] dash select input

the dash select input is shorted to 0V by the brake lever switch (if fitted) so the 'puter doesn't try to fight the brakes. Otherwise a SPDT on-off-on switch selects between dashboard display of speed, battery volts or battery amps. I expect it will spend most time displaying battery volts.

So; a single 5 core wire connects the handlebars to the electrics. Here's the Arduino code (so far), no control code yet, just checks on interfaces
I can show a snap of the boards & wiring if anyone wants.... it's not pretty...
Code:
// ebike controller
// wheel reedswitch/hall on D2
// gearbox reedswitch/hall on D3
// brake switch on A2
// throttle on A1
// battery current on A0
// battery volts on A3
// D9 is PWM control to ESC
// D8 connected to D9 - use D9 pwm to time program flow
// D10 is PWM to control speedometer needle on an RC servo

#include <PWM.h>

#define throttleMin 165      //ADC when throttle wound on full
#define throttleMax 740      //ADC when throttle off
#define servomin 65          //PWM control for servo left PWM 125=1ms 65 is min servo
#define servomax 295         //PWM control for servo right PWM 250=2ms 295 is max servo
#define ESCmin 65            //PWM control for ESC slow PWM 125=1ms
#define ESCmax 295           //PWM control for ESC fast PWM 250=2ms
#define LVC 789              //battery volts conversion low limit
#define speedfactor 22374    //this is 22374 x circumfrence(m) to give 1/10mph scaling
#define ampsscale 93         //= Rshunt * 1024 / 1.1
#define voltsscale 0.05156   //=  48 * 1.1 / 1024
#define ampsfilter 0.001     // filter delay = 20ms/ampsfilter

int throtl;                  // Throttle position ADC
int dashno;                  // dash readout control ADC
int ESCno;
int test2;                   //
int test3;                   //
int dashselect;              // Adc input 0 = brake switch, else dash select
float volts;                 // battery volts
volatile int gearspeedcount; // 20ms cycles since last gear turn
volatile unsigned int Tgear; // gear turn duration in milliseconds
int lastTg;                  // enable Tgear calculation
volatile int speedcount;     // 20ms cycles since last wheel turn
volatile unsigned int Twheel; // wheel turn duration in milliseconds
int lastTw;                  // enable Twheel calculation
unsigned int roadspeed;      // speed in 1/10ths mph
unsigned int rpm;            // rpm in err.... rpm
float amps;                  // battery amps
float filteredamps;          // battery amps filtered 20s

// Interrupt Service Routine (ISR) for gear sensor
void ISR_gear ()
{ unsigned int temp;

  gearspeedcount = 0;
  temp = millis();
  Tgear = (temp - lastTg);
  lastTg = temp;
}  // end of ISR_gear

// Interrupt Service Routine (ISR) for wheel sensor
void ISR_wheel ()
{ unsigned int temp;

  speedcount = 0;
  temp = millis();
  Twheel = (temp - lastTw);
  lastTw = temp;
}  // end of ISR_wheel

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);         // serial debug via the usb uart
  Serial.setTimeout(10000);   // 10s serial timeout
  Serial.println("throttle ADC conversion");

  pinMode(2, INPUT);          // wheel reedswitch falling interrupt
  pinMode(3, INPUT);          // gearbox reedswitch falling interrupt
  pinMode(4, INPUT);          // brake switch pulls low
  pinMode(8, INPUT);          // ESC output (9) fed back in here

  attachInterrupt(digitalPinToInterrupt(3), ISR_gear, RISING); //pin 3 gearspeed
  attachInterrupt(digitalPinToInterrupt(2), ISR_wheel, RISING);//pin 2 wheelspeed

  InitTimersSafe();
  //  SetPinFrequencySafe(11, 30); // D11 is another RCservo interface.
  SetPinFrequencySafe(9, 50); // D9 is ESC control output at 50Hz. Also sets D10
  pinMode(13, OUTPUT);        // LVC lights LED on arduino
  analogWrite(9, servomin);     // motor off
  analogWrite(10, servomax);    // try 2nd pwm pin
  pwmWrite(11, 128);
  //analogWrite(11, 1);       // try 3rd pwm pin
  analogReference(INTERNAL);  // use bandgap 1.1V ref
  delay(10);
  throtl = analogRead(A1);     // and do a dummy ADC read
  dashno = 150;
  test2 = 150;
  test3 = 30;
  filteredamps = 0.0;
  ESCno = ESCmin;
}

void loop() {
  // put your main code here, to run repeatedly:
  while (digitalRead(8) == 0) {  // delay - wait for 50Hz clock
  }
  noInterrupts();
  gearspeedcount += 1;
  speedcount += 1;
  interrupts();
  if (gearspeedcount > 50) { //1second
    rpm = 0;
  }
  else {
    rpm = 60000 / Tgear;
  }
  if (speedcount > 100) { //2seconds
    roadspeed = 0;
  }
  else {
    roadspeed = speedfactor / Twheel; //in 0.1mph steps
  }
  amps = float(analogRead(A0)) * ampsscale; // ampsscale;
  throtl = analogRead(A1);     // read throttle
  if (throtl < 0) {throtl = 0;}
  dashselect = analogRead(A2); // what to display?
  volts = float(analogRead(A2)) * voltsscale;      //
   filteredamps = (1.0 - ampsfilter) * filteredamps + ampsfilter * amps;
  if ((dashselect < 135) || (throtl < (throttleMin - 20)) || (throtl > (throttleMax + 20)))
  { // brake switch or throttle too high or low....... stop motor
    ESCno = ESCmin - 20;
  }
  else if (dashselect < 419) { // display battery amps
    dashno = int(amps * float(servomax-servomin) / 20.0);
  } // 20amp range
  else if (dashselect < 719) { // display speed
//    dashno = roadspeed * (servomax-servomin) / 350;
    dashno = (throtl - throttleMin)/3;
  } // 35mph range
  else { // display battery volts
    dashno = volts * (servomax-servomin) / 300;
  } // 30V range
  analogWrite(9, ESCno);
  analogWrite(10, (dashno+servomin));
  analogWrite(11, test2);
  Serial.print(amps);
  Serial.print(" ");
  Serial.print(throtl);
  Serial.print(" ");
  Serial.print(dashselect);
  Serial.print(" ");
  Serial.println(volts);
}
 
There's plenty of IO left, but for driving an RC servo I could only make 2 channels work (on the 16 bit timer). One 8 bit timer is used as a system clock but there is a further 8 bit timer which was tantalisingly close to doing the business, but not quite. There's a good chance that one could go into this a little more deeply and get 3 servos working. Also the Arduino "basic" system as supplied has 2 interrupts nicely packaged on pins 2 and 3, so I've used these for the speed detections. The chip can have other pins used as interrupts at the expense of slightly more software work, and that would free up pin 3 to be a PWM timer output.... You may have spotted that I hardwired pin 8 to pin 9, so the PWM driving the ESC is fed back in to control the machine "heartbeat"; a more professional approach would have been to directly use a timer interrupt - once again I just did it the easy way.
I wanted 3 dials, but it's a bit too hard so I'm just having one :)
(just to be clear, there are 2 RC servo interfaces working very easy with excellent resolution. I'm using one for an analog dash dial and the other to control an RC ESC to run the bike motor)
 
Just to be totally clear, (having re looked at one or 2 posts above) this circuit is a replacement for the "servo tester" that many folk use as part of an RC motor build for the throttle interface. It's not replacing the RC ESC!!!
I've been there and done that (servo tester thing); it works but it's twitchy & sensitive to drive, the servo tester costs money & has to be dismembered and butchered to make it work. I drove several thousand miles on something like that (I actually used a dual 555 timer [556] to make the interface, but the result is the same) & frankly other folk found it very difficult to start (the motor would tend to lose synch immediately for strangers). By using the bicycle speed to limit the ESC control the twitchiness can be eliminated, making a result that is actually quite nice to drive.
It's cheap, and can be made totally legal. My 1st prototype will likely be a bit of a dogs breakfast, but the system is potentially small neat and lightweight too.
 
I started out with a servo tester on my RC system and low end sync was not great. I'm using a Cycle Analyst now as a servo tester and it works so much better, but they are expensive. I suspect that this system would provide a better low end sync as you indicated, and inexpensive to build. If you were to supply a schematic and code for this it would be very cool. You could likely fit it all into a small project box that would fit on the handlebars and mount the servo gauge, switches, lights, etc to that as well.

-Warren
 
This is the main board, you can see the Arduino nano on there and the 5way connection to the handlebar devices
View attachment 2
The back side photo shows the battery shunt made of 4 parallel 0.7mm constantan
View attachment 1
This is the small board on the dash/handlebars. you can see the servo (dash needle) and a hall throttle twist grip
DSC01650.JPG
More guff to follow :) - principally schematics
This is all pretty easy stuff to anyone who's capable of assembling an ebike, especially the Arduino stuff.
 
I'll just explain why I didn't put it all on one handlebar mounted unit, it's so there's only the one small cable running to the handlebars (the 5 way cable). For me it WOULD be a problem taking the current measurement up there (heavy gauge battery cables to and from). So I'm leaving the "power" stuff down by the bottom bracket where it's needed.
That's all the stuff (in the pictures), there's a 56p switch, the shunt cost me £1, the Arduino £1.50 and the servo £1.50. The hall throttle was £5.50.

To complete the whole system I've used a 6354 outrunner at £40; a "Mystery" 80A ESC (BEC) at £13; a main battery switch at £1.20; and a 5Ah 6s LiPo brick at £28.30. I expect that should do about 7miles range; get more batteries to go further :)

It will have analog readouts of battery volts (gas gauge), battery amps (power) or speed, will be made compliant with EU power and speed limits, have good drivability and reasonable safety built in (power goes off when brakes are applied or in the case of any short or open circuit on any of the hall throttle wires.

I think that doesn't look too bad!
 
The schematic is dead simple, mostly connectors, + a few resistors & caps on the analog inputs
arduinoebike 001.jpg
Note the battery current measurement has an RC 22ms time constant to average over many pwm cycles.
The battery voltage measurement range is up to 52.8V (1.1Vref * 48). alter the 47k resistor to change it (and a #define at the top of the code...)

If reed switches are used, caps will be needed on the D2 and D3 pins to combat bounce. Shouldn't be needed with hall sensors.
 
Bunged some electrons through my home-made shunt (in the picture above): it measures 5.5milli-ohm. With the 1.1V reference I get amps measurement quantised in 0.2A steps. Everything is cool at 10A.
 
Quick test of interrupt code for speed and gearbox rpm measurement; perfect "out of the box" :D - the code above gives me speed in 1/10ths mph and rpm, and when the pulses stop this is detected in 1/2s or 1s (like it was supposed to).
Nice - normally this kind of stuff tests one's resolve and equanimity....
I've made some rather shonky bits and pieces, battery holder on the bottle cage rivnuts and analogue speedo tiewrapped to the handlebars.
Next job is to make the magnet & hall sensor work on the cycloidal gearbox output. On 2nd thoughts I'll put it on the crank, that way I can try the pedelec thing... I should use more magnets on the crank so it reacts faster as a pedelec, 5 should be enough
 
Back
Top