Hey guys, this is my first practical project using arduino or any microcontroller for that matter. My area of expertise is not programming or electrical, so this is very difficult for me.
So i have an old speedometer that used to run a mechanical drive unit. My motorcycle does not have this provision, therefore it has to be converted to electric drive. My plan is to use a hall effect sensor on the brake rotor to sense wheel speed and with simple dimensional analysis convert that to vehicle speed and send that to the servo driving the speedo needle.
I have found the rpm tutorial on the arduino website to be very helpful in configuring the setup to read frequency on the hall sensor. I was able to run the serial monitor on a bench test and read rpm and frequency in Hz. My problem is then using a linear function to convert to speed and output to the servo.
With the way i have it setup in the photo, rotating the wheel does nothing to the servo. The servo just sits at ~0 degrees and pushes against its own gears... In addition, the wheel speed does not change its behavior at all.
Im sure my problem is in the code; im a total beginner with all programming languages.
Please help. I would like to have a functional speedometer. Thanks!
#include <Servo.h>
Servo myservo;
// read RPM then output value to servo to display speed on a gauge face
int half_revolutions = 0;
int rpm = 0;
int speed = 0;
int needleangle = 5;
unsigned long lastmillis = 0;
void setup(){
myservo.attach(9);
Serial.begin(9600);
attachInterrupt(0, rpm_fan, FALLING);
}
void loop(){
if (millis() - lastmillis == 200){ //Uptade every one second, this will be equal to reading frecuency (Hz).
detachInterrupt(0);//Disable interrupt when calculating
rpm = half_revolutions * 60; // Convert frequency to RPM, note: this works for one interruption per full rotation. For two interrups per full rotation use half_revolutions * 30.
speed = rpm*.068423; // Convert wheel rotations to theoretical vehicle speed
needleangle = speed*1.55; // Convert speed to gauge needle angle
myservo.write(needleangle); // Write value to servo
Serial.print("RPM =\t"); //print the word "RPM" and tab.
Serial.print(rpm); // print the rpm value.
Serial.print("\t Speed =\t"); // print the word "Speed"
Serial.print(speed); // print speed.
Serial.print("\t Hz=\t"); //print the word "Hz".
Serial.println(half_revolutions); //print revolutions per second or Hz. And print new line or enter.
half_revolutions = 0; // Restart the RPM counter
lastmillis = millis(); // Uptade lasmillis
attachInterrupt(0, rpm_fan, FALLING); //enable interrupt
}
}
// this code will be executed every time the interrupt 0 (pin2) gets low.
void rpm_fan(){
half_revolutions++;
}
If you ever miss the millisecond where the elapsed time is 200 you won't trigger again for over a month. You should change "== 200" to ">= 200". You should also change the comment that says that 200 mS is one second.
Ok great. I made the changes. Thank you for the tips John.
Is there any way using an interrupt can interfere with the way the servo should function?
In the past i tried this project using an adafruit gps, but i could never get it to work as something would cause interference with the function of the servo causing it to respond very erratically. Im worried that the issue might persist here with this setup.
Hey Robin, thanks for the corrections. I tried needleangle = 90; and it writes to 90 degrees just fine. Then i tried simply saying needleangle = 1 + speed*3/2 and now the servo is not trying to commit suicide. The needleangle function past 0 rpm is not yet verified.
I was finally able to take the laptop out to the garage and check hall input to verify function was similar to the bench tests i conducted using the magnet mounted to a drill. Unfortunately no. Serial monitor show 0 rpm and frequency across the board, im assuming my hall sensor's minimum frequency is greater than how fast i can turn the front wheel by hand; about 60 rpm. Im not quite sure how to test this. I cant hold my laptop while i ride down the street... Its too bad there isnt an integrated datalogger on the uno.
Additionally i checked the output of the hall sensor using a multimeter. With the 5v supply voltage to the hall sensor, i yield .35 volts and when triggered it falls to around .05 volts. Under these conditions, FALLING is the correct trigger mode for the interrupt?
Ah. Your hall effect is not working quite the way you should have it.
I suspect your hall effect device is quite a good expensive hall effect sensor which can accurately detect the strength of a magnetic field, whereas what would be more useful would be a hall effect switch like this one.
Whilst it has to be very precisely located, so that it does trigger (you have a 1 to 3 mm tolerance for location) it either does 0 or 5V.
I completely agree with you that a switch would have probably been much easier to setup. On the other hand the aging roads of california provide some pretty rough conditions sometimes. I need something to be very secure and reliable considering the amount of vibrations this mounting location will experience.
I will look up the specifications of my sensor to determine what the correct output looks like.
ChilliTronix:
Bluejets, am I right in thinking that your hall effect is a hall effect switch rather than sensor?
The tacho has gone through a couple of changes since the original.
When I started, the only hall effect I could get was the UGN3503 which is a sensor, not a switch. To overcome this I connected it using an LM311 comparator. This then fed the LM2917 frequency to voltage converter which originally drove a series of LEDs in a circular pattern around the tacho readout.
Picaxe then came along and i was looking for an alternative, more realistic unit.
Rather than change everything, I decided to retain the above and use the 0-5V and drive a servo which has a gear driven output to give me 270 degree needle travel.
Nowadays I tend to stick with the allegro 1120 which is a switch.
I'll see what I can find but unfortunately we had a massive flood here 2 years ago (biggest in recorded history) and all my records on file went with the dirty water.