OutoSoft

Odd Software for Odd Jobs

Bike Sonar, 2nd test run

Took it for a quick test run this morning. No traffic around so I couldn't properly test it, so I rode past some parked cars instead!

Here's a screen grab from the Fly6 video.

Fly6 screengrab

An idea for a different implementation - replace the LED display with a Bluetooth module and feed the data to an app on my phone. This would be an opportunity to both figure out how to implement BT in my Arduino projects and also how to write an iOS app.

Anyway, refinement continues. I will probably replace the LeoStick with an Arduino Nano clone so I can run it off a 9V battery and thus enclose the ultrasonic sensor, Arduino and battery in a more-waterproof Jiffy box or similar. I could probably do the Bluetooth version at the same time so the whole sonar would be in a single box - much less fiddly.

I'm having fun regardless of how useful this may turn out to be!

Bike Sonar, Arduino code

Here's the Arduino code of the prototype I've got running on my bike after a bit of cleanup.


// Simple "bike sonar" ... aka rear parking sensor for a bicyle Winking
// Version 1.1, Brett Hallen, 2016
// Uses: HR-SC04 ultrasonic sensor,
// MAX7219 LED driver,
// four-digit LED display,
// and a piezo buzzer (Jaycar AB-3459)
// Implemented on my bike using a Freetronics LeoStick - requires 5V
// so powered with a "USB battery bank"

// http://playground.arduino.cc/Main/LedControl
#include "LedControl.h"

// http://playground.arduino.cc/Code/NewPing
#include "NewPing.h"

/* ---------------> Sonar Stuff <--------------- */
#define triggerPin 7
#define echoPin 6
#define maxDistance 400 // the HR-SC04 has a max range of about 450cm
#define triggerDistance 100 // when to trigger buzzer, in cm
#define pingDelay 50 // pause between sonar pings
NewPing sonar(triggerPin,echoPin,maxDistance);

/* ---------------> LED/MAX7219 Stuff <--------------- */
#define Din 8
#define CS 9
#define CLK 10
LedControl lc = LedControl(Din,CLK,CS,1);

/* ---------------> Speaker Stuff <--------------- */
#define speakerPin 12

void setup()
{
int i = 0;

// for verification of ping result to serial monitor
Serial.begin(115200);

// initialise the LEDs
lc.shutdown(0,false);
// Intensity between 0 (lowest) and 16 (highest)
lc.setIntensity(0,10);
lc.clearDisplay(0);

// Bit of fancy "I'm powering on, running setup()" indication
// print 0123 on LED
for (i=0;i<=3;i++)
{
lc.setChar(0,i,i,false);
delay(100);
lc.setChar(0,i,' ',false);
}
// print 3210 on LED
for (i=3;i>=0;i--)
{
lc.setChar(0,i,i,false);
delay(100);
lc.setChar(0,i,' ',false);
}

// initialise speaker output
pinMode(speakerPin, OUTPUT);

// setup done
playTone(500,700);
}

void loop()
{
// pause between sonar pings
delay(pingDelay);

// send a ping
int uS = sonar.ping();

// calculate distance in cm
int distance = uS / US_ROUNDTRIP_CM;

// print distance on the LED
printDistanceOnLED(distance);

// object closer than minimum distance?
if (triggerDistance > distance)
{
// closer the object, the faster the 'beeps'
int toneDelay = distance * 5;
// turn on LEDs
lc.shutdown(0,false);
playTone(toneDelay,500); // beep
delay(toneDelay); // pause
playTone(toneDelay,500); // beep
}
else if (250 < distance)
{
lc.shutdown(0,true);
}
}

void printDistanceOnLED(int distance)
{
int metres = distance / 100;
distance = distance - metres * 100;
int cms_tens = distance / 10;
int cms_ones = distance % 10;

// only display digits if non-zero
// no need for thousands digit
lc.setChar(0,0,' ',false);

// display hundreds digit?
// yes if it is non-zero
if (metres)
{
lc.setDigit(0,1,(byte)metres,false);
}
else
{
lc.setChar(0,1,' ',false);
}

// display tens digit?
// yes if it is non-zero or we already have displayed the hundreds digit
if ((cms_tens) || (metres))
{
lc.setDigit(0,2,(byte)cms_tens,false);
}
else
{
lc.setChar(0,2,' ',false);
}

// display ones digit?
// yes if it is non-zero, or we already have displayed the hundreds or tens digit
if ((cms_ones) || (cms_tens) || (metres))
{
lc.setDigit(0,3,(byte)cms_ones,false);
}
else
{
lc.setChar(0,3,' ',false);
}

// for verification to serial monitor
Serial.print(metres); Serial.print("."); Serial.print(cms_tens); Serial.print(cms_ones); Serial.println("m");
}

// duration in milliseconds, frequency in Hertz
// http://michael.thegrebs.com/2009/03/23/playing-a-tone-through-an-arduino-connected-piezo/
void playTone(long duration, int freq)
{
duration *= 1000;
int period = (1.0 / freq) * 1000000;
long elapsed_time = 0;
while (elapsed_time < duration) {
digitalWrite(speakerPin,HIGH);
delayMicroseconds(period / 2);
digitalWrite(speakerPin, LOW);
delayMicroseconds(period / 2);
elapsed_time += (period);
}
}

Bike Sonar, part 4

So this is what I've ended up with for mounting on my bike - bit of wood, a lot of cable ties, a bit of galvanised steel and some bolts (that has holes that perfectly lined up with where my red reflector was).

2016-01-16 15.17.33

Bike Sonar

2016-01-16 15.18.05

The display is mounted so that the distance is captured on video by my Cycliq Fly6.

I made the mistake of running the LeoStick from a 9V battery - whoa, that smelt bad when it blew! Silly mistake - I'd earlier used an Arduino Nano clone that happily ran off a 9V and had assumed the LeoStick was the same (when you assume, you make an ass out of u and me … but just me in this case).

So down to Jaycar to grab another LeoStick. But how to power it? There's no 5V batteries - could I used 6V directly? Probably not - I'd have to add a voltage regulator to my circuit to knock it down to 5V - a bit of a re-design after all that fiddly soldering I did!

But then got the idea to use one of those USB battery banks you can recharge your phone with.

Unfortunately, the battery bank I got is too clever … it can tell a phone isn't plugged in and so switches off. As a workaround, I have to plug my phone into the second USB output socket (shaking head).

I took it for a test ride … and it worked! Unfortunately, the cycling infrastructure around where I live is pretty good - lots of bike paths, so I didn't really get a chance to ride on the road. But I simulated by riding up close to parked cars.

First thing I realised … an LED display is not much use in the middle of the day! Not bright enough. Anyway, made some tweaks and did a static test after I got home.

Bike Sonar, part 3

Now, the idea seems to work on a breadboard.

To properly test it, I need to move it to something that can be attached to a bike and powered off a battery.

My original idea was to have the Arduino, ultrasonic sensor, LED display driver mounted on one circuit board at the back of the bike and the LED display mounted remotely on the handlebars.

Bike sonar, original plan

Slept on it, then decided to use a Freetronics LeoStick with the ultrasonic sensor mounted above it on a ProtoStick. The piezo buzzer, LED display and driver IC would then be mounted separately and I'd use my Cycliq Fly6 to record the results.

Bike sonar, new plan


This is what I ended up with - my original breadboard prototype at the top and the bike-ready prototype at the bottom:

2016-01-16 11.53.52

I had an old DSLAM serial-port cable handy with a handy ten-pin connector so I used that to link the two circuit boards.

Moving to the LeoStick required some port changes … note to self … solder the components to the ProtoStick first … and THEN solder in the male header pins (damn amateur).

Anyway, it worked pretty much straight away! Phew.

Next step - somehow mounting it on my bike!

Bike Sonar, part 2

The Arduino is coded up and it seems to be working!

Here's the Arduino code - pretty simple.

(sorry, I don't know how to display code all fancy-like at the moment!)


#include "LedControl.h"
#include "NewPing.h"

/* ---------------> Sonar Stuff <--------------- */
#define triggerPin 12
#define echoPin 10
#define maxDistance 400
NewPing sonar(triggerPin,echoPin,maxDistance);

/* ---------------> LED Stuff <--------------- */
#define Din 7
#define CLK 8
#define CS 9
LedControl lc = LedControl(Din,CLK,CS,1);

/* ---------------> speaker Stuff <--------------- */
#define speakerPin 11

#define triggerDistance 100 // cm
int i = 0;

void setup()
{
Serial.begin(115200);

// LEDs
lc.shutdown(false,0);
lc.setIntensity(0,8);
lc.clearDisplay(0);
for (i=0;i<=3;i++)
{
lc.setChar(0,i,i,false);
delay(100);
lc.setChar(0,i,' ',false);
}
for (i=3;i>=0;i--)
{
lc.setChar(0,i,i,false);
delay(100);
lc.setChar(0,i,' ',false);
}

pinMode(speakerPin, OUTPUT);

}

void loop()
{
delay(50);
int uS = sonar.ping();
int distance = 0;
int toneDelay = 0;

distance = uS / US_ROUNDTRIP_CM;
printDistanceOnLED(distance);
toneDelay = distance * 4;


if (triggerDistance > distance)
{
playTone(toneDelay,500);
delay(toneDelay);
playTone(toneDelay,500);
delay(toneDelay);
}
}

void printDistanceOnLED(int distance)
{
int metres = 0;
int cms = 0;
int cms_tens = 0;
int cms_ones = 0;

metres = distance / 100;
distance = distance - metres * 100;
cms_tens = distance / 10;
cms_ones = distance % 10;

// only display digits if non-zero
if (0 != metres)
{lc.setDigit(0,1,(byte)metres,false);}
else
{lc.setDigit(0,1,' ',false);}

if ((0 != cms_tens) || (0 != metres))
{lc.setDigit(0,2,(byte)cms_tens,false);}
else
{lc.setDigit(0,2,' ',false);}

if ((0 != cms_ones) || ((0 != cms_tens) || (0 != metres)))
{lc.setDigit(0,3,(byte)cms_ones,false);}
else
{lc.setDigit(0,3,' ',false);}

lc.setDigit(0,0,' ',true);

Serial.print(metres); Serial.print("."); Serial.print(cms_tens); Serial.print(cms_ones); Serial.println("m");
}

// duration in mSecs, frequency in hertz
// http://michael.thegrebs.com/2009/03/23/playing-a-tone-through-an-arduino-connected-piezo/
void playTone(long duration, int freq) {
duration *= 1000;
int period = (1.0 / freq) * 1000000;
long elapsed_time = 0;
while (elapsed_time < duration) {
digitalWrite(speakerPin,HIGH);
delayMicroseconds(period / 2);
digitalWrite(speakerPin, LOW);
delayMicroseconds(period / 2);
elapsed_time += (period);
}
}

Bike Sonar

Hi! This is my first attempt at a blog, so bear with me!

The easiest way I find of learning something new is to have an idea of something you want to create and then go about implement it, learning the pitfalls and how to solve them. I've never been any good at just reading a book and then creating some software.

So where I live in Australia, the government is introducing new laws this year regarding safe passing distances for cars & bicycles. Simply, allow a 1m gap. It's obviously not something you need to get out a ruler and measure but rather to get the mindset that pedestrians are a lot easier to kill than cyclist, and cyclists are a lot easier to kill than motorists. So just think and be courteous to other road users, regardless of their means of transport … no one person owns the road or has any greater rights.

Anyway, this gave me an idea to implement a simple little sonar for my bike. Essentially it's just a 'rear parking sensor' for a bike! The idea is if a car gets too close then an audible warning can be given to the cyclist. It also has a display so that the actual distance can be captured by a video camera, like the Cycliq Fly6.

Maybe this will be of interest to someone else. Like I said, it's pretty simple. And there's no doubt similar things already out there - this was just something so I could practise going from initial idea to prototype and then refine.

Step one. Get all the parts and put it together on a breadboard for testing to see if it'll actually work.

I used the following:

  • Adafruit USB-Boarduino
  • HR-SC04 ultrasonic sensor
  • four-digit seven-segment LED display (labelled "CPS02841AR", common cathode)
  • Maxim MAX7219 LED display driver (plus 68kΩ resistor, 10μF electrolytic and 100nF ceramic capacitors)
  • Freetronics piezo buzzer

First step was just wiring it all up. Here is the result:

Bike Sonar, prototype 1

Next step is to write the code for the Arduino to run it all and test.