Introduction: Bike Generator Charging Station

Want to workout but your phone's dead? With a stationary bike generator, that doesn't have to be a problem. You can hop on your bike and watch your calories burn as you provide the energy to recharge your phone (or Laptop). This project is an extension of a long-term project at Pomona College to build a bike generator for the student body to use to charge their electronic devices off the grid. We received great inspiration and inherited many parts from out predecessors who produced this Instructable.

The general construction is as follows:When the user pedals, they spin the back wheel which spins a DC motor via fan belt. The motor's leads are connected to a charge controller, which subsequently charges a lead-acid battery. The battery powers an inverter, which provides power to two 3-pronged outlets and two USB charging ports. We use an Arduino to turn on/off the charge controller and inverter as well as measure and display other diagnostic statistics of our bike generator on an LCD display.

Materials*:

  • Bike Frame w/ Back Wheel
  • Plywood/scrap wood/screws/bolts (for bike station)
  • Bike Training Stand
  • 24V Scooter Motor
  • Fan Belt
  • Fan Belt Pulley
  • 12V Lead-Acid Battery
  • DC-DC Battery Charger
  • DC-AC Inverter w/ USB & Wall Outlets
  • Arduino (We used a Leonardo but others will work)
  • MOSFET
  • LED & Photodiode
  • Hall Effect Current Sensor
  • LCD Screena
  • ON/OFF Switch
  • Relay, 5V Regulator, Diode, Buttons, Asst. Resistors

*This is a list of what used and is not meant to be an exhaustive list of what could or should be used. A lot of our decisions on electronics to use came down to what we had available (It wouldn't have been such a green bike if we had tons of new fancy electronics shipped in). So don't feel like you need everything on this list to make your own!

Step 1: The Bike Station

We inherited our bike setup from our predecessors, so for detailed instructions on how to set up the bike stand, see the first three steps of their Instructable. For your convenience, I will provide a quick synopsis of their work below:

Front Wheel Stand:

Because the bike was donated to our project without the front wheel, it was necessary to create a stand for it. This was done by making a small stand out of scrap 2x4's, threading a bolt across the top of the frame for the fork of the bike to rest on. This stand was then attached to a 2'x6' sheet of plywood to create a more permanent installation. We have had no issues with this stand, but for the more substantial or vigorous biker, additional lateral support for the stand might be considered for longevity of the stand.

Back Wheel Stand:

You could create a similar stand for the back wheel that attached to the plywood as well, but we found it convenient to use a prefabricated bike training stand*. This allows for greater flexibility (and arguably more stability) than creating an additional stand for the back wheel.

*Many bike training stands come with a form of resistance, which is unnecessary as the generator will provide you with all the resistance you need. Luckily, these resistance devices can be removed easily.

Generator:

The generator is actually a 24V DC Scooter Motor, but instead of applying a voltage to create a torque, we're applying a torque to create a voltage. The tire was removed from the back wheel of the bike so that we could run a fan belt around the back wheel of the bike and a pulley attached to the axle of the motor. Once the fan belt was in place on the tire and the pulley, the motor was screwed into the plywood so that the fan belt was reasonably taught (too taught and you introduce extra friction on the pulley). Note that by moving the back wheel stand, you can make small adjustments to the taught-ness of the fan belt even after the motor has been screwed down (and removing the bike stand will allow you to remove the fan belt).

Step 2: Generator to Battery

Battery:

A variety of batteries would work well in this project; we have chosen to use a 12V Lead-Acid battery simply because that was what we had available. While it is not necessarily important to use a specific type of battery for this project (provided that it is rechargeable), it is incredibly important to know what battery you are using. Different batteries like to be charged differently. In the case of our battery, it likes to be charged at 14V and a current no greater than 5.4A. These details can be easily acquired from the data sheet for your battery.

Other Battery care tips: You want to avoid draining the battery too low—this can permanently damage your battery. Conversely, you also do not want to overcharge the battery—this too can permanently damage the battery. Additionally, batteries will eventually degrade with age. There's no stopping the aging of batteries, but by treating the battery well and not letting it sit too long without use, you can extend its lifetime. To prevent draining the Battery with phantom loads we throw in a basic ON/OFF switch in between the negative end of the battery and anything that might be connected to it. To see how we use our Arduino to monitor the battery's voltage, see Step 4 on the integration of the Arduino with the charging of the battery.

Charge Controller:

Obviously we can't just hook up the motor to the battery terminals and pump charge in as fast as we can. That would quickly destroy your battery. To solve this problem, we connect the motor to the battery through a charge controller. The job of the charge controller is to keep the voltages and currents applied to the battery in the realm desired for the battery. In our setup, the charge controller would turn on when the user began pedaling. Holding the start button for three seconds would prompt the charge controller to check the condition of the battery (Automation of the step is covered in Step 4). If it was safe to charge (not already fully charged) the charge controller would begin to charge the battery. When pedaling stopped, so would the charge controller.

When purchasing a charge controller, it is important to find one that works in the range of inputs and outputs that your generator and battery require. For us that means a charge controller that can take an input voltage of up to 24V and provide 14V with a current limited to 5.4A. The charge controller we purchased had a variety of settings designed to charge many types of batteries and allowed for an adjustable output current (which we set to 5A). It is ultimately this current limit that sets the resistance of the generator on the bike.

Step 3: Battery to Inverter

Inverter:

Clearly one can not plug their cellphone or laptop directly into the battery. Not only is there not a 3-pronged outlet or a USB port on the battery, there are not safeguards to make sure the devices get the proper voltage and current, and nothing to turn the DC voltage of the battery into AC for your laptop. This is where the inverter comes in; it takes the 12V from the battery and provides the interface to charge phones and laptops. Just like the charge controller, which inverter you choose will depend on the voltages it must take from the battery (12V), how much power it must provide to the charging devices (Average phone: 5W; Average Laptop: 45-60W), and what type of outlets you need. The inverter we use has the capacity to provide 400W and has two wall outlets and two USB ports, though it is likely not to use either the full number of outlets no the full 400W at one time.

If you are only worried about charging phones or other USB devices, it is possible to omit the inverter entirely if you step down the voltage from the battery to the suggested voltage of 5V for a phone and have a USB port handy. This would avoid the inverter converting from DC to AC and then back to DC, however the power loss of this process is largely negligible and it is worth considering a cleaner interface—People are much more likely to trust an inverter with their phone than a makeshift USB charging port.

Hooking the inverter up to the battery is as simple as connecting the positive lead of the inverter to the positive end of the battery and the negative lead to the negative end of the battery. This is the bare minimum necessary for an operational bike generator. The generator will charge the battery through the charge controller and the battery will power the inverter, charging whatever devices are plugged into it.
To see how we better managed and controlled the charging of both the battery and electronic devices, see Step 4 on the integration of the Arduino into our bike station.

Step 4: Arduino Integration (Charging the Battery)

As mentioned before, for our charge controller to begin charging the battery, the start button must be held down for three seconds. This is a hassle to have to explain to a random user and it also requires the charge controller and all its extraneous buttons (that we'd rather random people not mess with) be accessible to the user. Instead we'd like the Arduino to press start once the user has started pedaling. This requires hacking into the charge controller.

Hacking the Charge Controller:

The charge controller is largely a black box; it takes in a positive and negative end from the DC generator and provides a current and voltage limited output out the other end to the battery. Everything in between is beyond the scope of this Instructable and is left alone. However, after taking the casing off the charge controller, it was fairy obvious how the button interface worked. The four buttons connected to a ribbon of five wires. When a button was pressed it connected the corresponding wire in the ribbon to the fifth "reference" wire. Deciding that it was easier to work with without the case we took the ribbon out of where it connected on the breadboard and soldered wires to these connections, attaching them to our shield with a molex connector. We used four buttons to recreate the buttons of the charge controller just in case we had to make changes in the settings if we had to and to press "Start" until we had the Arduino hooked up.

IMPORTANT: If, like us, you decide to leave your hacked charge controller out of its casing, be sure to provide it with a proper heat sink. Our charge controller case doubled as a heat sink and when we took this away, it was able to overheat after intense biking.

Pressing Start:

The challenge is then getting the Arduino to press a button. Obviously it cannot actually use a mechanic button, so we employed a relay. A relay more or less consists of an inductor across two pins and a switch across another two. When a voltage is applied across the inductor it closes the switch connecting the other two pins just like it was a button being pushed. If we connect one pin to the start wire and the other to the reference wire, we can have the Arduino output a voltage across the other two pins of the relay for three seconds on demand, thus "pressing" start whenever we ask it to. Though some relays have diodes built into them, we decided to put a precautionary one across the relay's induction pins to avoid current trying to flow back into the Arduino's pin when it was set to LOW.

Measuring the Battery and Motor Voltage:

This begs the question, when do we want to have the Arduino press start? Obviously we would want the Arduino to press start only when someone was pedaling, otherwise the charge controller would not be on to start in the first place. Though the charge controller should not knowingly overcharge the battery, we would not like to tempt it by repeatedly asking to charge the battery when it was full. This requires the Arduino to keep track of the voltage output by the generator and the battery. We'd like to wire these up to the Analog inputs of our Arduino, however they only like to read in voltages between 0 and 5V, whereas the battery will output anywhere from 11-14V and the generator will output anywhere from 0 to 24V. To step down from each of these voltages we use voltage dividers. In the case of the battery, we use a voltage divider with the first resistor being 1k ohms and the second (connected to ground) being 2.2k ohm. If the max voltage from the Battery is 14V, the max voltage across the second resistor, which we will measure is about 4.4V (For more information on how voltage dividers work and the math behind them, check out the Wikipedia page). We used resistors of 1k ohm and 4.7k ohm respectively for the voltage divider connected to the generator. For a generator voltage of 24V the Arduino would read 4.2V. Some simple math in the Arduino code can easily convert these measurements into the actual values. Obviously the voltage from the battery should be less than 14V or you risk overcharging the battery. The conditions for the generator are more flexible. As long as the user is providing enough voltage for the charge controller to turn on, the charge controller can charge the battery. We use >5V from the generator and <14V from the battery as our conditions.

Powering the Arduino:

Obviously the Arduino needs to be powered if it's to "press" any buttons (or do anything really). Having it constantly plugged into a computer is unreasonable. We also didn't want to use a 9V battery because we didn't want to have to replace it if it died. We decided to use the 12V battery to power the Arduino directly through the power jack. Though this should be able to take up to 12V, we decided it was safer to use a 5V regulator in between the battery and the Arduino. (This 5V could also be used as a voltage source for other electronics in our circuit if we wanted to avoid the Arduino's 5V pin). We then took one of the battery packs, cutting off the actual battery pack and connecting the wires to the 5V output of the regulator and ground. Regulators can get hot so it's important to put a heat sink on it.

Sample Code:

// complete code at the end of this Instructable

int motor = A0; //motor/generator pin on the Arduino

int batt = A1; //12V battery pin

int cc = 8; //charge controller pin

int wait = 500; //delay in milliseconds

float afactor = 1023.0; //Arduino's analog read max value

float motorV, battV; //motor voltage and battery voltage

boolean hasBeenOn = false; //to remember if the charge controller has been turned on

void setup() {

pinMode(motor, INPUT);

pinMode(batt, INPUT);

pinMode(cc, OUTPUT);

}

void loop() {

motorV = getmotorV(); //motovr/generator output voltage

if (motorV > 1.0 && !hasBeenOn) { //if our DC motor gives out more than 1V, we say it's on

digitalWrite(cc, HIGH); //the cc pin is connected to a relay

//that acts as the "Start" button for the charge controller

delay(3500); //our charge controller requires the start button to be held for 3 seconds

digitalWrite(cc, LOW); //electrically releasing the start button

hasBeenOn = true; //the charge controller should be charging the battery now

delay(wait); //we want our Arduino to wait so not to check every few millisec

}

else if(motorV > 1.0 && hasBeenOn){

delay(wait); //again, we don't want the Arduino to check every few millisec

}

else{

hasBeenOn = false; //the person is no longer biking

}

}

//we wrote separate functions so we could organize our code

float getmotorV(){

return (float( analogRead(motor) ) / afactor * 5.0); //the motor gives out about a max of 5V

}

float getbattV(){

return (float(analogRead(batt)) / afactor * 14.0); //the battery technically is~13.5V

}

Step 5: Arduino Integration (Turning on the Inverter)

We don't want our inverter always hooked up to the battery for multiple reasons. We don't want a ghost load potentially draining our battery when it's not in use, but most importantly, we don't want people able to plug in their phones or laptops and drain the battery without working for it. Using the Arduino to turn off and on the inverter allows us to manage the inputs and outputs of our battery without relying on the honesty or technical experience of our users.

We can easily integrate the Arduino as the gate keeper of the inverter by using a MOSFET. A MOSFET is like a normal transistor but requires less current from the gate to turn on, while delivering much greater currents (the trade off is that the gate voltage must be larger than a normal transistor but that's not a problem for an Arduino). We introduced the MOSFET into the battery-inverter circuit so that the negative end of the inverter was connected to the drain of the MOSFET and the negative end of the battery was connected to the source of the MOSFET. One of the Arduino's output pins was then connected to the gate of the MOSFET. When whatever criteria was set has been met (a certain duration of biking, voltage provided, etc.) the Arduino applies a voltage to the gate, allowing current from the battery's positive end to flow into the inverter through the MOSFET and into the negative end of the battery (ie completing the circuit). When the Arduino turns this signal off, the circuit is broken and the inverter turns off.

Because MOSFET can handle large currents, they can get pretty hot. Just like with the 5V regulator, we added a small heat sink to help dissipate heat.

Sample Code:

//the complete code can be found at the end of this Instructable

//the bolded code is what we add to the code from above

int mosfet = 7; // used to turn on the inverter

unsigned long timeOn, timecheck; // for time checking

void loop(){

if (motorV > 1.0 && !hasBeenOn) {
timeOn = millis();

}

inverterControl();

}

// the separate function

void inverterControl() {

battV = getbattV(); //check the battery voltage

timecheck = millis() - timeOn; //check how long the user has been biking

/* We want the user to have biked for a certain amount of time

before allowing the user to charge the user's electronics.

We also need to be sure that the battery isn't undercharged.

*/

if (hasBeenOn && (battV > 10.0) && (timecheck > 5000) && !mosfetOn) {

digitalWrite(mosfet, HIGH); //the inverter is on when the Arduino turns on the MOSFET

mosfetOn = true;

}

else if ((battV <= 10.0)) { //turns off inverter if the battery is too low

digitalWrite(mosfet, LOW);

mosfetOn = false;

}

else if(timecheck <5000) { //turns off if the user stopped/hasn't biked long enough

digitalWrite(mosfet, LOW);

mosfetOn = false;

}

}

Step 6: Arduino Integration (RPM Sensor)

In the spirit of a work out bike, we wanted to provide the user with a few relevant statistics about their workout. We singled out the RPM of the back tire as a key statistic. From it one can derive the equivalent speed the bike would be going or the distance it would have traveled if it weren't stationary. There are two easy ways to measure the RPM with an Arduino: An optical sensor and a Hall Effect sensor.

Optical Sensor:

We opted to build an optical RPM sensor for our bike due to the parts we had available. The concept is simple; An opaque, rigid object (in our case a thin plastic rectangle) is attached to the rim of the back wheel so that every time the wheel rotates, the object intercepts the path between an LED and a photo diode. To hold the photo diode and LED in place, we re-purposed a conveniently shaped piece of styrofoam with a notch in it just wide enough for the wheel (see photos). Styrofoam made it easy to adjust the LED and photo diode directly in line with each other (because photo diodes are very sensitive to the direction of the light—they work best with the light going directly into the top, thus reducing ambient light effects). If the LED was not aligned, we simple poked another hole in the styrofoam in the correct location. It is also important to attach the opaque object on the rim so that it does not interfere with the fan belt or hit the frame, ground, bike stand or other obstacles.

The circuitry is also fairly straightforward. We ran 5V from the Arduino to both the LED and the photo diode. It is important that the LED is not the only thing between 5V and ground. The LED does not provide much resistance and even 5V can send a large amount of current through the wire, which can blow your LED. We used a 1k ohm resistor in series with the LED, which means that the current through the LED is only ~5mA. The most important thing to remember when using a photo diode is that it operates the opposite of the LED. Instead of applying a voltage to produce light, a light is applied to produce a voltage, thus the diode must be placed in the circuit facing the opposite direction as the LED. The voltage produced by the current from the photo diode is measured across a resistor in series after the photo diode. The magnitude of this voltage is unimportant because we simply want to know if the photo diode senses the LED or if it is blocked. Adjusting the following resistor, however, can change the magnitude of voltage measured so that even with ambient light, the voltage read is 0. We found that using a 47k ohm resistor made for a voltage of 0 when blocked and a significant enough voltage to easily measure when it was not blocked. Every time the Arduino reads in 0 voltage, it knows the wheel has rotated once.

Hall Effect Approach:

The Hall effect can also be used to measure the rotation of the wheel. The Hall effect refers to the induced voltage created by a magnetic field. The set up for this approach is also very simple. A magnet is attached to the rim of the bike and a Hall probe is attached to the frame or in a similar location as the LED's of the optical sensor. A Hall probe is a circuit component designed to output a voltage proportional to the magnetic field transverse to it. Thus every time the magnet goes by the Hall probe, a voltage is output and can be read by the Arduino to count a rotation (again the magnitude of the voltage is irrelevant).

Sample Code (Optical Sensor):

//the complete code can be found at the end of this Instructable
//the bolded code is what we add to the code from above

int pdiode = A3; // photodiode for rpm

int photodiode;

int cycle = 0;

int numCycle = 20; // for averaging use

float t0 = 0.0;

float t1;

void setup() {

pinMode(pdiode, INPUT);

}

void loop() {

if (motorV > 1.0 && !hasBeenOn) {

cycle = 0;

t0 = float (millis());

}

getRpm();

}

void inverterControl() {

else if(timecheck <5000) {

cycle = 0; //this is a safety since arduino can't run multiple threads

t0 = float (millis());

}

}

void getRpm() {

//may want to consider an if else/boolean that makes sure increasing cycle only when biking

if (t0 == 0.0) { //safety for if the arduino just started and t0 hasn't been set yet

t0 = float (millis());

}

photodiode = analogRead(pdiode);

if (((photodiode != 0) && (analogRead(pdiode) == 0)) || ((photodiode == 0) && (analogRead(pdiode) != 0))) {

cycle++;

t1 = float(millis());

if (cycle > numCycle) {

rpm = (float(cycle)) / (t1 - t0)* 1000.0 * 60.0; //conversion to rotations per minute

cycle = 0;

t0 = float (millis());

}

}

Step 7: Arduino Integration (Current Sensor)

Though our charge controller displays the current it is outputting to the battery, we want to be able to keep track and display this quantity to the user for both diagnostic purposes as well as in the theme of other workout statistic. We chose to measure this quantity using the Hall effect mentioned in the previous step. Running the current from the charge controller through a special Hall probe current sensor that produces a voltage proportional to the magnetic field produced by the current running through it, we can indirectly measure the current we're providing the battery. There's unfortunately no easy reference table to convert the voltages output with the current creating them. However, the relationship between the voltage output by the hall probe and the current can be easily deduced by using a power source to run known currents through the probe and measuring the voltage produced. Plotting these will provide a zero-point value and the correlation between voltage and current you are looking for. Depending on which direction the current flows, the hall probe will give a different output. However, the absolute value of the slope should be the same.

This current can be converted into other statistics like the power being supplied to the battery and the total cumulative power produced. We plan on comparing the power supplied to the battery with the power used by charging various devices to determine whether the user needs to provide extra power to the battery before being able to charge their device if their device pulls more power than they can provide.

Sample Code:

//the complete code can be found at the end of this Instructable

//the bolded code is what we add to the code from above

int hall = A2; //for current sensing

float Wh = 0; //for recording the watt-hours generated since Arduino has been on

void setup() {

pinMode(hall, INPUT);

}

void loop() {

else if(motorV > 1.0 && hasBeenOn){

getCurrent();

}

}

void getCurrent(){ //the current going into the battery

current = (float(analogRead(hall))-514.5)/26.5; //equation for current from experimental plot

Wh = Wh + float(wait)/3600.0*current*13.0; // calculation for watt-hour

//assume 13V charge controller output into battery

}

Step 8: I2C LCD User-Interface and Menu

There are many ways to code the user-interface and menu using an Arduino and LCD shield. Our shield has 2 rows of display for 16 characters each, four directional buttons, a button intended for a "select" function, and a reset button. To simplify the coding process, we only utilized the four directional buttons, made a rather crude if-loop structure, and used instance variables for a lot of things. For those more comfortable with C++, we suggest you use a data structure (as suggested here) or something more elegant than too-many-if-loops. We wanted the user to access saved statistics such as the top time pedaled in one go, the total "distanced" pedaled on this bike and the total watt-hours generated since day one. While the user pedals, we want the screen to display statistics such as the time since user started pedaling, speed in kilometers per hour (because km is an under appreciated unit in the U.S.), power being generated, watt-hours generated during the cycling period. For readers who have not used an I2C LCD shield before, here is a good place to start.

The calculations for these statistics were not difficult; for RPM and km/s, we divided the number of cycles pedaled by the time it took for the user to pedal that many cycles, and converted the units. We measured the radius of the back wheel of our bike and found the radius to be 28 cm. Thus the circumference is 175.929 cm, 0.00109317 miles or 0.00175929km. We calculated the distance biked using distance = rate*time. For power generated, power = current * voltage (P=IV). To get a watt-hours generated, we performed a Riemann-sum-like addition by multiplying instantaneous power by the time that passed (0.5 seconds) and adding that every half second the user has pedaled.

As for the menu, we indexed each screen and used a dummy counting variable to navigate through the screens. Up and Down would subtract or add to the dummy variable, while Left returns us to the higher tiered menu and Right takes us to the submenus.

Here is a schematic of our menu

Root Menu

>Top time

>>Show value

>Total distance traveled

>>Show value

>Total power generated

>>Show value

>About

>>Whatever information there is about the bike.

//the complete code can be found at the end of this Instructable

//the bolded code is what we add to the code from above

// include the library code:

#include <Wire.h>

#include <Adafruit_MCP23017.h>

#include<Adafruit_RGBLCDShield.h>

#include <EEPROM.h> //for long term information storage on Arduinos

//This portion is taking word for word from Adafruit's tutorial, which we linked above

// The shield uses the I2C SCL and SDA pins. On classic Arduinos
// this is Analog 4 and 5 so you can't use those for analogRead() anymore

// However, you can connect other I2C sensors to the I2C bus and share

// the I2C bus. Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

// These #defines make it easy to set the backlight color

#define RED 0x1

#define YELLOW 0x3

#define GREEN 0x2

#define TEAL 0x6

#define BLUE 0x4

#define VIOLET 0x5

#define WHITE 0x7

//here starts the part we coded

int ptr = 0; // menu pointer

int mins, secs, kmh;

//long term storage variables

int timeAddress = 0;

int distanceAddress = 1;

int powerAddress = 2;

byte timeValue, distanceValue, powerValue;

boolean isHome = true;

void setup() {

lcd.begin(16, 2);

lcd.print("Hello, world!");

lcd.setBacklight(WHITE);

timeValue = EEPROM.read(timeAddress);

distanceValue = EEPROM.read(distanceAddress);

powerValue = EEPROM.read(powerAddress);

root(); //set display to root menu

}

uint8_t i=0; // we put this in because the tutorial included it (not exactly sure what it's for)

void loop() {

menuFunction(); //see if button is pressed

if (motorV > 1.0 && !hasBeenOn) {

lcd.clear();

lcd.setCursor(0,0);

lcd.print("Warming up...");

lcd.setCursor(0,1);

lcd.print("Keep pedaling. ");

lcd.setBacklight(GREEN);

digitalWrite(cc, HIGH); //press start on charge controller

lcd.setBacklight(YELLOW);

delay(3500); //press start for 3.5 seconds

cycle = 0;

t0 = millis();

digitalWrite(cc, LOW); //stop pressing start

//battery should now be charging

lcd.clear();

lcd.setCursor(0,0);

hasBeenOn = true;

lcd.print("Charging battery");

lcd.setBacklight(RED);

lcd.setCursor(3, 1);

timeOn = millis();

//time of how long person has been pedaling

lcd.print((millis()-timeOn)/1000);

delay(wait);

isHome = false;

}

else if(motorV > 1.0 && hasBeenOn){

secs = int((millis()-timeOn)/1000);

mins = int(secs/60);

secs = int(secs%60); //this could also be written as a separate function

lcd.clear();

lcd.setCursor(0, 0);

lcd.print(mins);

lcd.setCursor(2, 0);

// print the number of seconds since start biking

lcd.print(":");

lcd.setCursor(3, 0);

lcd.print(secs);

lcd.setCursor(9, 1);

lcd.print(rpm);

lcd.setCursor(13,1);

lcd.print("RPM");

isHome = false;

getCurrent(); //this prints W, Wh

getkmh(); //this prints km/h

}

else{

if (timeValue > (millis()-timeOn/1000/60)){

timeValue = int(millis()-timeOn/1000/60);

EEPROM.write(timeAddress, timeValue);

}

if(!isHome){

root();

}

}

}

void getkmh() {

kmh = rpm*60.0*revolution;

lcd.setCursor(0, 1);

lcd.print(kmh);

lcd.setCursor(2,1);

lcd.print("km/h ");

}

void getCurrent(){

current = (float(analogRead(hall))-514.5)/26.5;

lcd.setCursor(6, 0);

lcd.print(int (current*13));

lcd.setCursor(8,0);

lcd.print("W");

Wh = Wh + float(wait)/3600.0*current*13.0;

lcd.setCursor(10,0);

lcd.print(Wh);

lcd.setCursor(13,0);

lcd.print("Wh");

}

void menuFunction() {

delay(200);

uint8_t buttons = lcd.readButtons();

if (buttons) {

if (buttons & BUTTON_UP) {

scrollUp(ptr);

}

if (buttons & BUTTON_DOWN) {

if(ptr >0){

scrollDown(ptr);

}

}

if (buttons & BUTTON_LEFT) {

if(ptr >=1 && ptr <=4){

root();

}

else if(ptr >= 5){

menu();

}

}

if (buttons & BUTTON_RIGHT) {

scrollRight();

}

}

}

void menu() {

lcd.clear();

lcd.setCursor(0, 0);

lcd.print("MENU (scroll V)");

lcd.setCursor(0, 1);

lcd.print("Top times");

ptr = 1;

}

void root() {

lcd.clear();

lcd.setCursor(0, 0);

lcd.print("Bike to Charge!");

lcd.setCursor(0, 1);

lcd.print("Menu (Right >)");

ptr = 0;

isHome = true;

}

void scrollRight() {

Serial.println(ptr);

if(ptr == 0){

menu();

}

else if(ptr == 1){

lcd.clear();

lcd.setCursor(0, 0);

lcd.print("Top time");

lcd.setCursor(0, 1);

lcd.print(timeValue); // RECALL NUMBER!!! TOP TIME

lcd.setCursor(13,1);

lcd.print("min");

ptr = 5;

}

else if(ptr == 2){

lcd.clear();

lcd.setCursor(0, 0);

lcd.print("Total distance");

lcd.setCursor(0, 1);

lcd.print(distanceValue); // RECALL NUMBER!!! TOTAL DISTANCE

lcd.setCursor(14,1);

lcd.print("mi");

ptr = 6;

}

else if(ptr == 3){

lcd.clear();

lcd.setCursor(0, 0);

lcd.print("Total energy");

lcd.setCursor(0, 1);

lcd.print(powerValue); // RECALL NUMBER!!! TOTAL WATTHOURS

lcd.setCursor(15,1);

lcd.print("J");

ptr = 7;

}

else if(ptr == 4){

lcd.clear();

lcd.setCursor(0, 0);

lcd.print("Scroll down to ");

lcd.setCursor(0, 1);

lcd.print("read more!!! (V)"); // RECALL NUMBER!!! TOTAL WATTHOURS

ptr = 8;

}

}

void scrollDown(int i){

Serial.println(i);

if (i == 1){

lcd.setCursor(0, 1);

lcd.print("Total distance ");

ptr = 2;

}

else if (i == 2){

lcd.setCursor(0, 1);

lcd.print("Total energy ");

ptr = 3;

}

else if (i == 3){

lcd.setCursor(0, 1);

lcd.print("About! ");

ptr = 4;

}

else if (i == 8){

lcd.clear();

lcd.setCursor(0, 0);

lcd.print("Electronics bike");

lcd.setCursor(0, 1);

lcd.print("worked on by: ");

ptr = 9;

}

else if (i == 9){

lcd.clear();

lcd.setCursor(0, 0);

lcd.print("A. McKay '13");

lcd.setCursor(0, 1);

lcd.print("J. Wong '15");

ptr = 10;

}

else if (i == 10){

lcd.clear();

lcd.setCursor(0, 0);

lcd.print("A.Karapetrova'15");

lcd.setCursor(0, 1);

lcd.print("S. Walecka '15");

ptr = 11;

}

else if (i == 11){

lcd.clear();

lcd.setCursor(0, 0);

lcd.print("S. Li '17");

lcd.setCursor(0, 1);

lcd.print("N. Sandford '17");

ptr = 12;

}

else if (i == 12){

lcd.clear();

lcd.setCursor(0, 0);

lcd.print("For His Majesty ");

lcd.setCursor(0, 1);

lcd.print("Dwight Whitaker ");

ptr = 13;

}

else if (i == 13){

lcd.clear();

lcd.setCursor(0, 0);

lcd.print("Phys 128 ");

lcd.setCursor(0, 1);

lcd.print("Pomona College ");

ptr = 14;

}

else if (i == 14){

lcd.clear();

lcd.setCursor(0, 0);

lcd.print("Paid for by the ");

lcd.setCursor(0, 1);

lcd.print("SIO and Dept of ");

ptr = 15;

}

else if (i == 15){

lcd.clear();

lcd.setCursor(0, 0);

lcd.print("Physics and ");

lcd.setCursor(0, 1);

lcd.print("Astronomy. ");

ptr = 16;

}

}

void scrollUp(int i){

if (i ==2){

menu();

}

if (i>2){

scrollDown(i-2);

}

}

Step 9: Final Circuit Diagram and Code

95% of our circuitry was soldered onto a perfboard for organization and centralization of our electronics. Molex connectors are a great way of organizing incoming and outgoing wires on the perfboard. The complete code is attached as an .ino file and linked as a Google doc for those who don't have the Arduino IDE. The code could definitely be cleaner and more advanced with regards to the menu and screen display, but works for our purposes (it's our first time using the LCD shield).

Step 10: Tidying Up

Cleaning Up:

To wrap up our project we neatly bundled all the extra length in wires and placed all of the electronics (save the LCD display and inverter) in a container to the right of the front bike stand. Holes were cut to allow wires to run to the back of the bike (LED/photo diode and generator), the battery, the inverter and the LCD display. The wires going to the back of the bike were covered with half a PVC pipe and connected to the plywood to keep them out of the way. The battery was housed in a cardboard box, primarily to keep it out of sight, not that it provided any protection or security. A plastic book stand we inherited from the previous team was attached to the handle bars on which a book or phone could be placed. The LCD screen was also attached to this stand.

As mentioned in Step 2 we broke up the circuit by placing a manual ON/OFF switch between the negative end of the battery and everything that was attached to it to avoid any draining of the battery while it was not in use. This switch was placed on the handlebar for easy access. Be careful that the switch does not sit directly on the handle bar, because as we discovered the metal of the handle bar has no problem connecting between the two contacts of the switch, defeating the purpose of the switch. A layer of electrical tape will fix this no problem.

We then dressed up the bike and the plywood using some paint we had on hand (being careful not to get it in the gears, electronics, or spokes).

Future Plans:

We are planning to put more work into this project over the summer when we have spare time. Our current ideas for improvements and extensions include:

  • Heat Sink for the charge controller
  • Weather (Sun and rain) proofing (The end product may end up living outside)
  • Hall Effect RPM sensor
  • Better book stand, cup holder
  • More extensive/User Friendly Menu
  • Cleaner code using a menu data structure

Feel free to give an suggestions on how else we can improve or extend on this project.

Move It

Participated in the
Move It

Coded Creations

Participated in the
Coded Creations