Pages: 1 2 [3] 4 5 6   Go Down
Author Topic: Motorcycle Control Panel with Arduino + Bluetooth  (Read 23954 times)
0 Members and 1 Guest are viewing this topic.
ottawa, canada
Offline Offline
God Member
*****
Karma: 6
Posts: 993
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


I've already said I'm easily amused but this project's 15 minutes of fame has spread over onto Hack-a-Day.

http://hackaday.com/2009/06/14/bluetooth-motorcycle-control-panel-with-arduino/
Logged

Bill Rowe
Olduino - An Arduino for the First of Us
www.olduino.wordpress.com

North Yorkshire, UK
Offline Offline
Faraday Member
**
Karma: 104
Posts: 5531
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yeah but we read it here first guys...

Mowcius
Logged

ottawa, canada
Offline Offline
God Member
*****
Karma: 6
Posts: 993
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

June 19
BoB is Alive!
I can't imagine why I thought this was simple.  I reproduced the RBBB circuit on a Radio Shack proto-board and added the extra power protection and the voltage dividers and debounce circuits needed for the MC control panel.  I'm not completely finished the wiring but it got to the point where I could try a sketch and it worked.  The good news is that it does fit in the allowable space on the bike so that's something.

Next steps I have to finish wiring the LCD header and the serial hookup then I should be able to port the software.  Way too much trouble though.  If I do another prototype I'll try out something like the mpguino or some other proto-board as a base .

Logged

Bill Rowe
Olduino - An Arduino for the First of Us
www.olduino.wordpress.com

0
Offline Offline
Full Member
***
Karma: 0
Posts: 126
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

[size=12]What is that square white object in the lower right corner?  [/size]It has five leads connected to the board. smiley

Pakrat
Logged

Sofia, Bulgaria
Offline Offline
Full Member
***
Karma: 0
Posts: 237
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

a connector with 5 leads
Logged

0
Offline Offline
Full Member
***
Karma: 0
Posts: 126
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
mircho

Junior Member

Online

Arduino rocks

Posts: 66

  Re: Motorcycle Control Panel with Arduino + Bluetooth
Reply #34 - Today at 08:47:55  
 a connector with 5 leads  


CUTE

Logged

ottawa, canada
Offline Offline
God Member
*****
Karma: 6
Posts: 993
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok, BoB took his seat yesterday.
I was struggling with how to mount the new prototype in the motorcycle console.  The hole where the tach fits is a good size but positioning and holding it seemed tricky.  I hit on the idea of using a cupboard door knob as a seat for the circuit board.  The door knob mounts to a support made for the tach and positions the display just about perfectly.  The first pic below shows BoB and the display beside the tank console.  The upper hole in the console is for the tachometer, the lower one is the gas filler.  The second pic shows the cupboard door know mounted in the tach hole and the third pic shows BoB mounted on his new seat.  The positioning is not perfectly centered but I can figure that out.  I remain stonkered stymied though by mounting the thing in a weatherproof way - that panel could be subjected to hours or days of driving rain and high winds.


« Last Edit: June 30, 2009, 05:02:01 pm by bill2009 » Logged

Bill Rowe
Olduino - An Arduino for the First of Us
www.olduino.wordpress.com

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 210
Posts: 13030
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I remain stonkered though by mounting the thing in a weatherproof way...

http://www.wordwebonline.com/en/STONKERED
Adjective: stonkered  stóng-ku(r)d
1. Very tired
2. [Austral, NZ] Very drunk

http://www.urbandictionary.com/define.php?term=stonkered
1. To be severely affected by alcohol. Usually accompanied by loss of co-ordination, slurred speech and dishevelled appearance.
2. To feel bloatedly full, primarily with food.
3. To be stoned. Under the influence of Marijuana. THC poisoning, if you will.

You've seen it here first!  A new definition for the word "stonkered"!   smiley-wink

P.S. Thanks bill2009 for writing about your adventure.  smiley

- Brian
« Last Edit: June 30, 2009, 02:38:07 pm by bcook » Logged

ottawa, canada
Offline Offline
God Member
*****
Karma: 6
Posts: 993
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

BoB is retiring for the moment.  I cobbled up an LCD mount which I had hoped would stand up to modest water torture.  Sadly, no.  
Logged

Bill Rowe
Olduino - An Arduino for the First of Us
www.olduino.wordpress.com

0
Offline Offline
Full Member
***
Karma: 0
Posts: 113
Arduino paper
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

So how has BoB come up after the unexpected showering ?? smiley-sad
Logged

Checkout my projects development blog @ SLiDA

ottawa, canada
Offline Offline
God Member
*****
Karma: 6
Posts: 993
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

BoB is fine, the "head" is in disgrace on my coffee table.  I bought (another!) bike speedo and I'm going to try using that as a readout - presumably it's waterproof.

It's also kind of a neat idea if you think of it as a bike speedo circuit bending exercise.  You're basically breaking into the speedo's sensor wire and installing an arduino that changes the readout depending on the tach input.
Logged

Bill Rowe
Olduino - An Arduino for the First of Us
www.olduino.wordpress.com

0
Offline Offline
Newbie
*
Karma: 0
Posts: 13
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bill I like the idea it is a great ap to the micro. I would be interested in your code as I would like to build a data logger for the rpm on my dirt race car. any help would be apreciated. Hugh
Logged

ottawa, canada
Offline Offline
God Member
*****
Karma: 6
Posts: 993
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here is the latest version of the BoB code.  I may have to split it in multiple postings.  The only tricky part of this in my mind is the way I handle interrupts.  I have them split into stubs which catch the interrupts and store them in a table, and routines which run periodically out of "Loop" which scan the table and handle the events.  I do it this way so sloppy/slow coding doesn't make me miss interrupts without knowing.  In principal I could take that stuff out once it's working but I never seem to.

Code:
//july 11 V8 cut out voltage display cuz it doesn't work!
//display speed in MPH for US trip
#include <LiquidCrystal.h>
LiquidCrystal lcd(10,13,9,12,15,11,16); //(rs,rw,enbl,d4,d5,d6,d7)
unsigned long lasttachint,lastwheelint; //time in millis of most recent tach and wheel interrupts
float insttachrpm=0, avgtachrpm=0, wheelrpm=0;  //tach instantaneous and rolling average rpm,  wheel rpms
float revratio; int currentgear=0; //updated by setgear routine
float roadspeed=0; //speed in kph
volatile int ilog=0;
int maxlog=31;  
volatile boolean logoflo; //index to log table, max entry #, log overflow flag
volatile byte lflag[32];
volatile unsigned long lmillis[32]; //log of interrupts
int tachpin=2;  //pedal sensor booster, drives interrupt 0;
int wheelpin=3; //wheel sensor, drives interrupt 1;
int neutralpin=5;
void setup() {
  lcdbegin(); //initialize the lcd
  clearlog();  //clear the interrupt table
  attachInterrupt(0, tachmonitor, RISING);  //interrupt from tachometer
  digitalWrite(wheelpin,HIGH); //set pullup resistor for reed switch
  attachInterrupt(1, wheelmonitor, RISING);  //interrupt from reed switch wheel sensor
}

void loop(){
  checklog();  //make sure log is ok before processing
  processlog(); //process and dump the log file to the PC
  chkneutral(); //test for neutral
  chkstale(); //check to see if tach or speed readings are >3 seconds old (bike has stopped!)
  updatedisplay();
  delay(100);  //wait a while
}
void chkstale(){
  if ((millis()> (lastwheelint+3000)) && (wheelrpm>0)){
    wheelrpm=0; roadspeed=0;
  }
  if ((millis()> (lasttachint+3000)) && (insttachrpm>0)){
    insttachrpm=0; avgtachrpm=0;    
  }
}

void updatedisplay(){
  lcd.clear();
  pbc(currentgear); //display what gear we're in
  lcd.setCursor(4,0); lcd.print(int((avgtachrpm+50)/100)*100); //tach
  lcd.setCursor(4,1); lcd.print(int((roadspeed/1.6)+.5)); //speed in Mph
}
void chkneutral(){
  if (inneutral()){
    currentgear=10;
  } //10 is code for neutral
  else{ //need to see if we've come out of neutral with no other info  
    if (currentgear==10) {// if we used to be in neutral
      currentgear=0; //      0 is "don't know"
    }
  }
}

boolean inneutral(){ //see is neutral light is on
  int n=analogRead(neutralpin); //neutral light sensor is on analog pin 5 - usually <100 in neutral, >300 in gear.
  if (n<150){
    return(true);
  }
  else{
    return(false);
  }
}
Code:
void checklog(){ //make sure log hasn't overflowed
  if (logoflo==true){
    noInterrupts();
    clearlog();
    interrupts();
    Serial.print("log overflowed at ");
    Serial.println(millis());
  }
}

void processlog(){
  int dlog,i; //how many entries to copy and dump
  unsigned long dmillis[32];
  byte dflag[32];  //space for the log entries
  noInterrupts(); //disable interrupts while we copy the log
  dlog=ilog;  //copy the count
  if (dlog!=0) { //if there's anything to copy
    for(int i=0; i<dlog;i++){
      dmillis[i]=lmillis[i];
      dflag[i]=lflag[i];
    }
    ilog=0; //reset the count
  }
  interrupts(); //reenable interrupts
  if (dlog!=0){ //if there's anything to process
    for (i=0;i<dlog;i++){
      //Serial.print(i); Serial.print(dflag[i]); Serial.print(" "); Serial.print(dmillis[i]); Serial.print(" ");
      if (dflag[i]=='W') {
        processwheel(dmillis[i]);
      }
      else {
        if (dflag[i]=='T') {
          processtach(dmillis[i]);
        }
      }
      //Serial.println(" ");
    }
  }
}

void processtach(unsigned long lmillis){ // input is interrupt time in millis
  unsigned long tachtime; //elapsed time for 10 tach events
  if (lasttachint!=0) { //skip calculation on first time in
    tachtime=lmillis-lasttachint;  //time for last 10 events
    if (tachtime>0){ //just avoid divide by 0
      insttachrpm=60000/(float)tachtime*10;  //rpm based on time in ms for 10 tach pulses
      avgtachrpm=(avgtachrpm*2+insttachrpm)/3; //rolling average rpm
      //Serial.print(" tachtime="); Serial.print(tachtime); Serial.print(" inst tach rpm="); Serial.print(insttachrpm); Serial.print(" avg tach rpm="); Serial.print(avgtachrpm);
    }
  }
  lasttachint=lmillis;
}

void tachmonitor(){
  static int tachcount;
  if (tachcount <9) { //bulking up tach interrupts by a factor of 10
    tachcount++;
  }
  else {  //every 10th tach pulse we spawn a log entry
    if (ilog<=maxlog){
      lflag[ilog]='T'; //pedal pass flag
      lmillis[ilog]=millis();
      ilog++;
    }
    else {
      logoflo=true; //we've overrun the log table
    }
    tachcount=0;
  }
}

void processwheel(unsigned long lmillis){ //input is time of interrupt from log
  unsigned long wheeltime; //time for previous revolution
  if (lastwheelint!=0){ //don't do calculations 1st time in
    wheeltime=lmillis-lastwheelint; //track the exact rotation time
    wheelrpm=60000/(float)wheeltime;
    //Serial.print(" wheeltime="); Serial.print(wheeltime); Serial.print(" wheel rpm="); Serial.print(wheelrpm);
    roadspeed=.123*wheelrpm; //condensed version of 2.05*60*wheelrpm/1000; where 205 is wheel circ. in metres
    //Serial.print(" road speed kph="); Serial.print(roadspeed);
    setgear(); //figure out what gear we're in
  }
  lastwheelint=lmillis;
}

void wheelmonitor(){
    if (ilog<=maxlog){
      lflag[ilog]='W'; //wheel pass flag
      lmillis[ilog]=millis(); //record time
      ilog++;
    }
    else {
      logoflo=true;
    }
}

Logged

Bill Rowe
Olduino - An Arduino for the First of Us
www.olduino.wordpress.com

ottawa, canada
Offline Offline
God Member
*****
Karma: 6
Posts: 993
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

remaining code:
Code:
int whichgear(float ratio){
  float validratios[]={
    11.7,8.37,6.65,5.54,4.61  };
  int maxratioindex=4; //ratios for motorcycle

  int gearsforratios[]={
    1,2,3,4,5    };
  for (int i=0;i<=maxratioindex;i++){
    if (closeto(ratio,validratios[i],5)) return gearsforratios[i];
  }
  return 0;
}

boolean closeto(float param, float reference, float pcttolerance){ //true if param is within tolerance% of reference
  return (param>=(reference*(100-pcttolerance)/100))&&(param<=(reference*(100+pcttolerance)/100));
}


void setgear(){ //determine which gear the bike is in
  int newgear;
  static int prevgear, prev2gear;  
  if (wheelrpm!=0 && insttachrpm!=0){
    revratio=insttachrpm/wheelrpm;
    //Serial.print("<"); Serial.print(revratio); Serial.print(">");
    newgear=whichgear(revratio);
    if (newgear!=0){
      if (newgear==prevgear /*&& newgear==prev2gear*/){
        currentgear=newgear;
      //  Serial.print("Sel: "); Serial.print(newgear); Serial.print(" ");
      }
      //prev2gear=prevgear;
      prevgear=newgear;
      //Serial.print("Candidate: "); Serial.print(newgear); Serial.print(" ");
    }
  }
}

void clearlog(){ //clear the interrupt log
  for(int i=0; i<=maxlog; i++){
    lflag[i]=' ';
    lmillis[i]=12345678;
  }
  ilog=0;
  logoflo=false;
}

void pbc(byte x){
  //routine to print digits 0-9 & letter N in double height characters on an LCD
  //strings to index into for displaying the big numbers
  char bignumchars1[]={
    32,32,32,0, 1,4,32,0, 3,3,4,0, 1,3,4,0, 4,2,4,0,   4,3,3,0, 4,3,3,0, 1,1,4,0,   4,3,4,0, 4,3,4,0, 4,6,4,0  }; //0 was 4,4,4
  char bignumchars2[]={
    32,32,32,0, 2,4,2,0,  4,2,2,0, 2,2,4,0, 32,32,4,0, 2,2,4,0, 4,2,4,0, 32,32,4,0, 4,2,4,0, 2,2,4,0, 4,7,4,0  }; //0 was 4,2,4
  lcd.setCursor(0,0);
  lcd.print(bignumchars1+x*4);
  lcd.setCursor(0,1);
  lcd.print(bignumchars2+x*4);
}
void setupbigchars(){
  //routine to load the character generator ram on an lcd controller with block characters
  //credit to dcb on arduino forums http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1213319639
  lcd.command(B01001000);  // set cgram
  byte chars[]={
    B11111,B00000,B11111,B11111,B00000,B00000,B01110,
    B11111,B00000,B11111,B11111,B00000,B11000,B00111,
    B00000,B00000,B00000,B11111,B00000,B11000,B00111,
    B00000,B00000,B00000,B11111,B00000,B11000,B00111,
    B00000,B00000,B00000,B11111,B00000,B11100,B00011,
    B00000,B00000,B00000,B11111,B01110,B11100,B00011,
    B00000,B11111,B11111,B11111,B01110,B11100,B00011,
    B00000,B11111,B11111,B11111,B01110,B01110,B00000  };

  for(byte x=0;x<7;x++)
    for(byte y=0;y<8;y++)
      lcd.write(chars[y*7+x]); //write the character data to the character generator ram    
}

void lcdbegin(){
  delay(25); //make sure there's a clear delay for lcd power-on initialization
  lcd.command(0x28);  // function set: 4 bits, 1 line, 5x8 dots
  lcd.command(0x0C);  // display control: turn display on, cursor off, no blinking
  lcd.command(0x06);  // entry mode set: increment automatically, display shift, right shift
  lcd.clear();delay(5);
  lcd.print("V8 Bill!"); delay(250); lcd.clear(); delay(5);
  setupbigchars();delay(25); //write big fonts to lcd cgram
}
Logged

Bill Rowe
Olduino - An Arduino for the First of Us
www.olduino.wordpress.com

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 210
Posts: 13030
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I have them split into stubs which catch the interrupts and store them in a table, and routines which run periodically out of "Loop" which scan the table and handle the events

Nice!  The essence of a micro-kernel running on a micro-conroller.
Logged

Pages: 1 2 [3] 4 5 6   Go Up
Jump to: