当前位置: 首页 > 科技观察

OpenHarmony设备开发(五)——超声波传感器

时间:2023-03-13 12:12:36 科技观察

了解更多开源请访问:开源基础软件社区https://ost.51cto.com前言我有学到了很多新鲜有趣的知识。这次学习了超声波模块,利用学到的知识给遥控小车加了一个简单的自动避障功能。有了超声波模块,以后可以开发更多有趣的小实验,比如简单的无人车,简单的量尺……准备创建文件夹和相关代码文件。其中WIFI_car保存的是遥控车联网的代码,WIFI_hcsr04保存的是超声波模块相关的代码。编辑BUILD.gn,添加相关头文件的引用路径(小提示:不知道路径的头文件可以用Ctrl+P搜索)。static_library("WIFI_car_demo"){sources=["WIFI_car.c","WIFI_hcsr04.c",]include_dirs=["//utils/native/lite/include","//kernel/liteos_m/components/cmsis/2.0","//base/iot_hardware/peripheral/interfaces/kits","//ohos_bundles/@ohos/device_soc_hisilicon/hi3861v100/sdk_liteos/include","//ohos_bundles/@ohos/device_soc_hisilicon/hi3861v100/sdk_liteos/liteos/thir/include",]}编辑app路径下的BUILD.gn,这样我们的遥控车就可以被系统编译加载了。格式为:“文件夹名:静态库名”。超声波模块本例为HC-SR04超声波模块。超声波模块一共有4个引脚,分别是Vcc、Trig(控制端)、Echo(接收端)、GND;其中VCC和GND连接到5V电源。HC-SR04超声波距离传感器的核心是两个超声波传感器。Trig(控制终端)控制发射的超声波信号并将电信号转换为40KHz超声波脉冲。Echo(接收器)监听传输的脉冲。初始化通过查询原理图可以知道,汽车连接超声波的GPIO口是7和8,其中GPIO7是Trig(输入口),GPIO8是Echo(输出口)。首先,我们需要初始化这两个GPIO端口。GPIO口初始化分为三组:IO口初始化、IO口复用、IO口输入输出方向。#defineGPIO_Trig7#defineGPIO_Echo8inthcsr_gpio_init(void){IoTGpioInit(GPIO_Trig);hi_io_set_func(GPIO_Trig,0);//0是普通IO口的意思IoTGpioSetDir(GPIO_Trig,IOT_GPIO_DIR_OUT);IGPIO_Trig,IOT_GPIO_DIR_OUT);0);IoTGpioSetDir(GPIO_Echo,IOT_GPIO_DIR_IN);}编写检测距离函数我们要检测距离,首先要了解超声波传感器的原理。超声波传感器通过Trig高电平发出声波,Echo接收超声波。通过计算发送和接收的时间差,辅以声波的传播速度,就可以计算出汽车与障碍物的距离。编程流程:发送触发高电平。等待20us,trig设置为低电平。Echo接收到高电平,统计高电平时间,高电平持续时间为超声波从接收到返回的总时间。其中,为了减少干扰,可以先送trig高电平50us,再置trig为低电平,Echo接收到的数据会由高电平降到低电平,再启动。为了精度,也可以多次检测距离,然后对数据进行平均调试(当声波没有反射回来时,回波信号会在38毫秒后超时,返回低电平。因此,38的脉冲ms表示传感器范围内没有障碍物。)本例简单写了一个检测函数:floatGetDistance(void){IotGpioValuevalue=IOT_GPIO_VALUE0;浮动距离=0.0;int标志=0;staticunsignedlongstart_time=0,time=0;//发送声波IoTGpioSetOutputVal(GPIO_Trig,IOT_GPIO_VALUE1);hi_udelay(20);IoTGpioSetOutputVal(GPIO_Trig,IOT_GPIO_VALUE0);while(1){//持续检测声波IoTGpioGetInputVal(GPIO_Echo,&value);//记录高电平持续时间if(value==IOT_GPIO_VALUE1&&flag==0){start_time=hi_get_us();标志=1;}if(value==IOT_GPIO_VALUE0&&flag==1){time=hi_get_us()-start_time;开始时间=0;休息;}}距离=时间*0.034/2;printf("距离是%f\r\n",距离);returndistance;}避障线程简单的避障功能需要满足以下要求:避障线程的优先级需要高于遥控器的优先级,这样才能保证自动避障在被触发时正常运行即将撞到障碍物。需要设计一个信号量。信号量的作用是保证不会同时调用两个或多个关键代码。这里是为了避免避障线程和遥控线程的并发调用。此示例使用sem_d变量而不是信号量。当sem_d为1时,远程控制函数休眠。不断判断距离是否小于特定值,小于特定值时进行相应的避障。voidhcsr04_avoid(void){浮动距离=0;//IO口初始化hcsr_gpio_init();while(1){//获取距离信息distance=GetDistance();if(distance<20){printf("距离<20!!!");sem_d=1;汽车停止();汽车向后();睡觉(1);汽车停止();sem_d=0;}}}voidhcsr04_demo(void){osThreadAttr_t属性;attr.name="hcsr04_Task";属性.attr_bits=0U;属性.cb_mem=NULL;属性.cb_size=0U;属性.stack_mem=NULL;attr.stack_size=4096;属性优先级=24;if(osThreadNew((osThreadFunc_t)hcsr04_avoid,NULL,&attr)==NULL){printf("[hcsr04_Task]创建hcsr04_Task失败!\n");}}网络连接遥控小车源码文件为了加入超声波传感器线程,我们可以在小车IO口之后启动超声波线程(或者直接使用SYS_RUN()启动线程,这里是因为遥控器没有使用障碍避免,所以线程被延迟了):externvoidhcsr04_demo(void);hcsr04_demo();信号量的使用:首先创建一个全局变量,记得在头文件中extern这个变量,WIFI_hcsr04.c可以使用这个变量。当sem_d为1时,遥控器代码休眠直到sem_d为0。intsem_d=0;while(1){if(sem_d==1){continue;}//遥控车代码...}这里是头代码文件中的代码,这样WIFI_hcsr04.c可以调用一些需要的函数和变量。#ifndef__WIFI_CAR__#define__WIFI_CAR__voidcar_stop(void);voidcar_backwward(void);externintsem_d;#endif其他效果问题经过几轮测试,发现如下问题。测试中偶尔遇到stackoverflow,一直没有找到原因。超声波传感器的精度不高,容易误判障碍物(空障碍物emm)。目前解决方案:增加线程栈大小(不能从根本上解决)。找到栈溢出的原因,设计超时机制,避免内存不断堆积。设计检测距离的算法,取采集数据的平均值,去掉最大值和最小值。浮动距离总和[5];浮动距离=0;//获取数据(inti=0;i<5;i++){distance_sum[i]=GetDistance();}intmax_id=0;intmin_id=0;//记录最大最小数组下标for(inti=1;i<5;i++){if(distance_sum[i]>distance_sum[max_id]){max_id=i;}if(distance_sum[i]