So, I have a simple project. I basically hooked a standard size servo (Link) to a bicycle derailleur to shift it electronically. My setup is pretty simple. I have one servo, two buttons, and one LED, all controlled by an Uno. Circuit diagram on Tinkercad Circuits here. The code will tell the servo to upshift or downshift to the next gear when a button is pressed. (One for up, one for down.)
// 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 3 //HW pin to which servo signal line is attached
#define servoDelta 1 //Amt servo moves with each button push (degress)
#define upButtonPin 6 //Up button push grounds it
#define dnButtonPin 7 //Dn button push grounds it
#define led_pin 5 //LED Turn ON when button is pressed
#define highestGear 6 //Number of sprockets on rear hub
#define threshold 2000 // Long press button time threshold in mS
#define rearGear1 105 //Servo position values for the various rear sprockets (numbered low to high gears, not by size)
#define rearGear2 95 //These were determined empirically using the diyshift0 sketch while hooked up to a laptop
#define rearGear3 85
#define rearGear4 75
#define rearGear5 65
#define rearGear6 55
//#define rearGear7 90
//#define rearGear8 85
//#define rearGear9 80
#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 < 7))
{
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;
}
}
I copied this code from this website: DIY Derailleur e-Shifter with Arduino Nano... need help with programming... - Endless Sphere. All I have changed is I commented out the extra gears, the person on this website had nine and I have six. I also changed the variables that correspond to that (highest gear is now 6, not 9, etc.).
I have the servo power soldered to a USB cable. Both the servo USB cable and the Arduino are powered from a portable battery bank intended for charging phones. It is capable of 2.4A per USB port (it has 2), 3.4A total. The only data I have found on this servo’s current draw is from an Amazon answered question, where they claim a 1.8A maximum current draw at 5v when it is stalled.
However, the servo in the derailleur will only “power up” intermittently- I can hear it hum or move when it does.
Here is what I know:
-The battery is charged.
-The wiring to the servo is intact and works. I know the wires didn’t come unsoldered.
-The power wires to the servo are receiving power. I measured 5.05v with my multimeter, right where it should be.
-The code works. I tested it in Tinkercad Circuits, with the servo out of the bike, and with a different servo. They all work.
-The problem isn’t caused by a bad connection on the buttons, either. The LED lights up whenever I push them, just as it should. Thus, the Arduino is receiving and interpreting the signals.