Speed of a wheel measurement, light effect and sound effect

Hello my friends

I am going to try to explain my project first and then put my code and see if I can get some help.

My project is to measure the speed of a bike and the lighting effect happens to different speeds of the wheel. For example if the speed is below 15mph the RGB LED will lit red and when the speed gets to over 30mph the LED will lit Green and so on, and at the same time when the speed gets to 30mph I wanted a sound to be played.

Now in my case I was able to do the speed measurement and the lighting effect perfectly, now the problem is when I add the code for the SD card or sound, it doesn't work properly. When I combined the codes even the light only lit green which means it ain't working properly. so what I did was I tried to so make the 2nd part or the sound effect on another Arduino board and Voila the speed measurement and the lighting effect works except there is no sound playing at 30mph.

So what I think I am doing a mistake is on the I2C communication between the 2 Arduinos, I connected them like in A4 and A5 of the 2 Arduinos and common ground for both of them as well, but the code doesn't seem write. Can some body help me by directing me into a right direction please, Thanks a lot.

Code for the Master Arduino or the Speed and Lighting effect

//calculations
//tire radius ~ 10 inches
//circumference = pi*2*r =~62.8 inches
//max speed of 35mph =~ 616inches/second
//max rps =~7.25

#include <FastLED.h>
#define hallPin  2//pin connected to read switch
#define LED_PIN 7
#define NUM_LEDS 256
#include <Wire.h>

CRGB leds[NUM_LEDS];


//storage variables
float radius = 10;// tire radius (in inches)- CHANGE THIS FOR YOUR OWN BIKE
int ledpin = 3;
int hallVal;
long timer = 0;// time between one full rotation (in ms)
float mph = 0.00;
float circumference;
int x = 0;
//boolean backlight;

int maxhallCounter = 100;//min time (in ms) of one rotation (for debouncing)
int hallCounter;


void setup(){

  hallCounter = maxhallCounter;
  circumference = 2*3.14*radius;
  pinMode(LED_PIN,OUTPUT);
  pinMode(ledpin,OUTPUT);
  pinMode(hallPin, INPUT);
//  pinMode(Speaker, OUTPUT);
 
  FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);
  FastLED.setBrightness(32);
//  checkBacklight();
  
//  Serial.write(12);//clear
  
  // TIMER SETUP- the timer interrupt allows preceise timed measurements of the reed switch
  //for mor info about configuration of arduino timers see http://arduino.cc/playground/Code/Timer1
  cli();//stop interrupts

  //set timer1 interrupt at 1kHz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;
  // set timer count for 1khz increments
  OCR1A = 1999;// = (1/1000) / ((1/(16*10^6))*8) - 1
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS11 bit for 8 prescaler
  TCCR1B |= (1 << CS11);   
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);
  
  sei();//allow interrupts
  //END TIMER SETUP
  
  Serial.begin(9600);
  // Start the I2C Bus as Master
  Wire.begin(); 
}


ISR(TIMER1_COMPA_vect) {//Interrupt at freq of 1kHz to measure reed switch
  hallVal = digitalRead(hallPin);//get val of hall sensor
  if (hallVal==LOW){//if reed switch is closed
    if (hallCounter == 0){//min time between pulses has passed
      mph = (53.8*float(circumference))/float(timer);//calculate miles per hour
      timer = 0;//reset timer
      hallCounter = maxhallCounter;//reset hallCounter
    }
    else{
      if (hallCounter > 0){//don't let reedCounter go negative
        hallCounter -= 1;//decrement reedCounter
      }
    }
  }
  else{//if reed switch is open
    if (hallCounter > 0){//don't let reedCounter go negative
      hallCounter -= 1;//decrement reedCounter
    }
  }
  if (timer > 2000){
    mph = 0;//if no new pulses from reed switch- tire is still, set mph to 0
  }
  else{
    timer += 1;//increment timer
  } 
}


void loop(){
  if(hallVal == LOW){
    digitalWrite(ledpin, HIGH);
  }
  else{
    digitalWrite(ledpin, LOW);
  }
  //print mph once a second
  Serial.println(mph);
  if (mph == 0) {
    for(int i=0; i<=255; i++){
      leds[i] = CRGB(0,0,0);
    }
    FastLED.show();
  }
  if (mph <= 15 && mph>0) {
    for(int i=0; i<=255; i++){
      leds[i] = CRGB(255,0,0);
    }
    FastLED.show();
  }
  if (mph <= 30 && mph>15) {
    for(int i=0; i<=255; i++){
      leds[i] = CRGB(255,105,0);
    }
    FastLED.show();
  }
  if (mph > 30) {
    for(int i=0; i<=255; i++){
      leds[i] = CRGB(0,255,0);
    }
    FastLED.show();
  }
  int x = digitalRead(mph);
  Wire.beginTransmission(9); // transmit to device #9
  Wire.write(x);              // sends x 
  Wire.endTransmission();    // stop transmitting
  x++; // Increment x
  if (x > 30) x = 0; // `reset x once it gets 30
//  delay(500);
}

And here is the code for the slave Arduino or for the sound

#include <SD.h>
#define SD_ChipSelectPin 4
#include <TMRpcm.h>
#include <SPI.h>
#define Speaker 9
#include <Wire.h>


int x = 0;
TMRpcm tmrpcm;
char mychar;

void setup() {
  // put your setup code here, to run once:


   pinMode(Speaker, OUTPUT);
// Start the I2C Bus as Slave on address 9
   Wire.begin(9);
// Attach a function to trigger when something is received.
   Wire.onReceive(receiveEvent);
  
tmrpcm.speakerPin = 9;
if(!SD.begin(SD_ChipSelectPin)){
  Serial.println("SD fail");
  return;
} 
tmrpcm.setVolume(5);
}

void receiveEvent(int howMany){
  while (1 < Wire.available()){
    char c = Wire.read();
    Serial.print(c);
  }
  int x = Wire.read();  //read one character from I2C
  Serial.println(x);
}

void loop() {
  // put your main code here, to run repeatedly:
if (x == 30){
  digitalWrite(Speaker, HIGH);
  tmrpcm.play("23.wav");
  delay(3000);
   }
   else{
    digitalWrite(Speaker, LOW);
    delay(100);
   }
}

A few things off the top of my head.

What type of Arduino boards?

Are you using the correct pins for I2C SDA / SCL?

Do you have the required pullup resistors for SDA ? SCL?

Have you tested that the sound even works on the second board (i.e. triggered locally, not via I2C)?

Why does your variable x (in slave code) have such a poor name?

Why isn't your variable x (in slave code) declared 'volatile' (receiveEvent is really an ISR)?

Why is your variable x (in slave code) an integer? How many different command will you be sending?

Hello Gfvalco

I will try to give you a precise information of all of the questions,

  • The Arduino boards are both UNO

  • Yeah I think I am using the correct pins which are Analog A4 and Analog A5 on both of the Arduino UNO boards.

  • I don't have a pull up resistors for SCL or SDL, and if I have to how much of a resistor should I put, I didn't know that I was supposed to use a pull up resistor.

  • yes I have tested the sound on the Arduino slave alone and works perfectly.

  • I didn't get what you meant when u said a poor name for the int x?

  • If I have to change the int x or volatile into something else what should I do it, because I tried it float but it turns out that I can't transmit a floating number only a byte.

  • The only command that should go the slave Arduino board is just when the counting or the mph gets to 30mph (miles per hour).

Thank you for your reply, can you please give some more hints?

Thank you for your reply, can you please give some more hints?

Yes. Quit trying to use I2C. Create, on each Arduino, an instance of SoftwareSerial, and you can easily send text/binary data back and forth.

PaulS:
Quit trying to use I2C. Create, on each Arduino, an instance of SoftwareSerial, and you can easily send text/binary data back and forth.

Agree to disagree. SoftwareSerial is notoriously flaky. I2C transactions are handled in hardware and the interface seems idea for the limited amount of info that must be transferred (play sound / don't play sound).

Hello guys

Thank for your help, so you recommend me to use serial communication like Tx and Rx instead of this. Okay then I will try it using Serial and I ill let you know if I get any change.

Hello Guys

I tried to work it out using Serial communication but I failed. Look at my code, and I couldn't think of how to represent the character that I want to be transmitted from Arduino 1 to Arduino 2. Can you please see and tell me what changes I should make thank you for you help.

Here is the codes I tried to modify from the previous one, here I am trying to use Serial RX and TX

Master Code or Speed and lighting codes.

#include <FastLED.h>
#define hallPin  2//pin connected to read switch
#define LED_PIN 7
#define NUM_LEDS 256

CRGB leds[NUM_LEDS];


//storage variables
float radius = 10;// tire radius (in inches)- CHANGE THIS FOR YOUR OWN BIKE
int ledpin = 3;
int hallVal;
long timer = 0;// time between one full rotation (in ms)
float mph = 0.00;
float circumference;
char x = 30;
//boolean backlight;

int maxhallCounter = 100;//min time (in ms) of one rotation (for debouncing)
int hallCounter;


void setup(){

  hallCounter = maxhallCounter;
  circumference = 2*3.14*radius;
  pinMode(LED_PIN,OUTPUT);
  pinMode(ledpin,OUTPUT);
  pinMode(hallPin, INPUT);
 
  FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);
  FastLED.setBrightness(32);
//  checkBacklight();
  
//  Serial.write(12);//clear
  
  // TIMER SETUP- the timer interrupt allows preceise timed measurements of the reed switch
  //for mor info about configuration of arduino timers see http://arduino.cc/playground/Code/Timer1
  cli();//stop interrupts

  //set timer1 interrupt at 1kHz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;
  // set timer count for 1khz increments
  OCR1A = 1999;// = (1/1000) / ((1/(16*10^6))*8) - 1
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS11 bit for 8 prescaler
  TCCR1B |= (1 << CS11);   
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);
  
  sei();//allow interrupts
  //END TIMER SETUP
  
  Serial.begin(9600);
//  Serial1.begin(9600);
  // Start the I2C Bus as Master
//  Wire.begin(); 
}



ISR(TIMER1_COMPA_vect) {//Interrupt at freq of 1kHz to measure reed switch
  hallVal = digitalRead(hallPin);//get val of hall sensor
  if (hallVal==LOW){//if reed switch is closed
    if (hallCounter == 0){//min time between pulses has passed
      mph = (53.8*float(circumference))/float(timer);//calculate miles per hour
      timer = 0;//reset timer
      hallCounter = maxhallCounter;//reset hallCounter
    }
    else{
      if (hallCounter > 0){//don't let reedCounter go negative
        hallCounter -= 1;//decrement reedCounter
      }
    }
  }
  else{//if reed switch is open
    if (hallCounter > 0){//don't let reedCounter go negative
      hallCounter -= 1;//decrement reedCounter
    }
  }
  if (timer > 2000){
    mph = 0;//if no new pulses from reed switch- tire is still, set mph to 0
  }
  else{
    timer += 1;//increment timer
  } 
}



void loop(){
  if(hallVal == LOW){
    digitalWrite(ledpin, HIGH);
  }
  else{
    digitalWrite(ledpin, LOW);
  }
  //print mph once a second
  Serial.println(mph);
  if (mph == 0) {
    for(int i=0; i<=255; i++){
      leds[i] = CRGB(0,0,0);
    }
    FastLED.show();
  }
  if (mph <= 15 && mph>0) {
    for(int i=0; i<=255; i++){
      leds[i] = CRGB(255,0,0);
    }
    FastLED.show();
  }
  if (mph <= 30 && mph>15) {
    for(int i=0; i<=255; i++){
      leds[i] = CRGB(255,105,0);
    }
    FastLED.show();
  }
  if (mph > 30) {
    for(int i=0; i<=255; i++){
      leds[i] = CRGB(0,255,0);
    }
    FastLED.show();
  }
  char x = digitalRead(mph);
  Serial.write(x);

}

Code for the Sound

#include <SD.h>
#define SD_ChipSelectPin 4
#include <TMRpcm.h>
#include <SPI.h>
//#define hallPin 2
#define Speaker 9


char x [10];
TMRpcm tmrpcm;
//char mychar;

void setup() {
  // put your setup code here, to run once:


   pinMode(Speaker, OUTPUT);

  Serial.begin(9600);
  
tmrpcm.speakerPin = 9;
if(!SD.begin(SD_ChipSelectPin)){
  Serial.println("SD fail");
  return;
} 
tmrpcm.setVolume(5);
}



void loop() {
  // put your main code here, to run repeatedly:
 
  Serial.readBytes(x,5);
  Serial.println(x);
if (x == 30){
  digitalWrite(Speaker, HIGH);
  tmrpcm.play("23.wav");
  delay(3000);
   }
   else{
    digitalWrite(Speaker, LOW);
    delay(100);
   }
}

Still the same observation after the speed get to 30mph there is no sound although the lighting is working perfectly. Thanks a lot for your time.

Hello

Is there any ideas that I can make changes to my code please. I tried the I2C and Serial communication but still not working.

Any help will be much appreciated

Thank you.

hey Gfvolvo

I tried a lot of things on serial communication but I wasn't able to get any change my speed and the lighting effect are working good, but when it gets to the second Arduino it is not even responding to anything. Can you please help me here, thank you.

You only have one sound right? So you only have one bit of data. Your information to be transmitted is just "start now" or "don't".

Use one wire and digitalWrite(). The slave can digitalRead().

Don't forget to connect the grounds.

Hello MorganS

Yeah I only have one sound, but the thing is the SD card module is connected in the slave Arduino or receiver, so I think they are not communicating to each other as I can see it.

What are you advising me to do? Are you saying I should use the serial Rx and TX or I2C?
And if you have seen my code can you please let me know what changes I should do on the serial communication part? What I am getting confused is when sending data to second Arduino I don't know what character or byte or number to put in.

The idea of the project is when the speed measurement which is on the 1st Arduino gets to 30mph I wanted a data to be transmitted to the second Arduino so that the 2nd Arduino can play sound.

Thank you for your time Morgan I really appreciate it.

Hello Guys

Has anyone got any idea about my issue on the serial communication between 2 arduinos and how to transmit data from 1st Arduino to the 2nd Arduino? Please?

Yepino:
Hello Guys

Has anyone got any idea about my issue on the serial communication between 2 arduinos and how to transmit data from 1st Arduino to the 2nd Arduino? Please?

What do you need help with? xxSerial.print() and xxSerial.read() and xxSerial.available() are all you need. You know what you print (send), so you know how much to read.

No, I'm suggesting you use a single piece of wire (plus a ground.) No communication of bytes or anything fancy. Just on and off, HIGH and LOW.

Okay Guys

First thanks for your help, and as you said Morgan I have tried it with one wire which is TX of the Master to the RX of the receiver and a common ground I even powered the receiver Arduino from 5v of the Master Arduino.

What I can't figure out is that what character or number should I send using serial.read() and what to put on the serial.write().

I got confused because when I tried to send the mph (miles per hours) it doesn't let me compile it says invalid sending of array or something like that. When I tried to define a new character and then send that character to the receiver it doesn't do anything no sound at all I am guessing it is not sending anything.

If you look at my code there is something missing on the serial.read() and Serial.write() and the character or byte to be sent. I would appreciate if you help me there thanks a lot.

Hello PaulS

That's what I am missing here I don't know what to print. I mean I know what I want to print is the speed or the mph of the wheel, and then send that speed to the receiver Arduino well I was thinking to send only when the mph gets to 30mph and then make a sound and if the speed is less that 30mph then no sound.

This is what I want, can you please guide me to the right direction thank you.

For example look at this guys it says no matching function for hardware Serial (float), and this is on the receiver Arduino because mph is floating. These are the thing that I am struggling.

Capture.PNG

Hello guys

I have tried it so many time but I can't figure it out, I really need your help especial on the data or speed in mph to be sent to the receiver Arduino. If you want to check my sketch I can send it again thank you for your cooperation.

Hello

After trying so many experiments on the project I tried something and I figured the error might be on the code of the receiver Arduino.

Here is what I tried now, I thought what if I try to connect the hall sensor in the receiver Arduino only now I using 1 Arduino and try to interface the Sensor speed (or speed of the wheel in mph) to sound effect. Which means I got rid of the Lighting effect focus on the 2nd Arduino only.

Here is my code and I will explain what the out come of this code is:

#include <SD.h>
#define SD_ChipSelectPin 4
#include <TMRpcm.h>
#include <SPI.h>
#define hallPin  2
#define Speaker 9

int value;
TMRpcm tmrpcm;
char mychar;
float radius = 10;// tire radius (in inches)- CHANGE THIS FOR YOUR OWN BIKE
int ledpin = 3;
int hallVal;
long timer = 0;// time between one full rotation (in ms)
float mph = 0.00;
float circumference;


int maxhallCounter = 100;//min time (in ms) of one rotation (for debouncing)
int hallCounter;

void setup() {
  // put your setup code here, to run once:

   hallCounter = maxhallCounter;
   circumference = 2*3.14*radius;
   pinMode(ledpin,OUTPUT);
   pinMode(hallPin, INPUT);
   pinMode(Speaker, OUTPUT);
   

  // TIMER SETUP- the timer interrupt allows preceise timed measurements of the reed switch
  //for mor info about configuration of arduino timers see http://arduino.cc/playground/Code/Timer1
  cli();//stop interrupts

  //set timer1 interrupt at 1kHz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;
  // set timer count for 1khz increments
  OCR1A = 1999;// = (1/1000) / ((1/(16*10^6))*8) - 1
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS11 bit for 8 prescaler
  TCCR1B |= (1 << CS11);   
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);
  
  sei();//allow interrupts
  //END TIMER SETUP
  
  Serial.begin(9600);
  
tmrpcm.speakerPin = 9;
if(!SD.begin(SD_ChipSelectPin)){
  Serial.println("SD fail");
  return;
} 
tmrpcm.setVolume(5);
}

ISR(TIMER1_COMPA_vect) {//Interrupt at freq of 1kHz to measure reed switch
  hallVal = digitalRead(hallPin);//get val of hall sensor
  if (hallVal==LOW){//if reed switch is closed
    if (hallCounter == 0){//min time between pulses has passed
      mph = (56.8*float(circumference))/float(timer);//calculate miles per hour
      timer = 0;//reset timer
      hallCounter = maxhallCounter;//reset hallCounter
    }
    else{
      if (hallCounter > 0){//don't let reedCounter go negative
        hallCounter -= 1;//decrement reedCounter
      }
    }
  }
  else{//if reed switch is open
    if (hallCounter > 0){//don't let reedCounter go negative
      hallCounter -= 1;//decrement reedCounter
    }
  }
  if (timer > 2000){
    mph = 0;//if no new pulses from reed switch- tire is still, set mph to 0
  }
  else{
    timer += 1;//increment timer
  } 
}

void loop(){
  if(hallVal == LOW){
    digitalWrite(ledpin, HIGH);
  }
  else{
    digitalWrite(ledpin, LOW);
  }

  Serial.println(mph);
  if(mph>15){
    digitalWrite(Speaker, HIGH);
    tmrpcm.play("23.wav");
    delay(3000);
  }
  else if(mph ==0 && mph <=15){
    digitalWrite(Speaker, LOW);
    delay(100);
  }
}

So what The out come was:

  1. The speed doesn't look like to count as it was counting in the first one when there was master and receiver Arduino. It seems like it is only counting up to 15. something mph, and because of that you can see in my loop function in my if statement I changed the if (mph >30) to if (mph >15) any way.

  2. The second problem is that the sensor is counting and the sound is triggered when the speed gets to 15mph but it doesn't stop playing even when the speed drops down to 0 mph. I guess this has something to do with the delays I have put in there.

Now, my question is if I figure out to correct this, do you think that even with the master and receiver Arduino there is a chance for the project to work?

Thank you again.

Don't print or send any character.

  if(ifTimeToPlayTheSound()) {
    digitalWrite(pin_number, HIGH);
  } else {
    digitalWrite(pin_number, LOW);
  }
  if(digitalRead(pin_number)) {
    playSound();
  }