Address

Author Topic: Chorca's Bike Computer  (Read 2566 times)

Chorca

  • FamiLAB Member
  • Sr. Member
  • *
  • Posts: 272
  • My primary function is failure.
    • View Profile
    • Flickr
Chorca's Bike Computer
« on: April 08, 2012, 02:47:16 AM »
So here's the deal: bike computers (Cyclometers) are freaking expensive. You want one with a lot of features? Lots of money. Not $20 expensive, like $200 expensive.
The thing is, there's nothing really complex about them, they're just little micros with a magnet reed switch. You still have to program the wheel size, and then it uses that info to determine how fast you're going, how far you've traveled, and lots of other stats.

So, it's been my plan to build one using something simple like an Arduino, that uses an OLED display and has a simple input system (rotary encoder+push). I have most of the simple maths done, which includes the distance, speed, averaging of speed, etc., now I just need to write the GUI and do some of the other fun features.

I'm going to keep a log of my code, electronics, and other goodies here to show everyone what I'm up to, as well as to solicit better ideas on what I'm doing (I'm no code-head. I'm sure my code sucks.)
« Last Edit: April 16, 2012, 12:27:34 AM by Chorca »

Chorca

  • FamiLAB Member
  • Sr. Member
  • *
  • Posts: 272
  • My primary function is failure.
    • View Profile
    • Flickr
Re: Chorca's Bike Computer
« Reply #1 on: April 08, 2012, 03:16:40 AM »
What I have so far:

A quick shot of the math portion of the software. When the reed switch is tripped, it checks how long it's been since the last time it was tripped, and by knowing the circumference of the wheel, can tell how long it took to travel that distance, and therefore, how fast you traveled it.

Bike computer! by Chorca, on Flickr


A mock-up of the interface. I wrote this in arduino and am sending it via serial to the display, however, the display has it's own programming language that can be used to write code for it, which I may explore.

OLEDs.. by Chorca, on Flickr

Here's the current code:
Code: [Select]
//circ circumference in millimeters
int circ = 2108;

byte SensorPin = 2;                     //Input pin for speed sensor
unsigned long tripTime;                 //last time sensor was tripped
unsigned long lastTripTime;             //time before last sensor was tripped
unsigned long revs = 0;                 //number of revs
unsigned int milsecs;                   //this will overflow after 64 seconds or so between hits, but that doesn't matter, only need it for sub-second timings
unsigned int outspeed;                  //speed output to screen
unsigned long totalmm;                  //total millimeters
float mph = 0;                          //current calculated speed
unsigned int avg[4];                    //array for averaging speed
volatile boolean state = false;         //check for if sensor has been tripped
byte menuPin = 3;                       //Menu button
unsigned long menuTrip;                 //last trip time for menu button
boolean menuState;                      //current state of menu button
byte menuSelect;                        //current display mode
unsigned long displayTimer;             //last screen update


void setup()
{
  pinMode (SensorPin,INPUT);            //enable input sensor
  pinMode (menuPin,INPUT);
  digitalWrite (SensorPin, HIGH);       //turn on pull up resistor
  digitalWrite (menuPin, HIGH);
/*
  Serial.begin(9600);                   //Code for setting LCD to 38400 baud. LCD stores speed in EEPROM, so reconfig shouldn't be necessary.
  Serial.print(124, BYTE);
  Serial.print(16, BYTE);
  delay(500);
*/
  Serial.begin(38400);                  //Start serial communications with LCD
  Serial.print(0xFE, BYTE);             //Command byte
  Serial.print(0x01, BYTE);             //Clear screen
  attachInterrupt(0,sense,LOW);         //Setup interrupt for wheel sensor
}


void loop()
{
  if(state == true && (millis() - tripTime) > 40)    //check if the thing's been tripped, and also debounce the input (40ms = approx 250mph).
  {
    tripTime = millis();                //set the time the interrupt occured
    revs = revs + 1;                    //update the revs number
    calc();                             //recalculate the current stats
  }

  if(state == true)                     //if it's still true...
    state = false;                      //falsify state
   
  if (digitalRead(menuPin) == LOW)      //If the button is currently pushed
   {
    if ((menuState == false) && ((millis() - menuTrip) > 250))  //Check to see if the button was previously not pushed -If it was held- and if it's been longer than 250ms since last trip -For debounce-
    {
      menuState = true;                 //Set the current state to pressed
      menuTrip = millis();              //Reset the tripped time
      menuchange();                     //call the menu change routine
    }
   }
  else if (digitalRead(menuPin) == HIGH)  //If the button is not pushed
  {
    menuState = false;                  //Set the state to released
  }
}


void menuchange()
{
  menuSelect++;                         //Advance the menu and roll it over if need be
  if (menuSelect == 2)
    menuSelect = 0;
  display();                            //Update the display to give feedback that pressing the button does something
}


void calc()
{
  digitalWrite(13, HIGH);
  milsecs = tripTime - lastTripTime;    //calculate the difference between the current time and the last tripped time
  lastTripTime = tripTime;              //reset the last tripped time
  mph = (circ / milsecs) * 2.2369;      //calculate the speed
  avg[0] = avg[1];                      //shift storage array
  avg[1] = avg[2];                      //    "
  avg[2] = avg[3];                      //    "
  avg[3] = int(mph);                    //insert current calculated mph
  if ((millis() - displayTimer) >= 500) //run the display routine every 500ms if the wheel is spinning
    {
      displayTimer = millis();
      display();
    }
    digitalWrite(13, LOW);
}

void display()
{
  totalmm = revs * circ;                //multiply the number of revs by circumference to get total mm
  outspeed = ((avg[0] + avg[1] + avg[2] + avg[3]) / 4);    //average the speed over the last four readings (mean)
  Serial.print(0xFE, BYTE);             //Command byte
  Serial.print(0x01, BYTE);             //Clear screen
  Serial.print("Dist: ");               //Show distance
  if (menuSelect == 0)
  {
    float dist1 = totalmm / 1609344.0;  //in miles
    Serial.print(dist1);                //""
    Serial.print(" mi");                //show denominator
  }
  else if (menuSelect == 1)
  {
    unsigned long dist1 = totalmm / 304.8;      //in feet
    Serial.print(dist1);                //""
    Serial.print(" ft");                //show denominator
  }
  Serial.print(0xFE, BYTE);             //Command byte
  Serial.print(192, BYTE);              //Move to 2nd line
  Serial.print("Speed: ");              //Show speed
  Serial.print(outspeed);               //   "
  Serial.print(" mph");                 //show denominator
}


void sense()
{
  state = true;
}

digitalman2112

  • Lab Dad (ex-treasurer)
  • FamiLAB Member
  • Hero Member
  • *
  • Posts: 1096
  • Work Hard, Play Hard!
    • View Profile
    • Raising Geeks
Re: Chorca's Bike Computer
« Reply #2 on: April 08, 2012, 10:20:26 AM »
Looks awesome - nice work on the OLED screen output.


A few things I liked or wanted in the ones I had (and items that drove the price WAY up):


1) Crank speed sensor - good for knowing how long I could maintain a specific cadence, and when combined with speed, also lets you infer gearing changes. Another mag switch on the crank arm is pretty easy.


2) Having the wheel sensor on the BACK wheel instead of the front - allows you to use the system on a stationary bike trainer. (BTW, I have one - if you wanted to borrow it for testing, let me know...)


3) Heart Rate sensing - the Polar stuff is well documented on Arduino. Lets me train to stay at a certain intensity...


4) Stats upload - I had a Polar one that chirped to the mic on your laptop - you could easily do bluetooth or wifi with an arduino...




Looks great, can't wait to see where it goes from here...

Chorca

  • FamiLAB Member
  • Sr. Member
  • *
  • Posts: 272
  • My primary function is failure.
    • View Profile
    • Flickr
Re: Chorca's Bike Computer
« Reply #3 on: April 10, 2012, 10:38:15 AM »
So tonight I brought it out to Micro Monday to show off and work on a little. I successfully merged the library that I was working on with the serial out code. I used an #include <stdlib.h> which bumped the size up a little, (4000 to 6000) but gives me some useful functions like converting a float to a string. This is important for dumping out the data, as it's in float format for distance and some other stuff.

It's printing some very basic text out to the OLED, and while refreshes are kinda slow, I'm hoping I can just refresh small sections of the display so that you won't see much flicker.

I'll post pictures later.


Also, what digitalman2112 says, yes. I can incorporate all those wonderful things into this thing (provided i have enough space).

Chorca

  • FamiLAB Member
  • Sr. Member
  • *
  • Posts: 272
  • My primary function is failure.
    • View Profile
    • Flickr
Re: Chorca's Bike Computer
« Reply #4 on: May 02, 2012, 02:31:21 PM »
I totally got on Github, guys. It's my first project on there. I can use this for version control rather than dropbox.
https://github.com/chorca/bikeometer