PDA

View Full Version : Questions on ultrasonic distance finder



lilimike
- 10th March 2010, 21:07
Hi,

I am at the begining of my project, actually I spent 1 week trying to make the LCD work properly so that tels me that I have a long way to go.

I am using a 16F627A (just because that's what I have on hand) if a better chip is suggested I can change it.
I have found a number of designs on the Web and read quite a few treads on forums, not that I want to reinvent the wheel but I would rather make my own design although I am taking some parts of interesting code here and there.

I do have a few questions to get me going. Based on the attached file, this is pretty much the simplest flowchart I could come up with and next to it is my understaning of what needs to happen as far as signal however I am no sure about the following details:

I presume that between T1 and T2 there has to be a burst of 40k times per second but I don't know how long it should last.

Ditto for the listening time between T3 and T4 and I guess the length of time it is listening is partly related to the range I can detect as long as I have enough transmitting and receiving power.

Please correct me if I am wrong but I figure I only want to start listening at T3 because I don't want the receiver to pickup vibrations from the transmiter since they are both on the same PCB.

What I have seen so far can take care of a ranges from a few centimeters to a few meters but I would like my range to be 6 cm to 6 meters so I understand I have to add some amplification at the receiver using op-amps and probably I have to increase power to the transmitter but how do I increase the Tx power? by raising the voltage?

and one last question (for now) when I detect an echo, do I calculate the time from T1 or T2?

I don't really need more than +/-20 cm of precision at 6 meters but I do need a minimum of 2 or 3 cm at 6 cm.

Here is where I am at with the code which basically I can see 40Khz on the scope and I know the LCD works. Like I said, I have a long way to go...


@ __config _XT_OSC & _WDT_OFF & _MCLRE_ON & _LVP_OFF & _CP_OFF

DEFINE OSC 4
TRISB = 0 ' Make PORTB all outputs
TRISA = %10 ' A0 = send burst, A1 = listen to echo
CMCON = 7 ' Disable comparator
FLAGS = 0
T1CON = %00000001 ' enable Timer1 prescaler 1:1

disTance var byte
ECHO var PORTA.1
Cycles var byte

LCD_DB4 VAR PORTB.0 ' Set port for 4 bits bus
LCD_DB5 VAR PORTB.1
LCD_DB6 VAR PORTB.2
LCD_DB7 VAR PORTB.3
LCD_RS VAR PORTB.5 ' Set RS bit port
LCD_E VAR PORTB.4 ' Set Enable bit port
LCD_Lines CON 2 ' # of Lines on LCD, 1 or 2 (Note: use 2 for 4 lines)
LCD_DATAUS CON 50 ' Data delay time in us
LCD_COMMANDUS CON 2000 ' Command delay time in us
INCLUDE "LCD_AnyPin.pbp" ' Must go after LCD initialization
Pause 500: LCDOUT $FE,1: pause 250 ' clear screen and relax
LCDOUT $FE,$80,"Distance Finder"

goto start

asm
_Pulse
bsf PORTA,0 ; change to whatever port pin you have available
goto $+1 ; 2uS per GOTO $+1
goto $+1
goto $+1
goto $+1
goto $+1
bcf PORTA,0
goto $+1
goto $+1
goto $+1
goto $+1
goto $+1
decfsz _Cycles,f
goto _Pulse ; 25uS total for 40kHz carrier
RETLW 0 ; return to CALLing routine
ENDASM

Start:

' start timer ...

' send burst ...
Cycles = 8 ' number of carrier cycles to generate
CALL Pulse
PAUSEUS 24

' Listen for echo ...

' timed out...

' count number of time outs ...

' update display
gosub display_upd

GOTO start


Display_UPD:
LCDOUT $FE,$C0,"Distance = ",dec disTance," "
return

end

Kamikaze47
- 11th March 2010, 15:45
what hardware setup are you going to use?

i have built one of these before. ive attached a pic if you are interested.

the main problems i faced was to do with the detection of the reflection. i never managed to get the adc to detect a reflection, so i used amplification circuits and a comparator to detect the reflection and trigger an i/o pin.

the detection part of my circuit was from this site:

http://www.best-microcontroller-projects.com/pic-sonar.html

I found, however that the transmitter side of that one wasn't great. the best result i got was from using an inductor to build up much larger voltages across the transducer.

My results were good. I get +/- 1cm at most ranges. By changing the sensitivity of the detector I can shift the effective range. If i set it more sensitive, i get longer range but lose ability to detect short distances. If i set it less sensitive i can get shorter ranges but not long range.

6cm may be tricky tho. the shortest range ive managed is around 15cm.

I generate the pulse for 150uS. I found that for my purposes (not needing short range stuff at all - just ranges over 1m), i then wait about 1.5mS before looking for a reflection. Its best to experiment with different times to get the best result for you.

Hope some of this helps you.

Acetronics2
- 11th March 2010, 16:23
Hi, Kamikaze,

What a Bins to download the files from that site !!! ...

and , in the end ... you get a code to download the " LCD + Keyboard " project ...

Someting to correct, I wonder ...

Alain

Kamikaze47
- 11th March 2010, 16:28
Not sure about that. I didn't use any of the code from that site - i wrote my own in PBP.

All i used from that site was the receiver amplification/detection part of the circuit shown there.

lilimike
- 11th March 2010, 17:33
Hi Kamikaze,

I guess the answers to my questions is test and evaluate, in this case I am on the right track.

I started to design arround This guy's project (http://www.massmind.org/images/www/hobby_elec/e_pic6_6.htm) but I was never able to observe what I was expecting on the scope for the input amplification stages and I was not completely understanding what I was doing so I've decided to start with the basics and found this link from Les Johnson (http://www.docstoc.com/docs/22237623/ultrasonic-experiment-using-ultrasonic-sensor) which is really basic and I am having some difficulties understanding 100% of his code but I do get the basics.

I am pretty close to a newbe with PBP Pro and PICs, but I am really good at playing sounds on piezzo and blinking LEDs and I think now I am good with LCDs so like I said, I have a long way to go.

I was wondering if it is better to do more hardware and less code or vice versa but I guess the opposite is better since it is faster to change code than it is to change hardware, I am just not sure yet where I have to draw the line.

I am presently intensivelly playing with timers and interupts and I must say I am having a lot of fun trying to understand but as I am doing this on an average of 16 hours per day, I should get the hang of it in no time.

While I am at it maybe if someone can explain something; in my code I have

CMCON = 7 ' Disable comparator
INTCON = $80 ' Disable interupts
T1CON = 0 ' Timer1 off, prescaler 1:1


and then I do this:


TMR1H = 0:TMR1L = 0
T1CON.0 = 1
PAUSEUS 1
LCDOUT $FE,$80,"TMR1H = ", dec TMR1H
LCDOUT $FE,$C0,"TMR1L = ", dec TMR1L

I get: TMR1H = 4 and TMR1L = 23

What I understand from the datasheet is TMR1H cycles when TMR1L overflows so the value I am getting is actually:
4 x 65535 +23 ?

how did it get do far with PAUSEUS 1 ?

Then if I do PAUSEUS 2
I get: TMR1H = 4 and TMR1L = 24

I am confused!

Mike

Kamikaze47
- 11th March 2010, 17:39
TMR1H increments when TMR1L overflows at 256. So its 4x256+23.

Keep in mind that the timer will run at 1/4 the frequency of your main oscillator.

edit: also, pauseus 1 will not result in a 1us pause because pauseus has a minimum pause time. have a look at pauseus in the PBP manual.

Ioannis
- 11th March 2010, 23:01
Do you really have to built it yourself?

Look at the http://www.robot-electronics.co.uk/acatalog/Ultrasonic_Rangers.html

Once I had to built that ranger in 1990 but then I could not find ready made modules.

After a few year I tested the modules of the above link and was surprised.

First of the idea to drive the Tx US transducer by the well known MAX232 chip (it can produce fast +/- 10 volts of pulses!) and second by its simplicity and performance.

Ioannis

lilimike
- 12th March 2010, 00:11
Well the main reason why I want to build it myself is to learn everything about it, I really like the challenge and when I go to bed just about every other day or so I sleep well because I like the feeling of having learned something new.

Now trying to calculate and figure how I got this result on my display is probably going to keep me up for a few days because even after Kamikaze's response I am still confused. Maybe it's all about the timing differences between the speed my brain works and the speed of a PIC at 4MHz.:rolleyes:

Or maybe I am trying to calculate something that is uncalculatable!

Kamikaze47
- 12th March 2010, 03:37
OK, if you are running your PIC at 4MHz, then the timer will run at 1MHz, which means that TMR1L will increment every 1uS (when the prescale is set to 1:1).

timing the command PAUSEUS 1 will not give you a result of 1 becuase of 2 reasons. First, PAUSEUS has a minimum pause time and 1uS is so fast that the time it takes to check the timer value comes into play.

Try this:

temp VAR word

TMR1H=0 ' Reset timer value
TMR1L=0
T1CON.0=1 ' Start the timer
PAUSEUS 1000 ' Pause 1000uS
T1CON.0=0 ' Stop the timer
temp.HighByte=TMR1H
temp.LowByte=TMR1L
LCDOUT $FE,$80,"TMR1 = ", dec temp

The LCD should display somewhere around 1000 - Probably a little more because of the time it takes to start and stop the timer.

lilimike
- 12th March 2010, 04:49
you are absolutely right, 1001 is what I get.

I am sorry if I ask again about the timing but are you able to explain this?

if I keep the timer running, I removed the PAUSEUS and I do something like this:

LCDOUT $FE,$80,"H",dec TMR1H,"L",dec TMR1L,"H",dec TMR1H,"L",dec TMR1L

The first set of H/L I get 401
The second set I get 4604

Why it isn't the second set taking arround 800?
Is it because the actual calculation is based on the assembly and when it is compiling it is doing funny things?

Kamikaze47
- 12th March 2010, 05:00
Its possible that the LCDOUT routine really is taking that long.

But ive found that its generally best to stop the timer to take a reading, and usually best to store that reading in a variable before displaying it, or doing anything else with it.

See what happens if you do it like this:


temp VAR word

TMR1H=0 ' Reset timer value
TMR1L=0
T1CON.0=1 ' Start the timer
pauseus 1000
T1CON.0=0 ' Stop the timer
temp.HighByte=TMR1H
temp.LowByte=TMR1L
T1CON.0=1 ' Restart the timer
LCDOUT $FE,$80,"TMR1 = ", dec temp
T1CON.0=0 ' Stop the timer
temp.HighByte=TMR1H
temp.LowByte=TMR1L
LCDOUT $FE,$C0,"TMR1 = ", dec temp

The difference between the 2 results will tell you how long the first LCDOUT routine is taking.

lilimike
- 12th March 2010, 20:18
...well I am getting closer to the numbers I am expecting but...

My values were 1001 and 4206 so it took 3205 to perform LCDOUT.

Then I restarted the timer just before the last LCDOUT and added this to your code and got a value of 7405

T1CON.0=0 ' Stop the timer
temp.HighByte=TMR1H
temp.LowByte=TMR1L
LCDOUT $FE,$80,"TMR1 = ", dec temp

So the second time LCDOUT executed it took 3199
I did it a third time and found a different number again.

So LCDOUT executed 3 times and it took less time everytime it executed.

1st time took 3205
2nd time took 3199
3rd time took 3187

I figured writting to the LCD on a blank line took 3205
overwriting on the first line of the LCD took 3199
and overwritting on the second line took 3187

But I did it a fourth time (overwrote on the first line) and it took 3312
This is the code I ended up with:

temp VAR word
TMR1H=0 ' Reset timer value
TMR1L=0
T1CON.0=1 ' Start the timer
pauseus 1000
T1CON.0=0 ' Stop the timer
temp.HighByte=TMR1H
temp.LowByte=TMR1L
T1CON.0=1 ' Restart the timer
LCDOUT $FE,$80,"TMR1 = ", dec temp
T1CON.0=0 ' Stop the timer
temp.HighByte=TMR1H
temp.LowByte=TMR1L
T1CON.0=1 ' Restart the timer
LCDOUT $FE,$C0,"TMR1 = ", dec temp
T1CON.0=0 ' Stop the timer
temp.HighByte=TMR1H
temp.LowByte=TMR1L
T1CON.0=1 ' Restart the timer
LCDOUT $FE,$80,"TMR1 = ", dec temp
T1CON.0=0 ' Stop the timer
temp.HighByte=TMR1H
temp.LowByte=TMR1L
T1CON.0=1 ' Restart the timer
LCDOUT $FE,$C0,"TMR1 = ", dec temp
T1CON.0=0 ' Stop the timer
temp.HighByte=TMR1H
temp.LowByte=TMR1L
LCDOUT $FE,$80,"TMR1 = ", dec temp


This beeing said, if I start over from the begining, no matter how many times I am always getting the same results so this rules out a bad resonator or voltage noise or any othe hardware issue.

So there is something in the process that is hapenning which is irregular and I wish I could understand what it is!

I am really sorry to be such a pain and I appreciate your patience but I am still a little confused.

Mike

Dave
- 12th March 2010, 20:57
lilimike, A answer to your question is in the delays you have programmed into the LCD DEFINES. Just look at what you have....

LCD_DATAUS CON 50 ' Data delay time in us
LCD_COMMANDUS CON 2000 ' Command delay time in us

Everytime you send a cursor command proceeded with $FE your code is waiting 2 milliseconds...

Dave Purola,
N8NTA

lilimike
- 12th March 2010, 21:21
Hi Dave,

This I can understand that the LCDOUT command is taking time to do what it has to do and it is configured with some delays but what i don't understand is why it is taking a different time each time I send data to LCDOUT.
(I've never wrote the word "time" so many times in so little time in my life)

Could it be that it is the LCD's controller itself that is taking a different time to generate different data?

Maybe it is faster to write 1 than 8?

Maybe I am trying to find the solution in the PIC process but the solution is actually in the LCD process?

Kamikaze47
- 13th March 2010, 05:05
The difference between 3205, 3199, 3187 and 3312 is really not a lot when you think that this is measured in microseconds.

The command you are timing is this:

LCDOUT $FE,$80,"TMR1 = ", dec temp

The time this takes will depend on the value of temp. As temp increases, it takes longer to convert it into a decimal number (dec temp), and as the decimal number increases in number of digits, it takes slightly longer to write it to the screen.

What happens if you reset the timer value each time? Try adding TMR1H=0 and TMR1L=0 just before each time you start the timer.

lilimike
- 13th March 2010, 13:21
If I reset the timer I will obviously always get the same value because temp will always display the same value.
So I rewrote the code to this:

staticVal var word
temp VAR word
TMR1H=0 ' Reset timer value
TMR1L=0

T1CON.0=1 ' start the timer
pauseus 1000
T1CON.0=0 ' Stop the timer

staticVal = 70
T1CON.0=1 ' start the timer
LCDOUT $FE,$80,"TMR1 = ", dec staticVal
T1CON.0=0 ' Stop the timer
temp.HighByte=TMR1H
temp.LowByte=TMR1L
LCDOUT $FE,$C0,"Disp Time = ", dec temp

and I specified different values to display in staticVal.
It turns out that displaying 1 to 9 took 3819 ms
to display 10 to 29 and 40 to 49 took 3944 ms
to display 30 to 39 and 50 to 69 took 3938 ms
and so on...

So you are right, this confirms that the difference of time LCDOUT is taking to display is based on which value is beeing displayed. This makes me wonder because technically it is always computing 4 bit at a time but at least now I know what is going on and I thank you for your help and your patience.

Mike

jellis00
- 19th March 2010, 03:59
I don't really need more than +/-20 cm of precision at 6 meters but I do need a minimum of 2 or 3 cm at 6 cm.


You could save yourself a lot of time, heartache and coding efforts by using one of the commercially available ultrasonic rangers that outputs a pre-calulated measurement (in inches or cm) down to 1 cm accuracy for less than $25. The one I have had a lot of success with is the SRF02 (see this URL: http://www.robotshop.com/srf02-ultrasonic-range-finder-2.html?utm_source=google&utm_medium=base&utm_campaign=jos. I have been very impressed with the performance of this device, but it does have one idiosyncracy when using an I2C bus to communicate with it.

If you decide to use this product, let me know and I can share some PBP code with you that has been pre-tested to work with the SRF02.

mtripoli
- 19th March 2010, 04:50
I've used these sonic devices for a bunch of different projects. One thing that you have to pay attention to is the mechanical aspect of the transducers. They have to be rigidly fixed to the PCB and enclosure. Hanging off the pins as shown in your picture can cause all kinds of problems.

These things continue to "ring" after they've been pulsed. Many dampening circuits are available for electrically clamping the transducer. At the very least, wrap a small piece of felt around the body of the transducer, with a piece of dense foam around that (the dense weather stripping with an adhesive back is an ok place to start; buy it in a hardware store, something like 20' for $5.00). You can (and probably should) place a small plastic can around the transducer to make it more directional.

Years ago when my kids were younger we built a small robot for the science fair. It tooled around on its own through the crowd not bumping into anyone (people thought it was remote control). Anyway, we put the transducers in small plastic film cans with the pins sticking out the bottom. Line the film can with some thin felt (adhesive back - buy it at the craft store). Then take a piece of dense foam the same width as the transducer cut to length so that it wraps once and push it down around the transducer. We spaced the transducers so that they looked like "eyes". We also stuck some high brightness leds in there... you can experiment with the distance between the two. We used the full length of the film can but you can try cutting them back a little at a time until you get the response you want.

You will be amazed at the difference in performance.

RussMartin
- 18th April 2010, 06:28
The one I have had a lot of success with is the SRF02. . . . If you decide to use this product, let me know and I can share some PBP code with you that has been pre-tested to work with the SRF02.

I'm going to be working with the SRF02. I'd be interested in knowing what you developed. I assume it was I2C and not serial?

jellis00
- 20th April 2010, 21:19
I'm going to be working with the SRF02. I'd be interested in knowing what you developed. I assume it was I2C and not serial?

I am attaching a routine I use as an Interrupt Service handler with Darrel Taylor's DT_INTS-18.bas. Whenever the interrupt is received it executes this routine to take an ultrasonic range measurement, display it to LCD, and log it to EEPROM.

Note that I am using an I/O pin from the MCU to turn on and off power to the SRF02. Whenever the SRF02 is turned off but still connected to the I2C bus it will distort the bus and prevent use of any other devices that are connected to I2C. Therefore, just before and after you want to use the I2C bus for any device, you will have to turn on or off the SRF02. I did this to save battery power so I didn't have to keep the SRF02 continuously powered up.
Hope this works for you.


Range:
HIGH ext_pwr ' Temporarily turn on power to SRF02 for I2C bus use
PAUSE 500 ' Delay to let I2C bus stabilize after SRF02 turn on
'DEFINE WRITE_USED 1 'Required if only writing WORD variables in v2.6
' Update day counter and address offset for day's measurements
READ 9,day_cnt ' Test if EEPROM data has been captured
' & cleared by PC & new monthly epoch
' started.
day_cnt = day_cnt + 1 ' Increment day counter
Write 9,day_cnt 'Update contents of day_count memory address
Pause 10
If J >= 240 Then
J = 0 ' If allocated EEPROM already used, start over
ENDIF
' Make SRF02 Range Measurement
I2CWRITE SDA,SCL,$E0,0,[80] ' Request start of ranging in inches
pause 100 ' Wait for ranging to finish
I2CREAD SDA,SCL,$E0,2,[rng1,rng0] ' Get ranging results
'WRITE 253,rng1
'Write 254,rng0
WRITE 240,Word w0 ' Write range to EEPROM
' Display time & range measurement on LCD display in inches
LCDOut $FE,1:FLAGS=0:Pause 250 ' Clear Display
I2CREAD SDA, SCL, RTCdevice, SecReg,[sec,MINs,hr,day,date,mon,yr]
LCDOUT $fe,1
LCDOUT $fe,Line1,Hex2 mon,"/",hex2 date,"/",hex2 yr
LCDOUT $fe,Line2,hex2 hr,":",hex2 MINs,":",hex2 sec
Pause 2000 ' Allow Time for user to view
LCDOUT $FE,1
LCDOut $FE,Line1,"Range:" ' Display on 1st line
LCDOut $FE,Line2,#w0," in." ' Display on 2nd line
PAUSE 5000 ' Allow Time for user to view
' Clear STATUS register & Alarm flags..ready for next interrupt
I2CWrite SDA, SCL, rtcdevice, StatusReg,[$00]
LOW ext_pwr ' Turn off power to the SRF02 at end of display.
' This statement will distort the I2C bus and ext_pwr
' must be set HIGH again before any attempts are made to
' use the I2C bus.
' Store range as date-stamped value in EEPROM
WRITE 17+J,WORD w0 'Store day's range in EEPROM
PAUSE 10
Write 16+J,date ' with day of month date-stamp
PAUSE 10
' Step pointer to next logging address in EEPROM
J = J + 3
WRITE 10,J 'Update contents of J index EEPROM memory address
Pause 10
PAUSE 470 ' Delay to permit I2C bus to stabilize after SRF02 off
' Resume Main Program
@ INT_RETURN