Throttle solution for drop bars / road bikes with Arduino

SamRich

100 W
Joined
Jan 16, 2014
Messages
142
Location
San Diego, CA
I couldn't find a good solution for speed modulation with dropbars. I tried installing a throttle but it won't fit on the bars and even if it did the ergonomics wouldn't be great.
There was a good discussion here: http://endless-sphere.com/forums/viewtopic.php?f=3&t=25334

I have some experience using Arduinos so I bought a Nano version and programmed it to control the speed of the motor. The throttle input to most BLDC controllers is a continuous value between 0 and 5V (usually more like 1V-3.5V) - proportional to the desired speed. The Arduino can be used to output a 5V PWM signal and low pass filtered using an RC filter to generate a DC signal.
20140308_171109.jpg

Here's the wiring diagram:
Presentation1.jpg

Here are the buttons on the right side held temporarily with tape:
20140308_171809.jpg

I used phone wire which is thin and flat. Should be able to easily tuck it under the griptape.
Here are the 4 button functions:
Left hand
Button 1 - Power: Needs to be pressed to have the motor run. I thought it would be a good safety feature.
Button 2 - Reset: Stops everything and resets the speed to 0 since toggling the power button only turns the motor on and off at what ever speed is set with the right hand. This should be useful to accelerate from a stop slowly.

Right hand
Button 1 UP: Increases the speed one step. If held pressed the speed is increased every 250ms.
Button 2 Down: Decreases the speed one step. If held pressed the speed is increased every 250ms.
10 steps total.

Here it is in action (in the workshop):
[youtube]uIlfj8H-W_8[/youtube]

Here's the code for the arduino:
Code:
String inputString;
String Temp;
char buffer[100];
char type;

const char SET_INPUT  = 'I';
const char SET_DOWN  = 'D';
const char SET_UP  = 'U';

int voltage;
int pinT=3;

int DOWN=0;
int UP=50;
int STEP=10;
int MINVAL=70;
int MAXVAL=170;

int power=0;
int reset=0;
int DOWNCOM=0;
int UPCOM=0;
void setup() {

  Serial.begin(9600);
  analogWrite(pinT, 0);
  pinMode(6, OUTPUT);//RESET/power
  digitalWrite(A0, HIGH);
   digitalWrite(A1, HIGH); 
  digitalWrite(A2, HIGH); 
  digitalWrite(A3, HIGH); 
  inputString.reserve(100);
}
//A0 Right Green - UP
//A1 Left Green - Power
//A2 Right Yellow - Down
//A3 Left Yellow - Reset

void loop() {
  processSerial();
  power=analogRead(A1);
  reset=analogRead(A3);
  DOWNCOM=analogRead(A2);
  UPCOM=analogRead(A0);
  if(power<128&reset>128){
    if ((UP-DOWN)<MINVAL){
      UP=MINVAL;
      DOWN=0;
    }
    if ((UP-DOWN)>MAXVAL){
      UP=MAXVAL;
      DOWN=0;
    }
    voltage=max(UP-DOWN,MINVAL);
    analogWrite(pinT,voltage);
    if(UPCOM<128){
      UP=UP+STEP;
      if ((UP-DOWN)<MINVAL){
        UP=MINVAL;
        DOWN=0;
      }
      if ((UP-DOWN)>MAXVAL){
        UP=MAXVAL;
        DOWN=0;
      }
      voltage=max(UP-DOWN,MINVAL);
      analogWrite(pinT,voltage);
      delay(250);
    }
    if(DOWNCOM<128){
      DOWN=DOWN+STEP;
      if ((UP-DOWN)<MINVAL){
        UP=MINVAL;
        DOWN=0;
      }
      if ((UP-DOWN)>MAXVAL){
        UP=MAXVAL;
        DOWN=0;
      }
      voltage=max(UP-DOWN,MINVAL);
      analogWrite(pinT,voltage);
      delay(250);
    }
    //Serial.println(voltage); 
  }
  else if(reset<128){
    analogWrite(pinT,0);
    UP=MINVAL;
    DOWN=0;
  }
  else{
    analogWrite(pinT,0);
  }
}



void processSerial(){     
  if ( Serial.available()>0){
    char inChar = (char)Serial.read(); 
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag
    // so the main loop can do something about it:
    if (inChar == '\n') {
      //Serial.println(inputString);  

      if(inputString.charAt(0)==SET_INPUT){

        Temp=inputString.substring(1,2);  
        Temp.toCharArray(buffer, 10);
        power=atoi(buffer);//compensate for system response
        Serial.println(power); 

      }

      if(inputString.charAt(0)==SET_DOWN){

        Temp=inputString.substring(1,1);  
        Temp.toCharArray(buffer, 10);
        DOWN=DOWN+STEP;


      }

      if(inputString.charAt(0)==SET_UP){

        Temp=inputString.substring(1,1);  
        Temp.toCharArray(buffer, 10);
        UP=UP+STEP;

      }

      inputString="";//Clear inputstring

    }
  }
}
 
I like it ..

I think it were me I would have the button2 on the right just return to zero once pressed , and have button1 on the right stepping up a little faster unless you are using re-gen..

and only have button1 on the left needs to be pressed for the right buttons to function and when button1 on the left is released thottle output gets reset to zero.
 
OK, nice start, but on the other side, what happens if your motor is in high speed and a car turns into your path....you hit your breaks but the motor doesn't stop propelling you towards the car? :shock:

Gunna' put anything in the breaks to cut the motor?
 
Well - you've re-invented cruise control but without the safety of ebrakes (or even nudging a throttle) to stop it. If you do have ebrakes on your controller, the processor won't know or disengage on ebrake pull so the motor will re-apply as soon as the brakes are released.

The buttons on the seat far out of reach when hands are on the bars seems very undesirable.

IMHO the design seems flawed from a safety perspective.

Why not just invest in PAS?
 
gwhy! said:
I like it ..

I think it were me I would have the button2 on the right just return to zero once pressed , and have button1 on the right stepping up a little faster unless you are using re-gen..

and only have button1 on the left needs to be pressed for the right buttons to function and when button1 on the left is released thottle output gets reset to zero.
Thanks for the suggestion, yeah it's a start and I might reprogram it once I try it outdoors.
 
e-beach said:
OK, nice start, but on the other side, what happens if your motor is in high speed and a car turns into your path....you hit your breaks but the motor doesn't stop propelling you towards the car? :shock:

Gunna' put anything in the breaks to cut the motor?

Yeah of course! For one, button 1 on the left needs to be pressed to have any motor spin. Secondly I have a brake sensor that is connected directly to the controller to shut it off in case the arduino misbehaves.
 
teklektik said:
Well - you've re-invented cruise control but without the safety of ebrakes (or even nudging a throttle) to stop it. If you do have ebrakes on your controller, the processor won't know or disengage on ebrake pull so the motor will re-apply as soon as the brakes are released.

The buttons on the seat far out of reach when hands are on the bars seems very undesirable.

IMHO the design seems flawed from a safety perspective.

Why not just invest in PAS?
Good points.
safety was a concern when designing this setup.
I have e brakes and I am planning on having them communicate with the processor - work in progress.
I also thought of adding another set of bottons on top too...maybe in the future but I mostly ride on hoods anyway which was the reason for the design in the first place.
Again there are 4 buttons and one on the left needs to be pressed to have any spin, the other left side button resets the throttle.

I'm not a big fan of PAS unless it's torque based, which is too expensive - This was a $20 alternative and a bit of fun to figure out. :)
 
yes defo tie your ebrakes into the processor....

maybe all you need is one button on each side, button on left to hold current set speed but when released reset to zero throttle... button on right when pressed increases speed but needs left button to be released before right button becomes enabled, once upto desired speed left button is pressed to maintain set speed ( right button still needs to be pressed ) if right button is released speed decreases, if left button is released speed resets to zero and right button needs to be released again before it becomes active again. and of coarse both brake tied in to the processor also to reset the throttle to zero
 
Nice! and also nice to see someone working on this niche. What if instead of mounting the buttons to the hoods, you put the buttons on the fingertips of your gloves. That way you could move your hands around and still have control. If you went really fancy and did it through Bluetooth then you wouldn't have wires running to the gloves.
 
I worked on a similar Arduino setup on my bike which used only one button and an ebrake input. Basically, the button has to be held for the motor to run. On the first press and hold, the motor is commanded to the lowest speed. To step up to the next level, the button has to be momentarily released (less than about .25 seconds) and then held. I had nine levels (not including zero speed) programmed. On releasing the button, the Arduino would command a slower ramp down in speed towards zero speed. If the button is pressed and held before it stepped down to zero, then it would hold the closest speed step. Activating the brake would reset the speed to zero immediately.

I also had a piezo buzzer connected so that when it reach the top speed level, it would make a momentary high frequency beep to indicate that I was already at the highest throttle level so that I would know there was no point pulsing the button to get to a higher level. The buzzer was programmed to emit a lower frequency beep when it reach level one during the ramp-down where the throttle would remain there for a little longer before stepping down to zero. An alternative to this minimalist approach would be to have a simple 7-segment LED display to indicate the steps from zero to nine.


Although I coded and test-wired the setup successfully, I never fully implemented it because I got lazy and just put a throttle on like everyone else.
 
worldpax said:
Nice! and also nice to see someone working on this niche. What if instead of mounting the buttons to the hoods, you put the buttons on the fingertips of your gloves. That way you could move your hands around and still have control. If you went really fancy and did it through Bluetooth then you wouldn't have wires running to the gloves.
Now that is fancy! - you're way ahead of me there :)
 
dingrels said:
I worked on a similar Arduino setup on my bike which used only one button and an ebrake input. Basically, the button has to be held for the motor to run. On the first press and hold, the motor is commanded to the lowest speed. To step up to the next level, the button has to be momentarily released (less than about .25 seconds) and then held. I had nine levels (not including zero speed) programmed. On releasing the button, the Arduino would command a slower ramp down in speed towards zero speed. If the button is pressed and held before it stepped down to zero, then it would hold the closest speed step. Activating the brake would reset the speed to zero immediately.

I also had a piezo buzzer connected so that when it reach the top speed level, it would make a momentary high frequency beep to indicate that I was already at the highest throttle level so that I would know there was no point pulsing the button to get to a higher level. The buzzer was programmed to emit a lower frequency beep when it reach level one during the ramp-down where the throttle would remain there for a little longer before stepping down to zero. An alternative to this minimalist approach would be to have a simple 7-segment LED display to indicate the steps from zero to nine.


Although I coded and test-wired the setup successfully, I never fully implemented it because I got lazy and just put a throttle on like everyone else.

Cool thanks for sharing. I guess it's a tradeoff between the number of buttons and the complexity of the program. The nice thing about Arduinos is that you can easily reprogram the whole thing and try out different configurations. I might try programming something along the lines of what you did. Also like the idea of a "powerbar".
 
gwhy! said:
yes defo tie your ebrakes into the processor....

maybe all you need is one button on each side, button on left to hold current set speed but when released reset to zero throttle... button on right when pressed increases speed but needs left button to be released before right button becomes enabled, once upto desired speed left button is pressed to maintain set speed ( right button still needs to be pressed ) if right button is released speed decreases, if left button is released speed resets to zero and right button needs to be released again before it becomes active again. and of coarse both brake tied in to the processor also to reset the throttle to zero

Yeah that could work. The only downside I see is that you need both hands on the buttons at pretty much all time, which would might make shifting tricky under power without reseting the speed. Also with my setup you could wire a single power button on the top bars to maintain speed when riding upright and adjust speed at the hood - similar to how brake/shifter combos work on road bikes. (Perhaps less desirable in heavy city traffic but useful in less busy roads).
 
Hi

I'm new to arduino and almost made Sam's version run in a modified version.
I've replaced the "power" button with a speed Sensor/reed switch on the wheel and want it to be turned ON as long as the wheel is turning.

"Reset" is connected to the brakes as a safety instead of a switch.

My problem with the speed sensor is that it is not "ON" all the time ie. the bouncer and the period depends on how fast the run is.

Have looked at this https://www.arduino.cc/en/tutorial/debounce but I can't quite figure out how to merge it into the code.

How do I solve it best?
 
I don't know coding so can't help there, but:

Put more magnets on the wheel, it will increase the duty cycle on the reed switch, turning it on more often. The closer the magnets are spaced, the more often the switch will engage.

If there is a voltage across the switch, then you can also add an RC filter from the switch to the input to help smooth out the pulses. (even just a capacitance may be enough).


However, I'd like to point out the unsafeness of having the power engaged by the action of the wheel turning which is caused by having the power engaged, because it cannot ever turn itself off. So if your reset line breaks, and it's stuck at full throttle, you're stuck on a continuously moving bike you may have to crash to stop. ;)

If instead you put the speed sensor and magnets on the pedals (chainring, really), then you will have a PAS (pedal asist sensor) that your pedalling will control on/off.
 
nielsbakra said:
Hi

I'm new to arduino and almost made Sam's version run in a modified version.
I've replaced the "power" button with a speed Sensor/reed switch on the wheel and want it to be turned ON as long as the wheel is turning.

"Reset" is connected to the brakes as a safety instead of a switch.

My problem with the speed sensor is that it is not "ON" all the time ie. the bouncer and the period depends on how fast the run is.

Have looked at this https://www.arduino.cc/en/tutorial/debounce but I can't quite figure out how to merge it into the code.

How do I solve it best?
I don't know if it will help, but I think my diagram is wrong for the low-pass filter the resistor should be on the other side of the cap.
6UtMienkSm4DBJhFnMMeIxmKVmV35jKhoS8VhgMq9uSF9nSqy8IZLmIGQAjuFfzqidcNCXOcJzOGe2cwQ_9pwnUEcptIAbKrg8vZzELG9hlgqTmBmm9ooRSZMvVsmE_sWbHlMm-o8rhXnmI20JmGu4SQEPKKQCeiRukZ4FuAs619v2wtSfIOb6uu_VjVQ-6L8MhGwb_T_atE57qY-W3CDVnm9o74wFGlaXDIXKt_sI2YEjLmWGg2hprNBRSOOnZYZLn4P8sA8PcjGw_bwt0kovB-6aqgPiLu9lLiO6JZc7qos49bhvDEBNKlS46kNAXaupo8y52i40mJ6K5bE5s0b2Fidr5CxDEnHcjuCQtgVPONjJvzvUicirvbOJTniW8f7MkYruCMe6grbbZ-oQ8UHoW7L7qWmFyN36Oeq5sdKp8dz1lzXp7HTu8BSGo3LXkQ-r1N8jNpuy6ooPYllFrXGs-UtaNmKZ606aqcE03hbsotxNFBA8HJtZ7R1ANN6aoLjEz21kvCZ74AvIYY68L1JDfWFFVkixxTp687exBpy0d2EsAz3HfPpMXhFdERS0X-vzTAqiPa50cFmjk8BfNN2bYu-4uEkSNUEaw5fQEIJrmB9FVL1JivdSUGtrO1kO8vFrpyPA8aMMpkHQUPLk2j7tQC0e1pBqdXrfFQ5nxul0hMVGHiXnedCGpIgyzdp5zzqbztBoaxFypuZ8EKKu4AqqbusQ=w1001-h675-no
 
SamRich said:
I couldn't find a good solution for speed modulation with dropbars. I tried installing a throttle but it won't fit on the bars and even if it did the ergonomics wouldn't be great.
There was a good discussion here: http://endless-sphere.com/forums/viewtopic.php?f=3&t=25334

I have some experience using Arduinos so I bought a Nano version and programmed it to control the speed of the motor. The throttle input to most BLDC controllers is a continuous value between 0 and 5V (usually more like 1V-3.5V) - proportional to the desired speed. The Arduino can be used to output a 5V PWM signal and low pass filtered using an RC filter to generate a DC signal.
20140308_171109.jpg

Here's the wiring diagram:
Presentation1.jpg

CORRECTION:
6UtMienkSm4DBJhFnMMeIxmKVmV35jKhoS8VhgMq9uSF9nSqy8IZLmIGQAjuFfzqidcNCXOcJzOGe2cwQ_9pwnUEcptIAbKrg8vZzELG9hlgqTmBmm9ooRSZMvVsmE_sWbHlMm-o8rhXnmI20JmGu4SQEPKKQCeiRukZ4FuAs619v2wtSfIOb6uu_VjVQ-6L8MhGwb_T_atE57qY-W3CDVnm9o74wFGlaXDIXKt_sI2YEjLmWGg2hprNBRSOOnZYZLn4P8sA8PcjGw_bwt0kovB-6aqgPiLu9lLiO6JZc7qos49bhvDEBNKlS46kNAXaupo8y52i40mJ6K5bE5s0b2Fidr5CxDEnHcjuCQtgVPONjJvzvUicirvbOJTniW8f7MkYruCMe6grbbZ-oQ8UHoW7L7qWmFyN36Oeq5sdKp8dz1lzXp7HTu8BSGo3LXkQ-r1N8jNpuy6ooPYllFrXGs-UtaNmKZ606aqcE03hbsotxNFBA8HJtZ7R1ANN6aoLjEz21kvCZ74AvIYY68L1JDfWFFVkixxTp687exBpy0d2EsAz3HfPpMXhFdERS0X-vzTAqiPa50cFmjk8BfNN2bYu-4uEkSNUEaw5fQEIJrmB9FVL1JivdSUGtrO1kO8vFrpyPA8aMMpkHQUPLk2j7tQC0e1pBqdXrfFQ5nxul0hMVGHiXnedCGpIgyzdp5zzqbztBoaxFypuZ8EKKu4AqqbusQ=w1001-h675-no

Here are the buttons on the right side held temporarily with tape:
20140308_171809.jpg

I used phone wire which is thin and flat. Should be able to easily tuck it under the griptape.
Here are the 4 button functions:
Left hand
Button 1 - Power: Needs to be pressed to have the motor run. I thought it would be a good safety feature.
Button 2 - Reset: Stops everything and resets the speed to 0 since toggling the power button only turns the motor on and off at what ever speed is set with the right hand. This should be useful to accelerate from a stop slowly.

Right hand
Button 1 UP: Increases the speed one step. If held pressed the speed is increased every 250ms.
Button 2 Down: Decreases the speed one step. If held pressed the speed is increased every 250ms.
10 steps total.

Here it is in action (in the workshop):
[youtube]uIlfj8H-W_8[/youtube]

Here's the code for the arduino:
Code:
String inputString;
String Temp;
char buffer[100];
char type;

const char SET_INPUT  = 'I';
const char SET_DOWN  = 'D';
const char SET_UP  = 'U';

int voltage;
int pinT=3;

int DOWN=0;
int UP=50;
int STEP=10;
int MINVAL=70;
int MAXVAL=170;

int power=0;
int reset=0;
int DOWNCOM=0;
int UPCOM=0;
void setup() {

  Serial.begin(9600);
  analogWrite(pinT, 0);
  pinMode(6, OUTPUT);//RESET/power
  digitalWrite(A0, HIGH);
   digitalWrite(A1, HIGH); 
  digitalWrite(A2, HIGH); 
  digitalWrite(A3, HIGH); 
  inputString.reserve(100);
}
//A0 Right Green - UP
//A1 Left Green - Power
//A2 Right Yellow - Down
//A3 Left Yellow - Reset

void loop() {
  processSerial();
  power=analogRead(A1);
  reset=analogRead(A3);
  DOWNCOM=analogRead(A2);
  UPCOM=analogRead(A0);
  if(power<128&reset>128){
    if ((UP-DOWN)<MINVAL){
      UP=MINVAL;
      DOWN=0;
    }
    if ((UP-DOWN)>MAXVAL){
      UP=MAXVAL;
      DOWN=0;
    }
    voltage=max(UP-DOWN,MINVAL);
    analogWrite(pinT,voltage);
    if(UPCOM<128){
      UP=UP+STEP;
      if ((UP-DOWN)<MINVAL){
        UP=MINVAL;
        DOWN=0;
      }
      if ((UP-DOWN)>MAXVAL){
        UP=MAXVAL;
        DOWN=0;
      }
      voltage=max(UP-DOWN,MINVAL);
      analogWrite(pinT,voltage);
      delay(250);
    }
    if(DOWNCOM<128){
      DOWN=DOWN+STEP;
      if ((UP-DOWN)<MINVAL){
        UP=MINVAL;
        DOWN=0;
      }
      if ((UP-DOWN)>MAXVAL){
        UP=MAXVAL;
        DOWN=0;
      }
      voltage=max(UP-DOWN,MINVAL);
      analogWrite(pinT,voltage);
      delay(250);
    }
    //Serial.println(voltage); 
  }
  else if(reset<128){
    analogWrite(pinT,0);
    UP=MINVAL;
    DOWN=0;
  }
  else{
    analogWrite(pinT,0);
  }
}



void processSerial(){     
  if ( Serial.available()>0){
    char inChar = (char)Serial.read(); 
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag
    // so the main loop can do something about it:
    if (inChar == '\n') {
      //Serial.println(inputString);  

      if(inputString.charAt(0)==SET_INPUT){

        Temp=inputString.substring(1,2);  
        Temp.toCharArray(buffer, 10);
        power=atoi(buffer);//compensate for system response
        Serial.println(power); 

      }

      if(inputString.charAt(0)==SET_DOWN){

        Temp=inputString.substring(1,1);  
        Temp.toCharArray(buffer, 10);
        DOWN=DOWN+STEP;


      }

      if(inputString.charAt(0)==SET_UP){

        Temp=inputString.substring(1,1);  
        Temp.toCharArray(buffer, 10);
        UP=UP+STEP;

      }

      inputString="";//Clear inputstring

    }
  }
}
 
Hi

I found this thread where he solved the problem with adding a PAS sensor https://www.pedelecs.co.uk/forum/threads/how-to-add-a-throttle-to-a-carrera-vengeance-e-spec.31483/
Installed the PAS Sensor on the bike but could need a little help merging his PAS sensor code with Sam's code.
This is the only thing missing to finish the bike.

Both codes runs fine on the arduino.

I have added a few pictures of my setup including my wiring diagram.
Motor is to be installed in the seat tube :)

Hope someone have the time to help with the code as I can't figure out how to merge them (missing C coding skills).
 

Attachments

  • Arduino Nano1.jpg
    Arduino Nano1.jpg
    40.7 KB · Views: 1,325
  • MotorSetup.jpg
    MotorSetup.jpg
    402.1 KB · Views: 1,325
  • PAS Sensor.jpg
    PAS Sensor.jpg
    171.9 KB · Views: 1,325
Back
Top