DIY Derailleur e-Shifter with Arduino Nano... need help with programming...

papagino

10 mW
Joined
May 29, 2018
Messages
30
Hey Guys, I am currently upgrading my Enduro Ebike frame from a hub motor to a Bafang BBSHD Mid Drive with ASI BAC800 external controller from ERT. The drive components are a 42T Luna Eclipse Front ChainRing with a 9 Speeds Shimano Deore RD-M6000GS rear derailleur driving a 11-46T cassette. I am proficient in Mechanical Engineering, have a 3D printer and can design very complex things, but I'm not too good with coding, as Arduino is all new to me... I would need help with Arduino coding for my DIY e-Shifter. The code below is working flawlessly for shifting as you can see in the video, but I need to add to my current code something that will allow me to downshift to gear one (Lowest gear) when I hold the shifter "down button" for 2 seconds or more.

Here is my current Arduino Sketch code:

Code:
// Electromechanical derailleur project v.1.0
// Assumes you know the servo positions for each gear (determined using v.0.0 software)

#include <Servo.h> 
#include <EEPROM.h>            //Need this because we'll be saving the gear selection in EEPROM (to avoid shifts on startup)

#define db_time 20             //Button debounce time in mS
#define servo_pin 9            //HW pin to which servo signal line is attached
#define servoDelta 1           //Amt servo moves with each button push (degress)
#define upButtonPin 2          //Up button push grounds it
#define dnButtonPin 3          //Dn button push grounds it
#define led_pin 10             //LED Turn ON when button is pressed
#define highestGear 9          //Number of sprockets on rear hub

#define rearGear1 180           //Servo position values for the various rear sprockets (numbered low to high gears, not by size)
#define rearGear2 162          //These were determined empirically using the diyshift0 sketch while hooked up to a laptop
#define rearGear3 144
#define rearGear4 126
#define rearGear5 108
#define rearGear6 90
#define rearGear7 72
#define rearGear8 54
#define rearGear9 36

#define rearGearAddr 0            //EEPROM address for saving the gear selected

Servo rearServo;                  // Create servo object to control a servo 
int   lastUpButtonState = 1;
int   lastDnButtonState = 1;
int   rearPos = 90;               // variable to store the servo position
int   rearGear;                   //Numbered sprocket (1 is lowest gear; 9 is highest)
 
void setup() 
{ 
  rearGear = EEPROM.read(rearGearAddr);
  rearServo.attach(servo_pin);                          //Attach the rear servo to the servo object
  
  if ((rearGear > 0) && (rearGear < 10))
  {
    shiftToRearGear(rearGear);                          //And immediately set it to whatever gear was last saved in EEPROM
  }
  else
  {
    shiftToRearGear(3);                                 //If not valid, goto gear 3
  }
  
  pinMode(upButtonPin, INPUT);
  pinMode(dnButtonPin, INPUT);
  pinMode(led_pin, OUTPUT);
   
  digitalWrite(upButtonPin, HIGH);                      //Enable internal pullup resistors
  digitalWrite(dnButtonPin, HIGH);
  digitalWrite(led_pin, LOW);

  Serial.begin(9600);    //USED ONLY FOR DEBUG
} 
 
 
void loop() 
{ 
  int upButtonState = digitalRead(upButtonPin);          //Poll the up/dn buttons
  int dnButtonState = digitalRead(dnButtonPin);
  int count;                                             //variables to count the time button is held

  if (upButtonState == 0){                               //Button was pushed
    delay(db_time);                                      //Wait a bit to debounce the button
    upButtonState = digitalRead(upButtonPin);            //Test again
    if (upButtonState == 0 && lastUpButtonState == 1){   //If still down AND was up before
      upOneGear();                                       //Shift up one gear
      lastUpButtonState = 0;                             //Save state
      digitalWrite(led_pin, HIGH);                       // Turn On LED when button is pressed
    }
  }
  else {                                                  //upButton must be open (button state = 1)
    delay (db_time);                                      //Wait a bit to debounce the button
    upButtonState = digitalRead(upButtonPin);             //Test again
    if (upButtonState == 1){                              //Still open, save state
      lastUpButtonState = 1;
      digitalWrite(led_pin, LOW);
    }
  }
  //
  //Now same for dowm
  //
  if (dnButtonState == 0){                               //Button was pushed
    delay(db_time);                                      //Wait a bit to debounce the button
    dnButtonState = digitalRead(dnButtonPin);            //Test again
    if (dnButtonState == 0 && lastDnButtonState == 1){   //If still down AND was up before
      dnOneGear();                                       //Shift down one gear
      lastDnButtonState = 0;                             //Save state
      digitalWrite(led_pin, HIGH);                       // Turn On LED when button is pressed
    }
  }
  else {                                                  //dnButton must be open (button state = 1)
    delay (db_time);                                      //Wait a bit to debounce the button
    dnButtonState = digitalRead(dnButtonPin);             //Test again
    if (dnButtonState == 1){                              //Still open, save stated
      lastDnButtonState = 1;
      digitalWrite(led_pin, LOW);
    }
  }
}
//
//Functions called
//
  void upOneGear(){
    if (rearGear < highestGear){
      rearGear = rearGear + 1;
    }
    shiftToRearGear(rearGear);
  }
  
    void dnOneGear(){
    if (rearGear > 1){
      rearGear = rearGear - 1;
    }
    shiftToRearGear(rearGear);
  }
  
  void shiftToRearGear(int gear){
      EEPROM.write(rearGearAddr, gear);
      switch (gear) {
    case 1:
      rearServo.write(rearGear1);
      break;
    case 2:
      rearServo.write(rearGear2);
      break;
    case 3:
      rearServo.write(rearGear3);
      break;
    case 4:
      rearServo.write(rearGear4);
      break;
    case 5:
      rearServo.write(rearGear5);
      break;
    case 6:
      rearServo.write(rearGear6);
      break;
    case 7:
      rearServo.write(rearGear7);
      break;
    case 8:
      rearServo.write(rearGear8);
      break;
    case 9:
      rearServo.write(rearGear9);
      break;
    }
  }

Here is a video of e-Shifter working and also second video of the Bafang BBSHD spinning at 11000+RPM using ASI BAC800 external controller Field Weakening Technology.

[youtube]pbAWU7V_r1Y[/youtube]
[youtube]93wpKgX8quw[/youtube]

The controller and e-Shifter are inside the enduro ebike frame battery compartment and there are no wires exposed once the battery compartment side covers are installed. Very clean build as you will see in a couple weeks...
I will post videos and Pics when I am done with this build...

Can anyone help me with the Arduino coding to add the function that will allow me to downshift to gear one when I hold the down button for more than 2 seconds so I don't need to hit the button 8 times everytime I come to a stop.

Cheers.
:bigthumb:
Dan
 
I don't know coding, but have you looked at the thread for the eshifter over here?
https://endless-sphere.com/forums/viewtopic.php?f=30&t=102236
or here?
https://endless-sphere.com/forums/viewtopic.php?f=2&t=102122
Maybe they might have some pointers?


Alternately, have you thought about adding a speed sensor, so that when it drops down to a certain speed it automatically shifts down to compensate for that? If so, you could have it autoshift down to lowest gear whenever speed is zero, regardless of any other conditions.
 
amberwolf said:
I don't know coding, but have you looked at the thread for the eshifter over here?
https://endless-sphere.com/forums/viewtopic.php?f=30&t=102236
or here?
https://endless-sphere.com/forums/viewtopic.php?f=2&t=102122
Maybe they might have some pointers?


Alternately, have you thought about adding a speed sensor, so that when it drops down to a certain speed it automatically shifts down to compensate for that? If so, you could have it autoshift down to lowest gear whenever speed is zero, regardless of any other conditions.

Thanks amberwolf for your feedback, actually I did thought of using the existing Bafang speed sensor for this purpose, I ordered a Bafang main harness extension from Luna Cycle so I can have access to all signal without cutting original bafang harness. I am also planning in adding a cruise control to the bike. I know all this is possible using the Arduino, just need help with coding... I will look at the links you provided. Thank you.
 
I have just made modifications to your code, try this :

Code:
// Electromechanical derailleur project v.1.0
// Assumes you know the servo positions for each gear (determined using v.0.0 software)

#include <Servo.h> 
#include <EEPROM.h>            //Need this because we'll be saving the gear selection in EEPROM (to avoid shifts on startup)

#define db_time 20             //Button debounce time in mS
#define servo_pin 9            //HW pin to which servo signal line is attached
#define servoDelta 1           //Amt servo moves with each button push (degress)
#define upButtonPin 2          //Up button push grounds it
#define dnButtonPin 3          //Dn button push grounds it
#define led_pin 10             //LED Turn ON when button is pressed
#define highestGear 9          //Number of sprockets on rear hub
#define threshold 2000		   // Long press button time threshold in mS

#define rearGear1 180           //Servo position values for the various rear sprockets (numbered low to high gears, not by size)
#define rearGear2 162          //These were determined empirically using the diyshift0 sketch while hooked up to a laptop
#define rearGear3 144
#define rearGear4 126
#define rearGear5 108
#define rearGear6 90
#define rearGear7 72
#define rearGear8 54
#define rearGear9 36

#define rearGearAddr 0            //EEPROM address for saving the gear selected

Servo rearServo;                  // Create servo object to control a servo 
int   lastUpButtonState = 1;
int   lastDnButtonState = 1;
int   rearPos = 90;               // variable to store the servo position
int   rearGear;                   //Numbered sprocket (1 is lowest gear; 9 is highest)
 
void setup() 
{ 
  rearGear = EEPROM.read(rearGearAddr);
  rearServo.attach(servo_pin);                          //Attach the rear servo to the servo object
  
  if ((rearGear > 0) && (rearGear < 10))
  {
    shiftToRearGear(rearGear);                          //And immediately set it to whatever gear was last saved in EEPROM
  }
  else
  {
    shiftToRearGear(3);                                 //If not valid, goto gear 3
  }
  
  pinMode(upButtonPin, INPUT);
  pinMode(dnButtonPin, INPUT);
  pinMode(led_pin, OUTPUT);
   
  digitalWrite(upButtonPin, HIGH);                      //Enable internal pullup resistors
  digitalWrite(dnButtonPin, HIGH);
  digitalWrite(led_pin, LOW);

  Serial.begin(9600);    //USED ONLY FOR DEBUG
} 
 
 
void loop() 
{ 
  int upButtonState = digitalRead(upButtonPin);          //Poll the up/dn buttons
  int dnButtonState = digitalRead(dnButtonPin);
  int count;                                             //variables to count the time button is held

  if (upButtonState == 0){                               //Button was pushed
    delay(db_time);                                      //Wait a bit to debounce the button
    upButtonState = digitalRead(upButtonPin);            //Test again
    if (upButtonState == 0 && lastUpButtonState == 1){   //If still down AND was up before
      upOneGear();                                       //Shift up one gear
      lastUpButtonState = 0;                             //Save state
      digitalWrite(led_pin, HIGH);                       // Turn On LED when button is pressed
    }
  }
  else {                                                  //upButton must be open (button state = 1)
    delay (db_time);                                      //Wait a bit to debounce the button
    upButtonState = digitalRead(upButtonPin);             //Test again
    if (upButtonState == 1){                              //Still open, save state
      lastUpButtonState = 1;
      digitalWrite(led_pin, LOW);
    }
  }
  //
  //Now same for dowm
  //
  if (dnButtonState == 0){                               //Button was pushed
    delay(db_time);                                      //Wait a bit to debounce the button
    dnButtonState = digitalRead(dnButtonPin);            //Test again
	
    if (dnButtonState == 0 && lastDnButtonState == 1){   //If still down AND was up before
      dnOneGear();                                       //Shift down one gear
      lastDnButtonState = 0;                             //Save state
      digitalWrite(led_pin, HIGH);                       // Turn On LED when button is pressed
    }
	else if(dnButtonState == 0 && lastDnButtonState == 0)
	{
	  unsigned long last_time=millis();	
	  
	  do
		{
		 dnButtonState = digitalRead(dnButtonPin);
		 if(dnButtonState == 1)
			{
			 break;
			}
		 else if((millis()-last_time)>threshold)	
			{
			 dnRearGear1();
			}
		 
		}
	 while(1);	
	  
	
	}
  }
  else {                                                  //dnButton must be open (button state = 1)
    delay (db_time);                                      //Wait a bit to debounce the button
    dnButtonState = digitalRead(dnButtonPin);             //Test again
    if (dnButtonState == 1){                              //Still open, save stated
      lastDnButtonState = 1;
      digitalWrite(led_pin, LOW);
    }
  }
  

  
  
}
//
//Functions called
//
  void upOneGear(){
    if (rearGear < highestGear){
      rearGear = rearGear + 1;
    }
    shiftToRearGear(rearGear);
  }
  
    void dnOneGear(){
    if (rearGear > 1){
      rearGear = rearGear - 1;
    }
    shiftToRearGear(rearGear);
  }
  
  void dnRearGear1(){
    if (rearGear > 1){
      rearGear = 1;
    }
    shiftToRearGear(rearGear);
  }
  
  void shiftToRearGear(int gear){
      EEPROM.write(rearGearAddr, gear);
      switch (gear) {
    case 1:
      rearServo.write(rearGear1);
      break;
    case 2:
      rearServo.write(rearGear2);
      break;
    case 3:
      rearServo.write(rearGear3);
      break;
    case 4:
      rearServo.write(rearGear4);
      break;
    case 5:
      rearServo.write(rearGear5);
      break;
    case 6:
      rearServo.write(rearGear6);
      break;
    case 7:
      rearServo.write(rearGear7);
      break;
    case 8:
      rearServo.write(rearGear8);
      break;
    case 9:
      rearServo.write(rearGear9);
      break;
    }
  }

Your project is a good idea, I'm particularly interested in hardware details
 
NexusG said:
I have just made modifications to your code, try this :

Code:
// Electromechanical derailleur project v.1.0
// Assumes you know the servo positions for each gear (determined using v.0.0 software)

#include <Servo.h> 
#include <EEPROM.h>            //Need this because we'll be saving the gear selection in EEPROM (to avoid shifts on startup)

#define db_time 20             //Button debounce time in mS
#define servo_pin 9            //HW pin to which servo signal line is attached
#define servoDelta 1           //Amt servo moves with each button push (degress)
#define upButtonPin 2          //Up button push grounds it
#define dnButtonPin 3          //Dn button push grounds it
#define led_pin 10             //LED Turn ON when button is pressed
#define highestGear 9          //Number of sprockets on rear hub
#define threshold 2000		   // Long press button time threshold in mS

#define rearGear1 180           //Servo position values for the various rear sprockets (numbered low to high gears, not by size)
#define rearGear2 162          //These were determined empirically using the diyshift0 sketch while hooked up to a laptop
#define rearGear3 144
#define rearGear4 126
#define rearGear5 108
#define rearGear6 90
#define rearGear7 72
#define rearGear8 54
#define rearGear9 36

#define rearGearAddr 0            //EEPROM address for saving the gear selected

Servo rearServo;                  // Create servo object to control a servo 
int   lastUpButtonState = 1;
int   lastDnButtonState = 1;
int   rearPos = 90;               // variable to store the servo position
int   rearGear;                   //Numbered sprocket (1 is lowest gear; 9 is highest)
 
void setup() 
{ 
  rearGear = EEPROM.read(rearGearAddr);
  rearServo.attach(servo_pin);                          //Attach the rear servo to the servo object
  
  if ((rearGear > 0) && (rearGear < 10))
  {
    shiftToRearGear(rearGear);                          //And immediately set it to whatever gear was last saved in EEPROM
  }
  else
  {
    shiftToRearGear(3);                                 //If not valid, goto gear 3
  }
  
  pinMode(upButtonPin, INPUT);
  pinMode(dnButtonPin, INPUT);
  pinMode(led_pin, OUTPUT);
   
  digitalWrite(upButtonPin, HIGH);                      //Enable internal pullup resistors
  digitalWrite(dnButtonPin, HIGH);
  digitalWrite(led_pin, LOW);

  Serial.begin(9600);    //USED ONLY FOR DEBUG
} 
 
 
void loop() 
{ 
  int upButtonState = digitalRead(upButtonPin);          //Poll the up/dn buttons
  int dnButtonState = digitalRead(dnButtonPin);
  int count;                                             //variables to count the time button is held

  if (upButtonState == 0){                               //Button was pushed
    delay(db_time);                                      //Wait a bit to debounce the button
    upButtonState = digitalRead(upButtonPin);            //Test again
    if (upButtonState == 0 && lastUpButtonState == 1){   //If still down AND was up before
      upOneGear();                                       //Shift up one gear
      lastUpButtonState = 0;                             //Save state
      digitalWrite(led_pin, HIGH);                       // Turn On LED when button is pressed
    }
  }
  else {                                                  //upButton must be open (button state = 1)
    delay (db_time);                                      //Wait a bit to debounce the button
    upButtonState = digitalRead(upButtonPin);             //Test again
    if (upButtonState == 1){                              //Still open, save state
      lastUpButtonState = 1;
      digitalWrite(led_pin, LOW);
    }
  }
  //
  //Now same for dowm
  //
  if (dnButtonState == 0){                               //Button was pushed
    delay(db_time);                                      //Wait a bit to debounce the button
    dnButtonState = digitalRead(dnButtonPin);            //Test again
	
    if (dnButtonState == 0 && lastDnButtonState == 1){   //If still down AND was up before
      dnOneGear();                                       //Shift down one gear
      lastDnButtonState = 0;                             //Save state
      digitalWrite(led_pin, HIGH);                       // Turn On LED when button is pressed
    }
	else if(dnButtonState == 0 && lastDnButtonState == 0)
	{
	  unsigned long last_time=millis();	
	  
	  do
		{
		 dnButtonState = digitalRead(dnButtonPin);
		 if(dnButtonState == 1)
			{
			 break;
			}
		 else if((millis()-last_time)>threshold)	
			{
			 dnRearGear1();
			}
		 
		}
	 while(1);	
	  
	
	}
  }
  else {                                                  //dnButton must be open (button state = 1)
    delay (db_time);                                      //Wait a bit to debounce the button
    dnButtonState = digitalRead(dnButtonPin);             //Test again
    if (dnButtonState == 1){                              //Still open, save stated
      lastDnButtonState = 1;
      digitalWrite(led_pin, LOW);
    }
  }
  

  
  
}
//
//Functions called
//
  void upOneGear(){
    if (rearGear < highestGear){
      rearGear = rearGear + 1;
    }
    shiftToRearGear(rearGear);
  }
  
    void dnOneGear(){
    if (rearGear > 1){
      rearGear = rearGear - 1;
    }
    shiftToRearGear(rearGear);
  }
  
  void dnRearGear1(){
    if (rearGear > 1){
      rearGear = 1;
    }
    shiftToRearGear(rearGear);
  }
  
  void shiftToRearGear(int gear){
      EEPROM.write(rearGearAddr, gear);
      switch (gear) {
    case 1:
      rearServo.write(rearGear1);
      break;
    case 2:
      rearServo.write(rearGear2);
      break;
    case 3:
      rearServo.write(rearGear3);
      break;
    case 4:
      rearServo.write(rearGear4);
      break;
    case 5:
      rearServo.write(rearGear5);
      break;
    case 6:
      rearServo.write(rearGear6);
      break;
    case 7:
      rearServo.write(rearGear7);
      break;
    case 8:
      rearServo.write(rearGear8);
      break;
    case 9:
      rearServo.write(rearGear9);
      break;
    }
  }

Your project is a good idea, I'm particularly interested in hardware details

You, my friend, are a genius...
YES, this is working wonderfully.
(I wish I knew how to code with Arduino, so much thing I could do with this... Auto downshift when speed decrease, cruise control...)

I can share my design, but you would need to have access to a 3D Printer.
Most components available on Amazon.ca and cost about $95CAD to build.
Here is the shopping list for the components I've used.
https://www.amazon.ca/hz/wishlist/ls/22TI3XEMGTHJN?ref_=wl_share

Also, the Handlebar switches used for the shifter had to be modified, the slide switch was removed and 2 tact switches was installed instead. See 3D Printed Tact Switch Holder below..
Handlebar Switches.png
These can also be found on Amazon and are on the shopping list above.


The servo used is a 270deg servo, it can rotate 360deg without modification. You have to de-solder the 5K ohm Potentiometer inside the Servo and use an external slide Potentiometer on the 3D Printed Shifter Housing to detect servo positioning. It is a 5K linear slide Potentiometer with 60mm travel available at Mouser here:
https://www.mouser.ca/ProductDetail...%2bPT0NYs/w==&countrycode=CA&currencycode=CAD
(It is rated at 15000 Cycles, so, it should last a long time).

Here is a sketch for the Tact Switch Holder located inside the Handlebar Shifter Switches:
Tact Switch Housing.png

Here is a sketch for the e-Shifter Housing:
e-Shifter Housing.png

I wouldn't mind sharing all 3D Printed Parts on Thingiverse if this interest anyone but it was design specially for the EM3EV Enduro eBike frame so it fits under the Battery inside the Battery compartment and would require modification for any other mounting location on your particular bike...

Anyway, thanks a lots for your help.

Cheers
:bigthumb:
Dan
 
NexusG said:
I have just made modifications to your code, try this :

Code:
// Electromechanical derailleur project v.1.0
// Assumes you know the servo positions for each gear (determined using v.0.0 software)

#include <Servo.h> 
#include <EEPROM.h>            //Need this because we'll be saving the gear selection in EEPROM (to avoid shifts on startup)

#define db_time 20             //Button debounce time in mS
#define servo_pin 9            //HW pin to which servo signal line is attached
#define servoDelta 1           //Amt servo moves with each button push (degress)
#define upButtonPin 2          //Up button push grounds it
#define dnButtonPin 3          //Dn button push grounds it
#define led_pin 10             //LED Turn ON when button is pressed
#define highestGear 9          //Number of sprockets on rear hub
#define threshold 2000		   // Long press button time threshold in mS

#define rearGear1 180           //Servo position values for the various rear sprockets (numbered low to high gears, not by size)
#define rearGear2 162          //These were determined empirically using the diyshift0 sketch while hooked up to a laptop
#define rearGear3 144
#define rearGear4 126
#define rearGear5 108
#define rearGear6 90
#define rearGear7 72
#define rearGear8 54
#define rearGear9 36

#define rearGearAddr 0            //EEPROM address for saving the gear selected

Servo rearServo;                  // Create servo object to control a servo 
int   lastUpButtonState = 1;
int   lastDnButtonState = 1;
int   rearPos = 90;               // variable to store the servo position
int   rearGear;                   //Numbered sprocket (1 is lowest gear; 9 is highest)
 
void setup() 
{ 
  rearGear = EEPROM.read(rearGearAddr);
  rearServo.attach(servo_pin);                          //Attach the rear servo to the servo object
  
  if ((rearGear > 0) && (rearGear < 10))
  {
    shiftToRearGear(rearGear);                          //And immediately set it to whatever gear was last saved in EEPROM
  }
  else
  {
    shiftToRearGear(3);                                 //If not valid, goto gear 3
  }
  
  pinMode(upButtonPin, INPUT);
  pinMode(dnButtonPin, INPUT);
  pinMode(led_pin, OUTPUT);
   
  digitalWrite(upButtonPin, HIGH);                      //Enable internal pullup resistors
  digitalWrite(dnButtonPin, HIGH);
  digitalWrite(led_pin, LOW);

  Serial.begin(9600);    //USED ONLY FOR DEBUG
} 
 
 
void loop() 
{ 
  int upButtonState = digitalRead(upButtonPin);          //Poll the up/dn buttons
  int dnButtonState = digitalRead(dnButtonPin);
  int count;                                             //variables to count the time button is held

  if (upButtonState == 0){                               //Button was pushed
    delay(db_time);                                      //Wait a bit to debounce the button
    upButtonState = digitalRead(upButtonPin);            //Test again
    if (upButtonState == 0 && lastUpButtonState == 1){   //If still down AND was up before
      upOneGear();                                       //Shift up one gear
      lastUpButtonState = 0;                             //Save state
      digitalWrite(led_pin, HIGH);                       // Turn On LED when button is pressed
    }
  }
  else {                                                  //upButton must be open (button state = 1)
    delay (db_time);                                      //Wait a bit to debounce the button
    upButtonState = digitalRead(upButtonPin);             //Test again
    if (upButtonState == 1){                              //Still open, save state
      lastUpButtonState = 1;
      digitalWrite(led_pin, LOW);
    }
  }
  //
  //Now same for dowm
  //
  if (dnButtonState == 0){                               //Button was pushed
    delay(db_time);                                      //Wait a bit to debounce the button
    dnButtonState = digitalRead(dnButtonPin);            //Test again
	
    if (dnButtonState == 0 && lastDnButtonState == 1){   //If still down AND was up before
      dnOneGear();                                       //Shift down one gear
      lastDnButtonState = 0;                             //Save state
      digitalWrite(led_pin, HIGH);                       // Turn On LED when button is pressed
    }
	else if(dnButtonState == 0 && lastDnButtonState == 0)
	{
	  unsigned long last_time=millis();	
	  
	  do
		{
		 dnButtonState = digitalRead(dnButtonPin);
		 if(dnButtonState == 1)
			{
			 break;
			}
		 else if((millis()-last_time)>threshold)	
			{
			 dnRearGear1();
			}
		 
		}
	 while(1);	
	  
	
	}
  }
  else {                                                  //dnButton must be open (button state = 1)
    delay (db_time);                                      //Wait a bit to debounce the button
    dnButtonState = digitalRead(dnButtonPin);             //Test again
    if (dnButtonState == 1){                              //Still open, save stated
      lastDnButtonState = 1;
      digitalWrite(led_pin, LOW);
    }
  }
  

  
  
}
//
//Functions called
//
  void upOneGear(){
    if (rearGear < highestGear){
      rearGear = rearGear + 1;
    }
    shiftToRearGear(rearGear);
  }
  
    void dnOneGear(){
    if (rearGear > 1){
      rearGear = rearGear - 1;
    }
    shiftToRearGear(rearGear);
  }
  
  void dnRearGear1(){
    if (rearGear > 1){
      rearGear = 1;
    }
    shiftToRearGear(rearGear);
  }
  
  void shiftToRearGear(int gear){
      EEPROM.write(rearGearAddr, gear);
      switch (gear) {
    case 1:
      rearServo.write(rearGear1);
      break;
    case 2:
      rearServo.write(rearGear2);
      break;
    case 3:
      rearServo.write(rearGear3);
      break;
    case 4:
      rearServo.write(rearGear4);
      break;
    case 5:
      rearServo.write(rearGear5);
      break;
    case 6:
      rearServo.write(rearGear6);
      break;
    case 7:
      rearServo.write(rearGear7);
      break;
    case 8:
      rearServo.write(rearGear8);
      break;
    case 9:
      rearServo.write(rearGear9);
      break;
    }
  }

Your project is a good idea, I'm particularly interested in hardware details

Hello again NexusG, I would like to add a 7 Segment LED Display to my eBike to show me the gear that I am currently on.
View attachment 1

I am trying to figure out the Arduino Code to be able to accomplish this using the SevSeg.h Library using the tutorial here:
http://www.circuitbasics.com/arduino-7-segment-display-tutorial/

Do you think the following code would work:

Code:
// Electromechanical derailleur project v.1.0
// Assumes you know the servo positions for each gear (determined using v.0.0 software)

#include <Servo.h> 
#include <EEPROM.h>            //Need this because we'll be saving the gear selection in EEPROM (to avoid shifts on startup)
#include <SevSeg.h>            //This is used for the 7 Segment LED Display to show what gear the bike is
SevSeg sevseg;


#define db_time 20             //Button debounce time in mS
#define servo_pin 9            //HW pin to which servo signal line is attached
#define servoDelta 1           //Amt servo moves with each button push (degress)
#define upButtonPin 2          //Up button push grounds it
#define dnButtonPin 3          //Dn button push grounds it
#define led_pin 10             //LED Turn ON when button is pressed
#define highestGear 9          //Number of sprockets on rear hub
#define threshold 1000       // Long press button time threshold in mS

#define rearGear1 176           //Servo position values for the various rear sprockets (numbered low to high gears, not by size)
#define rearGear2 154          //These were determined empirically using the diyshift0 sketch while hooked up to a laptop
#define rearGear3 136
#define rearGear4 118
#define rearGear5 100
#define rearGear6 84
#define rearGear7 64
#define rearGear8 48
#define rearGear9 28

#define rearGearAddr 0            //EEPROM address for saving the gear selected

Servo rearServo;                  // Create servo object to control a servo 
int   lastUpButtonState = 1;
int   lastDnButtonState = 1;
int   rearPos = 90;               // variable to store the servo position
int   rearGear;                   //Numbered sprocket (1 is lowest gear; 9 is highest)
 
void setup() 
{ 
  rearGear = EEPROM.read(rearGearAddr);
  rearServo.attach(servo_pin);                          //Attach the rear servo to the servo object
  
  if ((rearGear > 0) && (rearGear < 10))
  {
    shiftToRearGear(rearGear);                          //And immediately set it to whatever gear was last saved in EEPROM
  }
  else
  {
    shiftToRearGear(3);                                 //If not valid, goto gear 3
  }

    byte numDigits = 1;
    byte digitPins[] = {};
    byte segmentPins[] = {6, 5, 4, 7, 8, 11, 12, 13};
    bool resistorsOnSegments = true;

    byte hardwareConfig = COMMON_ANODE; 
    sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments);
    sevseg.setBrightness(90);
  
  pinMode(upButtonPin, INPUT);
  pinMode(dnButtonPin, INPUT);
  pinMode(led_pin, OUTPUT);
   
  digitalWrite(upButtonPin, HIGH);                      //Enable internal pullup resistors
  digitalWrite(dnButtonPin, HIGH);
  digitalWrite(led_pin, LOW);

  Serial.begin(9600);    //USED ONLY FOR DEBUG
} 


 
 
void loop() 
{ 
  int upButtonState = digitalRead(upButtonPin);          //Poll the up/dn buttons
  int dnButtonState = digitalRead(dnButtonPin);
  int count;                                             //variables to count the time button is held

  if (upButtonState == 0){                               //Button was pushed
    delay(db_time);                                      //Wait a bit to debounce the button
    upButtonState = digitalRead(upButtonPin);            //Test again
    if (upButtonState == 0 && lastUpButtonState == 1){   //If still down AND was up before
      upOneGear();                                       //Shift up one gear
      lastUpButtonState = 0;                             //Save state
      digitalWrite(led_pin, HIGH);                       // Turn On LED when button is pressed
    }
  }
  else {                                                  //upButton must be open (button state = 1)
    delay (db_time);                                      //Wait a bit to debounce the button
    upButtonState = digitalRead(upButtonPin);             //Test again
    if (upButtonState == 1){                              //Still open, save state
      lastUpButtonState = 1;
      digitalWrite(led_pin, LOW);
    }
  }
  //
  //Now same for dowm
  //
  if (dnButtonState == 0){                               //Button was pushed
    delay(db_time);                                      //Wait a bit to debounce the button
    dnButtonState = digitalRead(dnButtonPin);            //Test again
  
    if (dnButtonState == 0 && lastDnButtonState == 1){   //If still down AND was up before
      dnOneGear();                                       //Shift down one gear
      lastDnButtonState = 0;                             //Save state
      digitalWrite(led_pin, HIGH);                       // Turn On LED when button is pressed
    }
  else if(dnButtonState == 0 && lastDnButtonState == 0)
  {
    unsigned long last_time=millis(); 
    
    do
    {
     dnButtonState = digitalRead(dnButtonPin);
     if(dnButtonState == 1)
      {
       break;
      }
     else if((millis()-last_time)>threshold)  
      {
       dnRearGear1();
      }
     
    }
   while(1);  
    
  
  }
  }
  else {                                                  //dnButton must be open (button state = 1)
    delay (db_time);                                      //Wait a bit to debounce the button
    dnButtonState = digitalRead(dnButtonPin);             //Test again
    if (dnButtonState == 1){                              //Still open, save stated
      lastDnButtonState = 1;
      digitalWrite(led_pin, LOW);
    }
  }
  

  
  
}
//
//Functions called
//
  void upOneGear(){
    if (rearGear < highestGear){
      rearGear = rearGear + 1;
    }
    shiftToRearGear(rearGear);
  }
  
    void dnOneGear(){
    if (rearGear > 1){
      rearGear = rearGear - 1;
    }
    shiftToRearGear(rearGear);
  }
  
  void dnRearGear1(){
    if (rearGear > 1){
      rearGear = 1;
    }
    shiftToRearGear(rearGear);
  }
  
  void shiftToRearGear(int gear){
      EEPROM.write(rearGearAddr, gear);
      switch (gear) {
    case 1:
      rearServo.write(rearGear1);
      sevseg.setNumber(1);
        sevseg.refreshDisplay();
      break;
    case 2:
      rearServo.write(rearGear2);
      sevseg.setNumber(2);
        sevseg.refreshDisplay();
      break;
    case 3:
      rearServo.write(rearGear3);
      sevseg.setNumber(3);
        sevseg.refreshDisplay();
      break;
    case 4:
      rearServo.write(rearGear4);
      sevseg.setNumber(4);
        sevseg.refreshDisplay();
      break;
    case 5:
      rearServo.write(rearGear5);
      sevseg.setNumber(5);
        sevseg.refreshDisplay();
      break;
    case 6:
      rearServo.write(rearGear6);
      sevseg.setNumber(6);
        sevseg.refreshDisplay();
      break;
    case 7:
      rearServo.write(rearGear7);
      sevseg.setNumber(7);
        sevseg.refreshDisplay();
      break;
    case 8:
      rearServo.write(rearGear8);
      sevseg.setNumber(8);
        sevseg.refreshDisplay();
      break;
    case 9:
      rearServo.write(rearGear9);
      sevseg.setNumber(9);
        sevseg.refreshDisplay();
      break;
    }
  }

Diagram.png
Thanks for your input.

Cheers
Dan
 
Actually, the codes above is working perfectly after a little tweaking...

See it in action here:
[youtube]zbBiMlinzlo[/youtube]
 
hello, am working on the same thing but need to add a auto shift function with reed switch and a magnet mounted on the motor shaft. i only know the basics of programming. so, am using your program as my base .it would be nice if anyone make some changes in the program for me.i also dont know how to take input from reed switch. i have researched a lot about this but did not got any code. a guy created same thing what i needed and posted the project in arduino forum without code and things used,i requested him but he is not responding.

it shoud automatically shift when my motor rpm reach >100rpm (as my motor only spin at 550rpm max)
am using a 7 speed cassete on my back wheel.
at 450rpm my gear should be on 7 and should auto return when speed decreases.

appreciate your work mate,welldone.
 
You can put 2kg of machinery and electronics on your bike for $200, or do it the smart way for $1 and 10 gramms.
[youtube]BqLCcapaUMg[/youtube]
 
Hi Dan,

I haven't followed this entire thread (and I haven't logged onto this site since last December). But if you still need help with the programming part, I'm reasonably competent and can help out (also I wanted to do something similar - your thing looks cool!)

Also - I might be able to add it to the opensource ebike project (though I'm not quite up-to-date on the state of that code). So the ebike motor controller can also control shifting (and do cool things like depower for shift)
 
Back
Top