Tachometer for my bike

Posted on
  • Just want to share my idea, what I gonna do with the Puck when it arrives:
    Last week, I bought my new bike. Normally, I don't need a tachometer. But I'm still interested, how much kilometres I have ridden the past year.
    So my idea is to connect the Puck to a reed contact and count the wheel ticks. If needed, I can use my smartphone to read out the kilometres.

  • The Puck has a magnetometer (compass), it can detect a magnet nearby. So a magnet on a wheel could be used to count the rotations. No reed switch or other hardware required.

  • Sounds like a great idea!

    The magnetometer on the Puck is handy, but it only outputs readings 80 times a second. I did a quick check and at 20 km/hr a typical wheel should be rotating 2.5 times a second, so it should work well enough.

    However, when running at that speed it draws a bit of power (1mA, so only 200 hrs battery life), so you'd have to be careful to only turn it on for high speed readings when it thought the bike was moving.

    In many ways just using a reed switch (especially if you used one off a cheap bike computer that's all set up for it) would be easier. You then don't have to worry about power consumption at all, as Puck.js will only wake up when it detects the input change state.

  • Both sound very promising.
    I could use the switch to activate/deactivate the magnetometer.

    Do the IO ports have internal pull-up or pull-down resistors? How should the reed contact be connected to the Puck for lowest power consumption?
    Am I right that I can use also my Espruino Pico to do the first tests to bridge the time until December? Are there any major differences between Pico and Puck I have to take into account? (besides no BT LE :-) )

  • Do the IO ports have internal pull-up or pull-down resistors?

    Yes, they have both - and they're switchable with software - simply use pinMode(pin, 'input_pullup') and connect the contact between GND and the pin, and you're done.

    Am I right that I can use also my Espruino Pico to do the first tests

    Yes, absolutely. Stuff like setWatch and pinMode are identical.

    Are there any major differences between Pico and Puck

    Not in terms of how you write the software. Just define the pins you're using as variables right at the top of your code (var REEDSW = A7;, etc) so you can swap the pins over, and you should be sorted.

  • I see the convenience of using the magneto meter... but what about having a deep sleep with a setWatch() on a pin with a coil connected (...of course with reverse voltage and spike suppression)? Would that not yield a better battery life?

  • First prototype is working :-)

    var circumference = 2.11;
    var pin = BTN;
    
    var counter = 0;
    var last_counter=0;
    var last_time=0;
    var velocity=0;
    
    
    var w=setWatch(function(e) {
      counter++;
      },
      pin,
      {repeat: 'true', edge:'rising'}
    );
    
    function getDistance() {
      return counter * circumference;
    }
    
    var i=setInterval(function(){
      var current_time=getTime();
      var current_counter=counter;
      velocity=(current_counter-last_counter)*­circumference/(current_time-last_time);
      last_time=current_time;
      last_counter=current_counter;
    }, 1000);
    

    My new bike computer cable will arrive on Saturday.

  • ...you may actually vary your interval depending on your cal culated speed... within the counter loop... Since the event knows about the time since lat event, you can speed up or down... and extend battery life... and even more sophisticated: intervalling based on the increase/decrease of the acceleration and deceleration...

  • Great! Actually, if you looked at the time between pulses, rather than the number of pulses in a period, I guess you might get a more accurate speed value?

    but what about having a deep sleep with a setWatch() on a pin with a coil connected

    Hmm, maybe - but then why not just use a reed switch instead of the coil and you could do everythig, with great battery life :)

  • reed switch...

    dooohhhh... the 'mechanic' version of hall switch / magneto'meter' / magneto-schmitt-trigger!

  • Sorry, I don't understand the discussion regard reed switch or not.

    I modified the code so that the interval timer is deactivate if the speed is 0. It's activated again by the first rotation: https://github.com/avanc/espruino-tachom­eter/blob/master/tachometer.js

    @Gordon: Is it not cheaper to calculate the speed just every few seconds than adding more logic into each wheel turn? In addition, caluclating the time in the watch function, I get some problems:

    lastTime is the time in seconds at which the pin last changed state. When using edge:'rising' or edge:'falling', this is not the same as when the function was last called.

  • Is it not cheaper to calculate the speed just every few seconds

    Well it would be if your wheel was turning quickly, but I think the maximum speed it'll do is around 5 revs per second, so it's not a big deal.

    IMO the problem is because it's not turning that fast, it's hard to accurately tell what speed it's going just by counting rotations. Suppose it is going round 5 times a second, and you test every 2 seconds - that means you'll only have counted to 10 - so the speed you're getting is only 10% accurate.

  • lastTime is the time in seconds at which the pin last changed state. When using edge:'rising' or edge:'falling', this is not the same as when the function was last called.

    Yes, but it's easy enough to work around?

    var lastTime;
    var RPM;
    var w=setWatch(function(e) {
      RPM = 60 / (e.time - lastTime);
      lastTime = e.time;
      counter++;
      },
      pin,
      {repeat: 'true', edge:'rising'}
    );
    
  • Is it not [power] cheaper to calculate the speed just every few seconds than adding more logic into each wheel turn?

    Absolutely, but you can go for a middle ground: you just store the times away and keep doing what you do every 30..60..90 seconds. This way you do insignificantly prolongate the power-on state per wheel rotation, but have good data to calculate / prep/ update (prep an update) for a graph in desired intervals and may be show it graph on a nokia 5110 (or better) on demand... managing the back lighting accordingly... Don't know the e-paper power consummation on update... (see e-paper GDE021A1 display).

  • Thank you both for the quick responses.
    I like the idea of removing the interval:
    https://github.com/avanc/espruino-tachom­eter/blob/f0a45a866a77ee9ad4a05aedd50cc0­3f38c4974c/tachometer.js

    Adding an e-paper is also an interesting idea. I have to see were to get one :-)

    A general question on using Espruino:
    Is it better (faster, less memory usage, ...) to initialise everything as I did in my example and then doing a save()?
    Or writing an init function:

    E.on('init', function() {
      // Initialise functions/variables and setWatch()
    });
    
  • Nice idea removing setInterval - I'd thought you might need it to detect 0 RPM, but you're right - you can check lastTime when you go to get the RPM value.

    onInit stuff doesn't make that much difference in terms of memory usage or efficiency really. I'd actually be tempted to stay with what you're doing, as it makes it easier for you to 'tweak' things later on if you want to.

    The only bad point is that if you had an LCD or some external hardware that needed initialisation, you'd still need onInit to handle that.

  • Hello,

    this weekend I got my reed switch from Sigma and connected it to my pico (GND and B3). As proposed, I set the pin to input_pullup and wrote a basic watch function:

    setWatch(function(e) {
      pincounter++;
      console.log(pincounter+"\n");
      },
      B3,
      {repeat: 'true', edge:'rising', debounce:10}
    );
    

    Now I get some strange behaviours with different options:
    edge: 'rising' no debouncing
    Most of the time two events when moving magnet to sensor and one when moving away.

    edge: 'rising', debounce: 10
    One event when moving magnet to sensor and one when moving away. The same for debounce 100 and 1000.

    edge: 'falling', no debounce
    Three events when moving magnet to sensor and no event when moving away.

    edge: 'falling', debounce: 10
    No events at all.

    Not exactly what I expected. Am I right that it seems that the reed switch only closes very short but not keep closed while the magnet is next to the sensor?

  • Just for completeness: I did a clearWatch() before each evaluation to be sure there is no other event listener.

  • ...I'm baffled... I could understand some bouncing... but that is weird...

    1. What does the data sheet of the switch say about how the magnet should be positioned and moved?
    2. What do you know about the magnet? ...its magnetic field?

    falling is definitively the right thing with your circuit setup. Worst case you have to do some 'debouncing' yourself... using fuzzy logic...

    In our case you get a rapid sequence of ons and then nothing for a while... if you just take the first one and ignore all others within a particular time frame. Not an elegant solution, but it may work, since you know that it is a wheel that can run only within a particular speed range.

    Debouncing is not an easy thing, as other users noticed in their conversations: here (1) and here (2).

  • A reed switch will tend to 'bounce' because it's a mechanical contact.

    What can happen is that it bounces so fast that the underlying hardware detects a change, but by the time the software gets to check the pin state it has changed again.

    If you're using pullup I'd just to a watch on the falling edge of the signal, and would then just ignore anything that happens less than 50ms after the first detected pulse. You could use debounce but it could get thrown off by the very quick changes I said about above.

    You're storing lastTime anyway, so it should be pretty easy:

    var lastTime;
    var RPM;
    var w=setWatch(function(e) {
      if (e.time<lastTime+0.05) return;
      RPM = 60 / (e.time - lastTime);
      lastTime = e.time;
      counter++;
      },
      pin,
      {repeat: 'true', edge:'rising'}
    );
    
  • Thanks for the hints. I got it working with the 50ms downtime.
    Will do the final tweaking when the contact is assembled to the bike.

  • Interestingly, BT LE already provides a service for Cycling Speed and Cadence Service (CSCS). I collected some information:
    https://github.com/avanc/espruino-tachom­eter/issues/1

    Looking forward for information on the Espruino JS interfaces for Bluetooth LE :-) I'm still confused, how pairing is done in general and how to define GATT services.

  • Nice - it should be pretty easy to get Espruino to output to CSCS, and then (hopefully) it'll be compatible with other cycling apps.

    It depends what you want though - if you're just trying to communicate with your own app (web or not), you might find that you're making more work for yourself by trying to adhere to the Bluetooth standard :)

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Tachometer for my bike

Posted by Avatar for avanc @avanc

Actions