1

I am relatively new to Arduino platform and not know much. I am working on a Bicycle speedometer with turn and stop indicators.

I am planning on connecting an inductor magnet to calculate the rotation of my front wheel while providing the following services from the same arduino board:

  1. Input horn and turn indicator switches.
  2. Output to turn indicators.
  3. Stop light when one of the brakes is applied.

While I am sure of how to connect all the sensors, except the magnet, I am not sure how to handle the various inputs and the outputs at once.

I must be able to horn and stuff while the indicator blinks at a regular interval all the while the monitor keeps displaying my speed and distance covered.

Any reference or help would be greatly appreciated. Thanks in advance.

Bharath. S.

  • 1
    Count rotations in an interrupt. Monitor user inputs in your loop() whenever you have nothing better to do (which will still be very frequently in human terms). The blink can be implemented either with a time interrupt or by checking elapsed time in the loop, with tradeoffs each way. – Chris Stratton Jul 31 '14 at 15:31
  • 1
    If you're willing to get your hands dirty, try timers. I'm probably going to write a library here soon to do that, so I'll post that if I get around to it. That would help with the blinking the LEDs... – Anonymous Penguin Jul 31 '14 at 18:42
1

How fast do we need to read the magnetic switch to not miss any pulses? I'll make some working assumptions:

  • Using 700c wheel and 28mm tire [assumed; adjust as necessary]
  • Rolling radius 2.1m [from here; there are other ways to arrive at this]
  • Max speed 22 m/sec (50mph), [working assumption; adjust as you see fit]
  • Magnet and switch interact for at most 3% of a rotation, [WAGuess]

The wheel will have to turn at ~10RPS at max speed giving a pulse period of 100ms. The pulse width will be at most 3% of that, or 3ms.

Your service loop would have to execute in somewhat less than 3ms, every time, in order to not miss any wheel pulses and that's if I haven't been too optimistic about the pulse width. I'd personally assume a 1ms maximum loop time, then test it on the road by sampling & logging wheel-pulse level with an Arduino at at least 10x that rate or 10+KHz.

Or I'd go with an interrupt-driven wheel pulse period timer not width) to ease the constraints on the main loop.

The main loop need only poll your turn, brake, and horn switches and a timer for blinking the turn signals. Even if the timing is a little erratic for some reason, no harm is done, and nothing is likely to be apparent to the rider or other road users.

1

You need a finite state machine. Then you can have code that would typically require delay() but without blocking the loop() while it waits.

Here is a crude class I wrote to do it

stateMachine.h

/*
 StateMachine

 Class to perform some state machine logic on the Arduino
*/

#if (ARDUINO >= 100)
 #include <Arduino.h>
#else
 #include <WProgram.h>
 #include <pins_arduino.h>
#endif

class StateMachine 
{
  public:
  // Constructor
  StateMachine(void (*)(void));
  // Functions
  void update(void);
  void nextState(uint16_t, uint32_t);
  uint16_t currentState(void);
  void stop(void);

  private:
  void (*callback)(void);   // Callback to state machine code
  uint16_t state;      // Current state of the machine
  uint32_t delay;      // Delay until state change. Delay of -1 is stopped
  uint32_t timer;      // Timer to keep track of last run time
  uint8_t isRunning;   // Are we running?
  int16_t counter[2];  // Two counters for general use
};

stateMachine.cpp

/*
 StateMachine

 Class to perform some state machine logic on the Arduino
*/

#include "StateMachine.h"

//
// Constructor
//
StateMachine::StateMachine(void (*callbackFunction) (void)) {
  state = 0;
  delay = 0;
  timer = 0;
  isRunning = 0;
  callback = callbackFunction;
  counter[0] = 0;
  counter[1] = 0;
}

//
// Update the state machine
//
// Use in loop()
// Will keep running over and over unless stop()ed
//
void StateMachine::update(void) {
  if (isRunning) {
    if(millis() - timer >= delay) {
      timer = millis();
      //Call the state machine
      callback();
    }
  }
}

//
// Current state
//
uint16_t StateMachine::currentState() {
  return state;
}

//
// Next state
//
void StateMachine::nextState(uint16_t nextState, uint32_t nextDelay) {
  state = nextState;
  delay = nextDelay;
  isRunning = 1;
  //Restart timer
  timer = millis();
}

//
// Stop
//
void StateMachine::stop()
{
  isRunning = 0;  
}

Then you need a function with the logic:

void exampleStateMachineCallback()
{
  switch (exampleStateMachine.currentState()) {
    case 0:
      //initialise everything and then got to state 1 immediately
      exampleStateMachine.nextState(1,0);
      break;

    case 1:
      //do something then do state 2 500ms later
      exampleStateMachine.nextState(2,500);
      break;

    case 2:
      //do something then do state 1 500ms later
      exampleStateMachine.nextState(1,500);
      break;
  }
}

Finally in the global variables we join them up

StateMachine exampleStateMachine = StateMachine(exampleStateMachineCallback);

And in loop() we call update all the time

exampleStateMachine.update();

The states implement your logic. For example, state 1 in the above code could be turn on the led, and state 2 could be turn it off. State 0 might prepare some variables. If you wanted the led to start flashing with a button press it might look like

if(digitalRead(LEFT_BUTTON) == HIGH) exampleStateMachine.nextState(0,0);

And if you wanted to stop it:

exampleStateMachine.stop();

In the StateMachine class I put two counters, you could use these to do other timers. For example, to flash a led for 30 seconds it might look like

void exampleStateMachineCallback()
{
  switch (exampleStateMachine.currentState()) {
    case 0:
      exampleStateMachine.counter[0] = 0;
      exampleStateMachine.nextState(1,0);
      break;

    case 1:
      digitalWrite(13,HIGH);
      exampleStateMachine.nextState(2,500);
      break;

    case 2:
      digitalWrite(13,LOW);
      exampleStateMachine.counter[0]++;
      if (exampleStateMachine.counter[0] >= 30) exampleStateMachine.stop();
      else exampleStateMachine.nextState(1,500);
      break;
  }
}
0

Since I apparently can't comment yet, here's an incomplete but I think useful answer; this is a perspective on how I would go about it: For the brake lights it's pretty easy to just put it in a loop that 'if brakes, brake light on'. I would say keep everything in one loop, no interrupts or anything. If an indicator switch is on, the loop gets the current time with millis(), sets a flag to on, and turns on the light. It then loops like normal, checks the flag and if sufficient time has passed turns off the light, gets a new time, and unchecks the flag. If i understand your needs correctly, the rest is just 'if input high, output high' that you can check every time through the loop. Can't help with the magnet though, no experience there.

-1

Since your post mentioned that you are relatively new to Arduino, in case you have not done below, you may start by

a) get a printed book, ebook or 'well structured' tutorial, says, systematically covering 10 to 20 topics instead of short tutorial on just one topic

b) this will get you covered for your task 1 to 3, but, only as individual tasks.

c) after mastering (b), try to combine them, instead of stand alone in tutorial

d) interrupt is advance topic and not be cover in many starting books. You can see http://arduino.cc/en/Reference/attachInterrupt Interrupt works only on certain pins, depending on which Arduino board model.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.