Sunteți pe pagina 1din 18

Blind stick

This project is designed to guide a visually impaired person to walk and avoid bumping into
obstacles. Low cost ultrasonic rangefinders along with a microcontroller is used to measure the
distance to obstacles and if they are close enough provide a feedback to the user in form of beeps
or vibrations.
The project is made on a small single layer PCB. The sensors are not mounted on the PCB but
they are mounted on front of the stick and connected to the main board using wires. All the parts
of project PCB is shown in the image below.

Using the stick is simple, just plug the power bank to the USB plug (refer the image above) and
switch on board using the On/Off Switch. The power indicator LED should glow. The system is
now ready.

For testing purpose keep all the three sensors on flat surface such as ultrasonic beam emitted by
them is horizontal. Make sure their are no obstacles in front of any sensor up-to a distance of 1
meter. Slowly come close to the center sensor until the buzzer starts beeping. For obstacles found
by the center sensor their are two quick beeps. Try to remember this beep patten. Now move
slowly towards the right sensor also make sure their is no obstacle in front of the front sensor.
For obstacles sensed by right sensor it will give three quick beeps. Similarly for left sensor it will
give single beep.

From the block diagram given above you can see that this project has four major parts.

The Power Bank


Finding a good power source for this project was a challenge, the power supply should have to
be mobile, so that we cannot use power adapters. Also it had to be rechargeable so that it is
economical for day long use to. And last but not the least! It had to be low cost. So we picked up
a rechargeable 5v power bank used to charge mobile phones or tablets. Due to mass production
and high demand as a mobile accessory these are dirt cheap! A common 2700mAH power bank
with USB type socket is shown below.

These can be charged in 2hours using a 5v charger. The charger is plugged into the wall socket
and 5v output from the charger is given to the power bank and allowed to charge for 2 hours. The
power bank must be detached from the project while charging.

Ultrasonic Range Finders


These are used to measure the distance to the obstacle. They emit sound waves with their
frequency lying in the ultrasonic spectrum (more than 20Kz) and thus inaudible to human ears.
These sound waves goes to the obstacle and bounces back to the detectors. We use a common
HC-SR04 rangefinder module for this purpose.

PIC Microcontroller
This is the heart of the project. It reads distance to obstacle using the sensor and also commands
the buzzer. There are several member in the PIC MCU family, but we have chosen PIC16F877A
because it is very popular, easily available and is recommended in the academic course of many
universities of Bharat.

Buzzer
A small 10mm diameter 5 volt buzzer is used to alert the user about the obstacles. It beeps once
for a obstacle in left, twice for a obstacle in front and thrice for an obstacle in right. You can also
connect a vibrator motor in parallel with the buzzer. This will provide a vibrational feedback
along with audio beeps.

Bill of Materials (BOM)


S.No Reference
01
R1, R3
02
R2, R4
03
C1, C2
04
C3, C4
05
Q1
06
D1
07
D2

Value
4K7
330 ohms
22pF
0.1uF
BC548
-

08

U1

09
10
11
12
13
14
15
16
17
18

J1
J2
J3
SW1
X1
X5
X2,X3,X4
-

20MHz
5v
-

Part
1/4 Watt Resistor
1/4 Watt Resistor
Ceramic Disc Capacitor
Ceramic Disc Capacitor
Transistor
5mm Round LED GREEN
5mm Round LED RED
PIC16F877A Microcontroller (PRE PROGRAMMED WITH
FIRMWARE)
USB Type A Plug
2 Pin Relimate Connecter
6 Pin Relimate Connecter
Toggle Switch
Crystal Oscillator
Buzzer 10mm Diameter
Vibrator Motor (Optional)
HC-SR04 Ultrasonic Rangefinder Module
5v Rechargeable Power Bank
Charger for Power Bank with Cable

Quantity
2
2
2
2
1
1
1
1
1
1
1
1
1
1
1
3
1
1

Top legend layer

Bottom copper layer

Prototype of PCB

For sensing distance to obstacles, an HC-SR04 sensor module has been used. It has an ultrasonic
transducer which generates the ultra sonic waves, an ultra sonic receiver and control circuitry
built on a small PCB.

Front View of HC-SR04

Back View of HC-SR04


For interfacing with microcontroller it provides two lines namely TRIGGER and ECHO. The
trigger pin is an input pin, the MCU sends a 10uS high pulse on this line to tell the HC-SR04 to
start a taking a measurement.

As soon as the HC-SR04 receives this pulse it sends out ultrasonic waves and waits for it to goto
the obstacle and come back to the sensor. The sensor then emits a pulse on the ECHO line whose
width is equal to this time. By simple calculation we can find the distance to obstacle.

Three such such sensors are used in this project to find obstacle in front, left and right of the user.

/
*****************************************************************************
*
A smart walking stick made for visually impaired persons. Three ultrasonic
range finder (HC-SR04) are used to sense any obstacles that are in front,
left and right of the person. When obstacles are sensed, an audio warning
is given.
Written By
Avinash Gupta
Contact
gmail@avinashgupta.com
For more interesting microcontroller tutorials and projects. Please visit
http://www.extremeelectronics.co.in
NOTICE:
PROGRAM SAMPLE PROVIDED FOR SELF LEARNING PURPOSE ONLY!
NO PART OF THIS WORK SHOULD BE USED IN ANY COMMERCIAL PROJECTS OR IN ANY
TEACHING INSTITUTES FOR TEACHING THEIR STUDENTS
NO PART OF THIS WORK SHOULD BE PUBLISHED IN ANY FORM LIKE PRINTED OR
ELECTRONIC
MEDIA
COPYRIGHT (C) 2008-2015 EXTREME ELECTRONICS, INDIA
*****************************************************************************
*/
#include <xc.h>
#include <stdint.h>
// CONFIG
#pragma config FOSC = HS
// Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF
// Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF
// Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF
// Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = ON
// Low-Voltage (Single-Supply) In-Circuit
Serial Programming Enable bit (RB3/PGM pin has PGM function; low-voltage
programming enabled)
#pragma config CPD = OFF
// Data EEPROM Memory Code Protection bit
(Data EEPROM code protection off)
#pragma config WRT = OFF
// Flash Program Memory Write Enable bits
(Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF
// Flash Program Memory Code Protection bit
(Code protection off)
/********************************************************************
Configuration Area.
UltraSonic (US) sensor connection.
in this example it is connected to as follows
Sensor | MCU
_____________

Trig
Echo

| PC0
| PC1

********************************************************************/
#define US_PORT PORTA
#define US_TRIS TRISA
#define US_TRIG_POS

#define US_ERROR
-1
#define US_NO_OBSTACLE
#define THRESHOLD_DISTANCE

-2
60

//CM

void HCSR04Init()
{
//Set trigger port as output
US_TRIS&=~(1<<US_TRIG_POS);
//Setup Timer1
T1CKPS0=1; //Prescaller = 1:2
}
void HCSR04Trigger()
{
//Send a 10uS pulse on trigger line
US_PORT|=(1<<US_TRIG_POS); //high
__delay_us(15);

//wait 15uS

US_PORT&=~(1<<US_TRIG_POS);
//low
}
/*
Returns the width of pulse in uS (micro seconds)
*/
int16_t GetPulseWidth(uint8_t n)
{
uint32_t i,result;
n++;//since echo lines starts at PORTA1 so convert 0 to 1 and so on
//Wait for the rising edge
for(i=0;i<600000;i++)
{
if(!(US_PORT & (1<<n)))
continue; //Line is still low, so wait
else
break; //High edge detected, so break.
}
if(i==600000)
return US_ERROR;

//Indicates time out

//High Edge Found


TMR1=0x00; //Init counter
TMR1ON=1;
//Start timer
//Now wait for the falling edge
for(i=0;i<600000;i++)
{
if(US_PORT & (1<<n))
{
if(TMR1 > 60000) break; else continue;
}
else
break;
}

if(i==600000)
return US_NO_OBSTACLE;

//Indicates time out

//Falling edge found


//Stop Timer
TMR1ON=0;
result=TMR1;

if(result > 60000)


return US_NO_OBSTACLE;
else
return (result * 0.4);

//No obstacle
// since period of timer is 0.4uS

void Alert(uint8_t n)
{
for(uint8_t i=0;i<n;i++)
{
RB1=1;//Start Vibrator
__delay_ms(50);

RB1=0;//Stop Vibrator
__delay_ms(30);

}
void main (void)
{
int16_t r;
//All PORTA pins are digital input and NOT analog
PCFG2=1;
PCFG1=1;
//Vibrator motor or buzzer i/o port pin as output

TRISBbits.TRISB1=0;
RB1=0;//No alert at startup
HCSR04Init();
int d[3];
while(1)
{
//loop for 3 sensors
for(uint8_t i=0;i<3;i++)
{
//wait for all ECHO line to come down
while(RA1==1);
while(RA2==1);
while(RA3==1);
//Send a trigger pulse
HCSR04Trigger();
//Measure the width of pulse
r=GetPulseWidth(i);

{
}

if(r!=US_ERROR && r!=US_NO_OBSTACLE)


d[i]=(r*0.01718); //Convert to cm
}//For loop of 3 sensor

//Alert
if(d[1]<THRESHOLD_DISTANCE)
{
Alert(2);
}
else
{
if(d[2]<(THRESHOLD_DISTANCE-30))
Alert(3);
else if (d[0]<(THRESHOLD_DISTANCE-30))
Alert(1);
}
__delay_ms(250);
}//main while loop
}

The most important and complex part of this program is the part which measures the distance
using the HC-SR04 sensor. Reading the sensor involves two important steps.

Triggering the sensor.

Measuring the width of pulse on the ECHO line.

From the circuit diagram you can see that we have connected the TRIG lines of all the sensor
together. And this TRIG line is connected to bit 0 of PORTA. We have written a function
HCSR04Trigger() to trigger the sensor. The implementation of this function is very simple. We
just pull the line high by writing 1 to it, then wait for 15uS using the built in delay function
__delay_us() then we pull the line low by writing low to it.
We have not directly manipulated the port pin, because this hinders portability of the code.
Instead we have defined constants using the C's #define directive. This also enhances the
readability of the code. US_PORT (short for Ultrasonic port) conveys much more information to
the reader than PORTA. Also in future due to any reason we can to connect the sensor to PORTC
or PORTD we can simply change this at one location.
123456789101112
void HCSR04Trigger()
{
//Send a 10uS pulse on trigger line
US_PORT|=(1<<US_TRIG_POS); //high
__delay_us(15);
US_PORT&=~(1<<US_TRIG_POS);

//wait 15uS
//low

Above is the complete listing of the function, in the function two constants are defined.
US_PORT and US_TRIG_POS. US_PORT stands for the port name in which the sensor is
connected, its value is PORTA. While US_TRIG_POS stands for the position of trigger pin on
the port. Since we have connected the trigger line to bit 0, its value is 0. Thus these two variable
completely describes the connection pin and makes it easy to change the connection. For
example if you wish to connect the trigger signal to PORTA5 instead of PORTA0 you can simply
change value of US_TRIG_POS to 5.
Switching on and off of the bits is done by the bitwise OR | and AND & operator. For
understanding of it one should be good at C and the bitwise operators.
Once the trigger pulse is sent to the sensor, the MCU waits for a high edge on the ECHO line.
This is done inside the function GetPulseWidth(). Since we have three different sensors (each
for left, right and front obstacle sensing) this function accepts and argument which should be 0, 1
or 2 depending on which sensor you wish to read.
Variable name for this argument is n.
At the start of this function we define two local variables :Variable
i

Use
for looping variable

Variable
result

Use
storing final result of measurement of pulse width

Then we wait for the rising edge on the ECHO line of the selected sensor. Some people use while
loop in such situation, but it has a great disadvantage! Suppose if the sensor wire is broken and
we never get a high edge on the echo line (because the high edge is generated by the sensor, if no
sensor that means no high edge!). In that case we will be waiting forever, from the user's ends it
will appear the the program has hung!
So instead of waiting forever, we wait for a limited number of tries.
Below is the complete listing of the part which waits for a high edge.
1234567891011121314//Wait for the rising edge
for(i=0;i<600000;i++)
{
if(!(US_PORT & (1<<n)))
continue; //Line is still low, so wait
else
break; //High edge detected, so break.
}
if(i==600000)
return US_ERROR;

//Indicates time out

//High Edge Found

At line two we have created a for loop, are we are looping 6,00,000 times, each time checking
the status of bit represented by n on the US_PORT. If n is 1 value of bit number 1 is tested using
simple bitwise & operator of the C language. If the bit is found to be low we continue the loop. If
it is found high, then we break the loop. So their is two ways to reach line # 10. Either we have
just broken the loop due to a high edge detection or the for loop has counted full 6,00,000
iterations. In the second case the value of i would be 6,00,000 so we check it at line #10. If it
happens to be so, that means whole 6,00,000 iterations has been done without getting a high edge
on the MCUs i/o line, it is a clear indication that the sensor has some problem. Either the power
line of sensor is disconnected or the ECHO line from the sensor to MCU is broken or the sensor
has developed any kind of fault. So in this case we end the function here and return an error.
Error values are returned in form of negative integer numbers. These constants are also defined
using C's #define directive.
As soon as we get a high edge on the ECHO line we start the TIMER1 for measuring the width
of this pulse. This is done by first writing 0 to the counter register (TMR1) and then starting the
counter by writing 1 to the TMR1ON bit. This is analogous to pressing the start button of a
stopwatch as soon as players start to run in a running competition.
Timer1 is configured with a prescaler of 1:2, that means its counting frequency is half the CPU
frequency. And CPU frequency is 5MHz (as we are using a crystal oscillator or 20MHz) So the
frequency of the timer is 2.5MHz. That means its period is 0.4 microseconds.

We then wait for the falling edge of the pulse. This is simple, check the i/o line connected to the
ECHO signal output from the sensor, if it is high then continue else if it low then break. As soon
as we break we stop the timer by writing 0 to the TMR1ON bit. And we copy the counter
register TMR1 to the result variable. And we return the value of result variable multiplied by
0.4, as we discussed above that the period of timer is 0.4uS.
Now this function is returning the length of the pulse in microsecond (uS). Its time to convert
this to cm. For this we have to refresh our knowledge of Kinematics and recall the relationship
of speed, time and distance.
We know that speed = distance traveled / time required to travel the distance.
So
distance = speed x time (simple maths!) Eq. 1
And since actual distance to obstacle is only half of the distance traveled by sound
Distance to obstacle = (speed x time)/2 Eq. 2
Speed of sound in air is
34359cm/sec = 0.034359cm/uS
substituting this value in equation 2 we get
Distance to obstacle = (0.034359 x time) /2
or
Distance to obstacle = (0.01718 x time)
So whenever we require the distance, we multiply time as returned by GetPulseWidth()
function by 0.01718

S-ar putea să vă placă și