使用Python进行超声距离测量 – 第1部分
-
超声波传感器
LED,蜂鸣器和开关是人们尝试与Raspberry Pi相连接的最常见的项目。在某宝中发现的有点不同的是超声波测量模块。这允许您测量距离最近的墙壁或固体物体的距离。这些模块很容易买到,便宜而且比较直接的连接到GPIO头。
所以这里有一些关于我的超声测量模块和Python的实验的信息。在未来的项目中,我可以看到这些模块是向Pi动力机器人或汽车添加一些智能的好方法。
HC-SR04模块的成本约为3-4yuan,是一个匹配的大小。其设计由5V供电,具有1个输入引脚和1个输出引脚。该模块通过向空中发送超声波脉冲并测量反弹所需的时间来工作。该值可以用于计算脉冲行进的距离。
连接到Pi
为模块供电很简单。只需将+ 5V和Ground引脚连接到Pi的GPIO接头上的引脚2和引脚6。
模块上的输入引脚称为“触发”,用于触发发送超声波脉冲。理想情况下,它需要一个5V信号,但它与GPIO的3.3V信号工作正常。所以我将触发器直接连接到GPIO头上的引脚16(GPIO23)。
您可以在RPI上使用任何您喜欢的GPIO引脚,但您需要注意引用并相应地修改您的Python脚本。
模块的输出称为“回波”,需要更多思考。输出引脚为低电平(0V),直到模块进行距离测量。然后将此引脚设置为高电平(+ 5V),使脉冲返回相同的时间。所以我们的脚本需要衡量这个引脚保持高电平的时间。该模块对“高”使用+ 5V电平,但是对于仅适用于3.3V的GPIO头上的输入,该模块太高。为了确保Pi只能用3.3V命中,我们可以使用基本的分压器。这是由两个电阻组成。
如果R1和R2相同,则电压被分成两半。这将给我们2.5V。如果R2是R1的两倍,那么我们得到3.33V,这是很好的。所以理想情况下,您希望R2位于R1和R1 x2之间。在我的示例电路中,我使用了330和470欧姆的电阻。一个替代方案是使用1K和1K5值。如果不用也可以 ,但不保证不bug
这是我的最后一个电路图。我选择了GPIO23和GPIO24,但您可以使用GPIO头上的17个可用GPIO引脚中的任何一个。只要记住更新脚本。
超声波模块电路
这是我的电路照片。我用了一小块面包板和一些男对女跳线。
超声波传感器电路
Python脚本
现在脚本实际上要做一些测量。在这个例子中,我使用的是Python。为什么Python?这是Pi最喜欢的语言,所以我倾向于将它用于所有的实验,但是这里的技术很容易应用于C.
您可以直接使用此链接 或通过Pi上的命令行下载脚本:
wget https://bitbucket.org/MattHawkinsUK/rpispy-misc/raw/master/python/ultrasonic_1.py
然后可以使用以下命令运行:
sudo python ultrasonic_1.py
声音的速度
用于找到距离的计算依赖于声音的速度。这随温度而变化。脚本根据预定义的温度计算要使用的正确值。如果需要,您可以更改此值,或者使用温度传感器动态测量该值。
相片
以下是我通过GPIO头连接到Raspberry Pi的超声波传感器的一些照片:
准确性
这里有一些关于准确性的一些观点:
-
距离测量的精度取决于时间。Linux下的Python不适合精确的时序,但是对于一般的操作,它可以正常工作。为了提高准确性,您需要开始使用C代替。
-
当配置GPIO时,模块需要一段时间才能完成第一次读取,所以我在脚本开始时添加了0.5秒的延迟。
-
传感器具有广泛的灵敏度。在杂乱的环境中,由于对象在模块的侧面,您可能会读取更短的读数。
-
测量时间可达2厘米左右。低于这个限度,结果可以给出奇怪的结果。
-
如果超声波传感器接触任何东西,结果是不可预知的。
感谢这项技术,我现在知道从我的桌子到天花板的距离是155厘米。
如果不用上面的代码 可以复制如下代码进行测试。我是在树莓派3B上运行
|#! /usr/bin/python
# -*- coding:utf-8 -*-
#本代码实现的是树莓派利用超声波模块测距
#使用超声波测距模块时,VCC接树莓派的5V,GND接树莓派GND。trig接树莓派38,echo接树莓派40.
#GPIO编码方式为BOARD!!!
import RPi.GPIO as GPIO
import time
def checkdist():
#发出触发信号
GPIO.output(38,GPIO.HIGH)
#保持10us以上(我选择15us)
time.sleep(0.000015)
GPIO.output(38,GPIO.LOW)
while not GPIO.input(40):
pass
#发现高电平时开时计时
t1 = time.time()
while GPIO.input(40):
pass
#高电平结束停止计时
t2 = time.time()
#返回距离,单位为厘米
return (t2-t1)*34000/2
GPIO.setmode(GPIO.BOARD)
GPIO.setup(38,GPIO.OUT,initial=GPIO.LOW)
GPIO.setup(40,GPIO.IN)
time.sleep(2)
try:
while True:
print 'Distance: %0.2f cm' %checkdist()
time.sleep(0.5)
except KeyboardInterrupt:
GPIO.cleanup()
|
下面为小车避障的代码 ,先定义小车前后左右的动作。然后进行距离判断进行相应的动作。
|#!/home/pi/server
# coding=utf-8
#使用超声波测距模块时,VCC接树莓派的5V,GND接树莓派GND。trig接树莓派38,echo接树莓派40.
#GPIO编码方式为BOARD!!
import RPi.GPIO as GPIO
import time
def t_stop():
GPIO.output(11,False)
GPIO.output(12,False)
GPIO.output(15,False)
GPIO.output(16,False)
def t_up():
GPIO.output(11,True)
GPIO.output(12,False)
GPIO.output(15,True)
GPIO.output(16,False)
def t_down():
GPIO.output(11,False)
GPIO.output(12,True)
GPIO.output(15,False)
GPIO.output(16,True)
def t_left():
GPIO.output(11,False)
GPIO.output(12,True)
GPIO.output(15,True)
GPIO.output(16,False)
def t_right():
GPIO.output(11,True)
GPIO.output(12,False)
GPIO.output(15,False)
GPIO.output(16,True)
def bee():
GPIO.output(12,True)
time.sleep(0.5)
GPIO.output(12,False)
GPIO.output(15,True)
time.sleep(5)
GPIO.output(12,True)
GPIO.output(15,False)
def checkdist():
#发出触发信号
GPIO.output(38,GPIO.HIGH)
#保持10us以上(我选择15us)
time.sleep(0.000015)
GPIO.output(38,GPIO.LOW)
while not GPIO.input(40):
pass
#发现高电平时开时计时
t1 = time.time()
while GPIO.input(40):
pass
#高电平结束停止计时
t2 = time.time()
#返回距离,单位为厘米
return (t2-t1)*34000/2
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(38,GPIO.OUT,initial=GPIO.LOW)
GPIO.setup(40,GPIO.IN)
GPIO.setup(11,GPIO.OUT)
GPIO.setup(12,GPIO.OUT)
GPIO.setup(15,GPIO.OUT)
GPIO.setup(16,GPIO.OUT)
##time.sleep(2)
try:
while True:
dis = int(checkdistance())
print(dis)
if dis <= 30:
print"distance less than 0.30m and back"
t_stop()
time.sleep(0.1)
t_down()
time.sleep(0.5)
t_left()
elif dis >30:
print"forward"
time.sleep(0.1)
t_up()
except KeyboardInterrupt:
GPIO.cleanup()
|
此图与代码中定义是C语言的代码
如下为小车超声波避障的C代码
|#include <stdio.h>
#include <stdlib.h>
#include <softPwm.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include <wiringPi.h>
#define Trig28
#define Echo29
#define BUFSIZE 512
#define MOTOR_GO_FORWARD
digitalWrite(1,HIGH);
digitalWrite(4,LOW);
digitalWrite(5,HIGH);
digitalWrite(6,LOW)
#define MOTOR_GO_BACK
digitalWrite(1,LOW);
digitalWrite(4,HIGH);
digitalWrite(5,LOW);
digitalWrite(6,HIGH)
#define MOTOR_GO_RIGHT
digitalWrite(1,HIGH);
digitalWrite(4,LOW);
digitalWrite(5,LOW);
digitalWrite(6,LOW)
#define MOTOR_GO_LEFT
digitalWrite(1,LOW);
digitalWrite(4,LOW);
digitalWrite(5,HIGH);
digitalWrite(6,LOW)
#define MOTOR_GO_STOP
digitalWrite(1, LOW);
digitalWrite(4,LOW);
digitalWrite(5, LOW);
digitalWrite(6,LOW)
void ultraInit(void)
{
pinMode(Echo, INPUT);
pinMode(Trig, OUTPUT);
}
float disMeasure(void)
{
struct timeval tv1;
struct timeval tv2;
long start, stop;
float dis;
digitalWrite(Trig, LOW);
delayMicroseconds(2);
digitalWrite(Trig, HIGH);
delayMicroseconds(10);
//发出超声波脉冲
digitalWrite(Trig, LOW);
while(!(digitalRead(Echo) == 1));
gettimeofday(&
tv1, NULL);
//获取当前时间
while(!(digitalRead(Echo) == 0));
gettimeofday(&
tv2, NULL);
//获取当前时间
start = tv1.tv_sec * 1000000 + tv1.tv_usec;
//微秒级的时间
stop = tv2.tv_sec * 1000000 + tv2.tv_usec;
dis = (float)(stop - start) / 1000000 * 34990 / 2;
//求出距离
return dis;
}
int main(int argc, char *argv[])
{
float dis;
// char buf[BUFSIZE]={0xff,0x00,0x00,0x00,0xff };
int time=1;
/*RPI*/
wiringPiSetup();
/*WiringPi GPIO*/
pinMode (1, OUTPUT);
//IN1
pinMode (4, OUTPUT);
//IN2
pinMode (5, OUTPUT);
//IN3
pinMode (6, OUTPUT);
//IN4
printf("ok");
//
while(1){
dis = disMeasure();
printf("distance = %0.2f cmn",dis);
//输出当前超声波测得的距离
if(dis<30){ //测得前方障碍的距离小于30cm时做出如下响应
MOTOR_GO_BACK;
delay(time * 300);
MOTOR_GO_LEFT;
delay(time * 300);
}
else{
MOTOR_GO_FORWARD;
//无障碍时前进
delay(time * 10);
MOTOR_GO_STOP;
}
}
return 0;
}
|
原文始发于:树莓派Python/C语言超声波测距以及利用超声波模块小车避障
|