空地协同智能消防系统——无人机、小车协同

2024-02-13 22:59

本文主要是介绍空地协同智能消防系统——无人机、小车协同,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1 题目

1.1 任务

设计一个由四旋翼无人机及消防车构成的空地协同智能消防系统。无人机上安装垂直向下的激光笔,用于指示巡逻航迹。巡防区域为40dm×48dm。无人机巡逻时可覆盖地面8dm宽度区域。以缩短完成全覆盖巡逻时间为原则,无人机按照规划航线巡逻。发现火情后立即采取初步消防措施,并将火源地点位置信息发给消防车,使其前往熄灭火源。空地协同巡逻及消防工作完成时间越短越好。

在这里插入图片描述

1.2 任务点

1、基本要求(50分)

  • (1)参赛队需自制模拟火源。模拟火源是用电池供电的红色光源,如LED等,用激光笔持续照射可控制开启或关闭:持续照射2秒左右开启,再持续照射2秒左右关闭。(5分)
  • (2)展示规划的巡逻航线图,在消防车上按键启动无人机垂直起飞后,无
    人机以18dm左右高度,在巡防区域按规划的航线完成全覆盖巡逻。(22分)
  • (3)无人机与消防车之间采用无线通信;巡逻期间无人机每秒向消防车发
    送1次位置坐标信息,消防车上显示器实时更新显示无人机位置坐标信息。(8分)
  • (4)巡逻中,消防车显示器显示巡逻航迹曲线,计算并显示累计巡逻航程。(8分)
  • (5)完成巡逻后,无人机返回,准确降落在起飞区域内。(7分)

2、发挥部分(50分)

  • (1)手动操作激光笔点亮-一个火源。在消防车上启动无人机巡逻。无人机
    按规划航线巡逻,发现火情后,前往接近火源(水平距离≤5dm)识别确认,再在无人机上用LED指示灯示警。(8分)
  • (2)无人机飞至火源地点上方,降低至10dm左右高度,悬停3s后抛洒灭
    火包,灭火包落在以火源点为中心、半径3dm圆形区域内;再将火源地点位置坐标发送给消防车,然后继续巡逻,完成后返航回到起飞点。(12分)
  • (3)消防车接收到火情信息,显示火源地点位置坐标后,从消防站出发前
    往火源地点,途中不得碾压街区及其边界线,在5dm距离内以激光笔光束照射模拟火源将其熄灭。(15分)
  • (4)熄灭模拟火源后消防车返回到出发区域内。发挥部分限时360s内完成。(10分)
  • (5)其他。(5分)

1.3 设计部分

1.3.1 模拟火源

该部分的要求如下:
模拟火源可用电池供电的红色LED等,需带向上的喇叭形遮光罩,遮光罩角度约60°左右,高度不超过10cm。可用激光笔控制其开启或关闭。
示意图如下:
在这里插入图片描述
外部遮光罩可仿照宠物防咬罩进行修改:
请添加图片描述
内部LED灯罩是为了扩大灯光面积,以便系统内图像识别系统的工作。同时为了提高小车激光跟随算法的工作效率,需要扩大光敏传感器检测区域,建议使用人体微波检测模块上的塑料透镜,以达到聚光的效果。
请添加图片描述
电路设计图:STC8最小系统板加两节1.5V干电池,一个红色LED,300Ω左右的电阻,一个光敏传感器就差不多了。
程序设计:程序中用到一个GPIO输出、ADC、定时器。

1.3.2 小车部分

该部分要求如下:
消防车要求使用 4 轮电动小车,长宽投影尺寸不大于 20cm×35cm,高度不大于 40cm;不得使用麦克纳姆轮。

1、底盘与电机:
(1)底盘:自选。
(2)电机:最好使用带编码器的金属齿轮减速点击,能够得到转速和角度,以便估测小车位置,更好地控制小车。
(3)电机驱动:H桥电机驱动模块。
(4)电池:12V高倍率锂电池组。
最好找要带有电机驱动的、编码器接口、能够降压给主控供电的小车底板,比如开山斧电机驱动模块。
四轮小车的前两个轮子无动力,采用舵机控制方向,后两个轮子分别采用直流电机控制。
请添加图片描述

2、主控芯片
(1)盘古:
如果选择TI的,盘古这块系统板开发起来还是比较顺手的,用起来Bug少。板子上有OLED驱动芯片和加速度传感器、蜂鸣器、多个按键、串口接口多。
请添加图片描述

(2)TM4C123GXL:
这块板子十分不推荐,调试接口有问题,驱动也不好打(ICDI,要安装CCS),性能也比较差,供电端口也少,写代码的时候Keil闪退无数次,硬件跑程序也容易进中断卡死。
要是有别人改过的、开发好的成品,用用还是可以的。
请添加图片描述

3、电机驱动芯片:
使用的是无名创新的开山斧驱动板,以下是模块接口图:
在这里插入图片描述

  • 电机控制信号接口:为四路PWM输入,两路PWM控制一个电机的转速和旋转方向。
  • … …

3、显示屏
建议使用陶晶驰的串口屏,配置方便,代码简单,能够回传字符串。
引脚:5V、GND、TXD、RXD
请添加图片描述

4、无线模块
可以使用蓝牙、WIFI、Lora等等。
无线模块建议采用有广播功能的模块,这样多机调试更加方便。
引脚:VCC(5~3.3V)、GND、TXD、RXD
请添加图片描述
今年还允许使用UWB,能够实现无人机和小车的精确定位,还能够传输数据,只要来得及开发代码,可以说是降维打击,不过价格还是比较昂贵的。

5、机器视觉和舵机
对于模拟火源的检测,有OpenMV方案和K210方案。
OpenMV模块有控制舵机的例程,可以控制激光笔关闭模拟火源,但溢价过多,可以自己DIY。

6、IMU
这个主控板上有就最好,没有就用模块化的MPU6050,不过要安装在小车中心处。

7、其他模块:
(1)灰度传感器:白光照射不同颜色的地面,反射回的光强不同,可以进行巡线等任务。
(2)激光头。
(3)…

1.3.3 无人机部分

直接购买成品化的TI无人机,主控板可以使用前面提到的主控。

2 程序设计

我主要是做小车的,因此讲一下我小车的设计方案。
小车上主控板选用TI 盘古的开发板,板载芯片为TM4C123GH6PZT7,MCU内核为ARM Cortex-M4F,MCU最大主频为80 MHz,工作电压范围1.08 V-3.63 V,RAM为32 KB,Flash大小为256 KB,EEPROM为2 KB,核心位宽为32-Bit,ADC为12 bit。
外设和内部资源需要使用串口屏、蓝牙模块/UWB模块、定时器、PWM、LED输出、按键输入(这个可以使用串口屏的按键串口信息回传事件替代)、蜂鸣器驱动。

2.1 蓝牙模块配置

本人使用的是大熊智能的双模蓝牙模块,两个蓝牙模块配对的话需要设置一主机一从机,以下蓝牙模块连接CH340模块,在电脑上使用AT命令配置两个模块。默认使用115200波特率连接。

蓝牙从机,连接无人机:

AT+NAME=DX2003-S		# 设置从机名称
AT+MASTER=01			# 设置从机工作模式
AT+BAUD=115200			# 设置波特率为115200
AT+LADDR				# 读取从机蓝牙地址,以便主机连接

+LADDR=22345000891f

蓝牙主机,连接小车:

AT+NAME=DX2003-M		# 设置主机名称
AT+MASTER=04			# 设置主机工作模式
AT+BAUD=115200			# 设置波特率为115200
AT+CONN=22345000891f	# 主机连接从机地址

连接上之后:
(1)主机显示:

IM_CONN:0		# 0代表是BLE连接上,1代表是SPP连接上

(2)从机显示:

IM_CONN:8

蓝牙断开连接命令:

AT+DSCET=1	

2.2 小车串口屏界面设计

串口屏使用USART HMI软件绘制界面,需要进行界面排版,字库添加,程序编译。
软件下载及学习链接:

http://mall.micromove.cn/start/download_ide.html

在这里插入图片描述

2.2.1 串口通信协议

1、串口屏接收:
协议为:字符串+HEX标识符
HEX标识符为:\xff\xff\xff
USART HMI软件上仿真不需要添加HEX标识符(\xff\xff\xff)。
例子:
如果是串口屏使用CH340连接电脑,则电脑上的串口工具输入(不要加空格):

t0.txt="陶晶驰电子"\xff\xff\xff
b0.txt="Hello World"\xff\xff\xff
j0.val=100\xff\xff\xff
page0.bco=WHITE\xff\xff\xff

如果是MCU串口发送数据:在2.4.2中详述。

2、串口屏发送:
(1)prints:从串口打印一个变量/常量。
(2)printh:从串口打印16进制。

2.2.2 绘图函数

主要使用的有:
(1)cirs:绘制实心圆

cirs x,y,radius,color\xff\xff\xff
cirs 160,266,6,RED\xff\xff\xff

(2)line:绘制直线

line x_start,y_start,x_end,y_end,color\xff\xff\xff
line 185,246,185,26,BLUE\xff\xff\xff

(3)插入图片

pic x,y,picid\xff\xff\xff					# picid为软件插入的ID号为x的图片
pic,123,150,0\xff\xff\xff

2.2.3 串口屏界面设计

小车能够通过蓝牙串口接收无人机传回的航点数据(协议A)和火灾位置数据(协议B),并在串口屏上显示出蓝色原点和红色六角形。

在这里插入图片描述

2.3 无人机与小车之间的通信协议设计

1、无人机通过串口发送给小车的字符串:

A,160,150,F			// 无人机航点坐标(160,150)
B,250,100,F			// 模拟火源坐标(250,100)
C,1,F				// 模拟火源ID: 1

A类表示无人机航点,F为结束标志位
B类表示无人机检测到的火源坐标,F为结束标志位。
C类表示无人机检测到的模拟火源所在的区域ID,F为结束标志位。这个协议可以不发送,直接小车通过B类协议计算模拟火源位置。

2、小车通过串口发给无人机的字符串只需要一个按键使能,使用按键输入或者串口屏的点击,通过蓝牙串口发送“TakeOff”字符串,无人机检测到就能起飞了。

2.4 小车程序设计

首先进行各个部分的初始化,然后进入while(1)循环,循环内写入大部分处理函数。中断处理函数中存放处理函数的使能位,当某些函数工作时间较长,需要在中断中使能标志位,然后在主函数main中进行处理,以免造成中断阻塞。
在这里插入图片描述

主函数:

#include "stdio.h"
#include <stdint.h>
#include <stdbool.h>
// ......// 全局变量
char uart4_rec_temp[50];		// 接收到暂存的字符数组
bool uart4_rec_check_flag = 0;		// 接收数据解包的标志位// ......int main(void)
{ROM_FPUEnable();//使能浮点单元ROM_FPULazyStackingEnable();//浮点延迟堆栈,减少中断响应延迟  ROM_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);//配置系统时钟initTime();					// 初始化滴答定时器GPIO_Init();				// LED灯初始化// ......ConfigureUART4();			// 初始化蓝牙BLE-串口4ConfigureUART5();			// 初始化串口屏驱动-串口5UART4_BLE_CONNECT();		// 串口4连接蓝牙HMI_Init();					// 串口屏初始化// ......while(1){// ......uart4_data_check();		//串口4数据包解包uart5_uav_point_write();	// 向串口屏写入无人机航点Control_UAV_flight_status();	// 小车控制无人机起飞// ......}
}

2.4.1 蓝牙串口程序

蓝牙串口程序包括串口初始化、串口发送、串口中断服务函数(串口接收)、串口数据解析等部分。

1、串口初始化:

// 蓝牙-串口4驱动 PC4/PC5
void ConfigureUART4(void)
{ ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);// Enable the GPIO Peripheral used by the UART.ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART4);// Enable UART0ROM_GPIOPinConfigure(GPIO_PC4_U4RX);// Configure GPIO Pins for UART mode.ROM_GPIOPinConfigure(GPIO_PC5_U4TX);ROM_GPIOPinTypeUART(GPIO_PORTC_BASE, GPIO_PIN_4 | GPIO_PIN_5);UARTConfigSetExpClk(UART4_BASE,SysCtlClockGet(),115200,(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));UARTFIFODisable(UART4_BASE);			// 使能UART4中断UARTIntEnable(UART4_BASE,UART_INT_RX);	// 使能UART4接收中断UARTIntRegister(UART4_BASE,UART4_IRQHandler);	//UART4中断地址注册IntPrioritySet(INT_UART4,USER_INT3);			//中断优先级设置USER_INT3(0最高)
}

2、串口中断服务函数:

void UART4_IRQHandler(void)		//UART4中断函数-蓝牙BLE接收中断(无人机信息发送给小车)
{uint32_t flag = UARTIntStatus(UART4_BASE,1);//获取中断标志 原始中断状态 屏蔽中断标志		UARTIntClear(UART4_BASE,flag);//清除中断标志	char ch;while(UARTCharsAvail(UART4_BASE))//判断FIFO是否还有数据		{ch = UARTCharGet(UART4_BASE);	uart4_rec_temp[temp_cnt] = ch;temp_cnt ++;}if(ch == 'F')uart4_rec_check_flag = 1;			// 接收数据解包的标志位置1if(temp_cnt >= 50)						//数组存满后清空{memset(uart4_rec_temp, 0, sizeof(uart4_rec_temp));		// 清空字符数组temp_cnt = 0;}bit_data = !bit_data;GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_5, bit_data);		//置低位点亮,保持闪烁,如果LED不闪烁了,表示程序卡死了
}

3、串口发送函数:

void UART4_SendString(const char *string)
{int len = strlen(string);while(len--){// 等待UART发送缓冲区为空while(UARTSpaceAvail(UART4_BASE) == 0);// 发送字符到UARTUARTCharPut(UART4_BASE, *string++);}
}

4、解析串口接收到的数据:
首先检测第一个数是否是“A”或“B”,然后检测字符串最后一个字符是否是“F”。接着索引字符串中的“,”,将中间的两个数字字符串拆分出来,使用atof()函数将字符串转换为浮点数。最后将获得的浮点数存入对应的变量中,或者使用调试接口输出,或使用OLED屏输出。

// 串口4数据包解包
void uart4_data_check(void)
{if(uart4_rec_check_flag == 1)		// 分析uart4_rec_temp中的数据{uart4_rec_check_flag = 0;if(uart4_rec_temp[0] == 'A')		// 是无人机XY坐标数据包{int len = strlen(uart4_rec_temp);if(uart4_rec_temp[len-1] == 'F'){char* token;token = strtok(uart4_rec_temp,",");token = strtok(NULL,",");uart4_rec_x[uav_cnt] = atof(token);token = strtok(NULL,",");uart4_rec_y[uav_cnt] = atof(token);uart4_flight_dist = uart4_flight_dist + sqrt(pow(uart4_rec_x[uav_cnt]-uart4_rec_x[uav_cnt-1],2) + pow(uart4_rec_y[uav_cnt]-uart4_rec_y[uav_cnt-1],2));printf("A-X: uart4_rec_x[%d]:%f\r\n",uav_cnt,uart4_rec_x[uav_cnt]);		// 测试printf("A-Y: uart4_rec_y[%d]:%f\r\n",uav_cnt,uart4_rec_y[uav_cnt]);		// 测试printf("A-D: uart4_flight_dist[%d]:%fm\r\n",uav_cnt,uart4_flight_dist/100);		// 测试// ......}// 处理完成后,清空uart4_rec_tempmemset(uart4_rec_temp, 0, sizeof(uart4_rec_temp));temp_cnt = 0;}else if(uart4_rec_temp[0] == 'B')		// 是火源XY坐标数据包{int len = strlen(uart4_rec_temp);if(uart4_rec_temp[len-1] == 'F'){char* token;token = strtok(uart4_rec_temp,",");token = strtok(NULL,",");uart4_fire[0] = atof(token);token = strtok(NULL,",");uart4_fire[1] = atof(token);printf("B-X: uart4_fire[0]:%f\r\n",uart4_fire[0]);		// 测试printf("B-Y: uart4_fire[1]:%f\r\n",uart4_fire[1]);		// 测试// ......}// 处理完成后,清空uart4_rec_tempmemset(uart4_rec_temp, 0, sizeof(uart4_rec_temp));temp_cnt = 0;}else{	// 没找到A/B数据包,清空uart4_rec_tempmemset(uart4_rec_temp, 0, sizeof(uart4_rec_temp));temp_cnt = 0;}}
}

2.4.2 串口屏控制程序

串口屏界面:
在这里插入图片描述

1、串口驱动:

// 串口屏-串口5 PE4/PE5
void ConfigureUART5(void)
{ ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);// Enable the GPIO Peripheral used by the UART.ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART5);// Enable UART6ROM_GPIOPinConfigure(GPIO_PE4_U5RX);// Configure GPIO Pins for UART mode.ROM_GPIOPinConfigure(GPIO_PE5_U5TX);ROM_GPIOPinTypeUART(GPIO_PORTE_BASE, GPIO_PIN_4 | GPIO_PIN_5);UARTConfigSetExpClk(UART5_BASE,SysCtlClockGet(),115200,(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));UARTFIFODisable(UART5_BASE);			// 使能UART6中断UARTIntEnable(UART5_BASE,UART_INT_RX);	// 使能UART6接收中断UARTIntRegister(UART5_BASE,UART5_IRQHandler);	//UART6中断地址注册IntPrioritySet(INT_UART5,USER_INT5);			// 中断优先级设置USER_INT6
}

2、串口中断服务函数:
函数内包含串口接收,由于接收数据分析较为简单,解析就在函数内解决了,如果数据解析较为复杂,建议在中断服务中给个flag,在主函数内处理。

void UART5_IRQHandler(void)
{uint32_t flag = UARTIntStatus(UART5_BASE,1);//获取中断标志 原始中断状态 屏蔽中断标志		UARTIntClear(UART5_BASE,flag);//清除中断标志	char ch;while(UARTCharsAvail(UART5_BASE))//判断FIFO是否还有数据		{ch = UARTCharGet(UART5_BASE);uart5_hmi_rec[uart5_cnt] = ch;	//串口屏发送回的数据存储到buffer中}uart5_cnt ++;if(strstr(uart5_hmi_rec,"TO"))		// 数据解析,如果uart5_hmi_rec中有"TO",则设置flag{key_flag = 1;		// 蓝牙串口发送数据的flag}if(uart5_cnt >= 5){uart5_cnt = 0;memset(uart5_hmi_rec,0,sizeof(uart5_hmi_rec));		// 清空buffer}
}

3、串口发动函数:

// UART5 主控串口5发送给串口屏HMI-----字符串
void UART5_SendString(const char *string)
{int len = strlen(string);while(len--){// 等待UART发送缓冲区为空while(UARTSpaceAvail(UART5_BASE) == 0);// 发送字符到UARTUARTCharPut(UART5_BASE, *string++);}
}// UART5 主控串口5发送给串口屏HMI------二进制
void UART5_SendBinary(void)
{u8 i;for(i=0;i<3;i++){// 等待UART发送缓冲区为空while(UARTSpaceAvail(UART5_BASE) == 0);// 发送二进制0xff到UARTUARTCharPut(UART5_BASE, 0xff);}
}

4、串口屏启动程序:
函数UART5_SendString(cmd)的后面必须跟着函数UART5_SendBinary(),为的是给串口屏发送三个0xff结束标志符。

// 串口屏初始化
void HMI_Init(void)
{char cmd[50];const int point_num = 5;int UAVwaypoint[point_num][2] = {{185, 246},{185, 70},{400, 70},{400, 246},{185, 246}};UART5_SendString("rest");	// 重启屏幕UART5_SendBinary();Delay_Ms(1000);UART5_SendString("line 100,20,150,20,BLUE");	// 绘制巡逻轨迹样例UART5_SendBinary();for(int i=0;i<point_num-1;i++)					// 	绘制规划航点{sprintf(cmd,"line %d,%d,%d,%d,BLUE",UAVwaypoint[i][0],UAVwaypoint[i][1],UAVwaypoint[i+1][0],UAVwaypoint[i+1][1]);UART5_SendString(cmd);UART5_SendBinary();Delay_Ms(250);}sprintf(cmd,"line %d,%d,%d,%d,BLUE",UAVwaypoint[point_num-1][0],UAVwaypoint[point_num-1][1],UAVwaypoint[0][0],UAVwaypoint[0][1]);UART5_SendString(cmd);UART5_SendBinary();
}

5、向串口屏写入无人机航点位置和火源位置:

void uart5_uav_point_write(void)
{if(uav_flag == 1)  //无人机航点位置{uav_flag = 0;char cmd[30];memset(cmd,0,sizeof(cmd));// X、Y数据处理float x_fixed,y_fixed;if(uart4_rec_x[uav_cnt-1] > 480)x_fixed = 480;else if(uart4_rec_x[uav_cnt-1] < 0)x_fixed = 0;elsex_fixed = uart4_rec_x[uav_cnt-1];uint16_t x_pixel = (uint16_t)(x_fixed/480*312);if(uart4_rec_y[uav_cnt-1] > 400)y_fixed = 400;else if(uart4_rec_y[uav_cnt-1] < 0)y_fixed = 0;elsey_fixed = uart4_rec_y[uav_cnt-1];uint16_t y_pixel = (uint16_t)(y_fixed/256*400);sprintf(cmd,"cirs %d,%d,6,BLUE",160+x_pixel,262-y_pixel);//printf("uav_cmd:    %s\r\n\r\n",cmd);UART5_SendString(cmd);	// 绘制蓝色圆形 x,y,radius,colorUART5_SendBinary();sprintf(cmd,"t16.txt=\"(%d,%d)\"",(int)(x_fixed/10),(int)(y_fixed/10));//printf("uav_position:    %s\r\n\r\n",cmd);UART5_SendString(cmd);	// 写入无人机位置坐标(x,y)UART5_SendBinary();sprintf(cmd,"t10.txt=\"%.3f\"",uart4_flight_dist/100);//printf("uav_flight_dist:    %s\r\n\r\n",cmd);UART5_SendString(cmd);	// 写入无人机航程UART5_SendBinary();}if(fire_flag == 1)	// 火源位置{fire_flag = 0;char cmd[30];memset(cmd,0,sizeof(cmd));float x_fixed,y_fixed;if(uart4_fire[0] > 480)x_fixed = 480;else if(uart4_fire[0] < 0)x_fixed = 0;elsex_fixed = uart4_fire[0];uint16_t x_pixel = (uint16_t)(x_fixed*312/480);if(uart4_fire[1] > 400)y_fixed = 400;else if(uart4_fire[1] < 0)y_fixed = 0;elsey_fixed = uart4_fire[1];uint16_t y_pixel = (uint16_t)(y_fixed*256/400);sprintf(cmd,"pic %d,%d,1",160+x_pixel,262-y_pixel);//printf("fire_cmd:   %s\r\n\r\n",cmd);UART5_SendString(cmd);	// 绘制红色火灾图像UART5_SendBinary();sprintf(cmd,"t8.txt=\"(%d,%d)\"",(int)(x_fixed/10),(int)(y_fixed/10));//printf("fire_position:    %s\r\n\r\n",cmd);UART5_SendString(cmd);	// 写入火源位置坐标UART5_SendBinary();}
}

2.4.3 小车控制无人机

依旧是蓝牙串口的部分,蓝牙串口发送“TakeOff\r\n”字符串,无人机串口检测到后能够解锁。

// key_flag = 1时,小车控制无人机起飞
void Control_UAV_flight_status(void)
{if(key_flag == 1){key_flag = 0;UART4_SendString("TakeOff\r\n");}
}

2.4.4 小车电机控制

小车控制电机最好需要检测编码器信号、读取IMU的姿态和加速度信号,但由于时间限制,这一些部分并没有编写,完全处于开环控制。

开山斧模块能够直接获取电机的转速和方向:
在这里插入图片描述

此处对小车直流电机进行控制,采用定时器控制PWM波占空比,以调整直流电机转速。

1、PWM初始化:

void PWM0_Init(void)
{SysCtlPWMClockSet(MOTOR_PWM_SYSCTL_PWMDIV); // Set divider to 80M/8=10M=0.1usSysCtlPeripheralEnable(SYSCTL_PERIPH_PWM0); // Enable PWM peripheralSysCtlDelay(2); // Insert a few cycles after enabling the peripheral to allow the clock to be fully activatedSysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); // Enable GPIOB peripheralSysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD); // Enable GPIOB peripheralSysCtlDelay(2); // Insert a few cycles after enabling the peripheral to allow the clock to be fully activated// Use alternate functionGPIOPinConfigure(GPIO_PB4_M0PWM2);GPIOPinConfigure(GPIO_PB5_M0PWM3);GPIOPinConfigure(GPIO_PD0_M0PWM6);GPIOPinConfigure(GPIO_PD1_M0PWM7);// Use pin with PWM peripheralGPIOPinTypePWM(GPIO_PORTB_BASE, GPIO_PIN_4);//M0PWM2GPIOPinTypePWM(GPIO_PORTB_BASE, GPIO_PIN_5);//M0PWM3GPIOPinTypePWM(GPIO_PORTD_BASE, GPIO_PIN_0);//M0PWM6GPIOPinTypePWM(GPIO_PORTD_BASE, GPIO_PIN_1);//M0PWM7// Configure the PWM generator for count down mode with immediate updates to the parametersPWMGenConfigure(PWM0_BASE, PWM_GEN_0, PWM_GEN_MODE | PWM_GEN_SYNC_MODE);PWMGenConfigure(PWM0_BASE, PWM_GEN_1, PWM_GEN_MODE | PWM_GEN_SYNC_MODE);PWMGenConfigure(PWM0_BASE, PWM_GEN_2, PWM_GEN_MODE | PWM_GEN_SYNC_MODE);PWMGenConfigure(PWM0_BASE, PWM_GEN_3, PWM_GEN_MODE | PWM_GEN_SYNC_MODE);// The period is set to 100us (10 KHz)period = MOTOR_PERIOD_MAX_800US; PWMGenPeriodSet(PWM0_BASE, PWM_GEN_0, period); // Set the periodPWMGenPeriodSet(PWM0_BASE, PWM_GEN_1, period);PWMGenPeriodSet(PWM0_BASE, PWM_GEN_2, period);PWMGenPeriodSet(PWM0_BASE, PWM_GEN_3, period);// Start the timers in generator 0 and 1PWMGenEnable(PWM0_BASE, PWM_GEN_0);PWMGenEnable(PWM0_BASE, PWM_GEN_1);PWMGenEnable(PWM0_BASE, PWM_GEN_2);PWMGenEnable(PWM0_BASE, PWM_GEN_3);// Enable the outputsPWMOutputState(PWM0_BASE, PWM_OUT_0_BIT | PWM_OUT_1_BIT | PWM_OUT_2_BIT | PWM_OUT_3_BIT| PWM_OUT_4_BIT | PWM_OUT_5_BIT| PWM_OUT_6_BIT | PWM_OUT_7_BIT,  true);									
}

2、PWM输出:

// width1/2/3/4 为四个PWM通道设置的脉冲宽度(0-1000)
void PWM_Output(uint16_t width1, uint16_t width2, uint16_t width3, uint16_t width4)
{uint16_t pwm[4]={0};pwm[0]  = width1;pwm[1] = width2;pwm[2] = width3;pwm[3] = width4;//EPWM1端口M0PWM0、M0PWM1、M0PWM2、M0PWM3PWMPulseWidthSet(PWM0_BASE,PWM_OUT_2, pwm[0]);//PH0——M0PWM0 PWMPulseWidthSet(PWM0_BASE,PWM_OUT_3, pwm[1]);//PH1——M0PWM1 PWMPulseWidthSet(PWM0_BASE,PWM_OUT_6, pwm[2]);//PH2——M0PWM2 PWMPulseWidthSet(PWM0_BASE,PWM_OUT_7, pwm[3]);//PH3——M0PWM3
}      

3、小车运动:
简单编写了小车向前/后/左/右运动的函数。

// 向前,value为脉宽,换算一下相当于速度;delay_ms为持续时间
void Car_Forward(int value,int delay_ms)
{PWM_Output(0,0,0,0);PWM_Output(0,value,value,0);Delay_Ms(delay_ms);PWM_Output(0,0,0,0);
}
// 向后,value为脉宽,换算一下相当于速度;delay_ms为持续时间
void Car_Backward(int value,int delay_ms)
{PWM_Output(0,0,0,0);PWM_Output(value,0,0,value);Delay_Ms(delay_ms);PWM_Output(0,0,0,0);
}
// 左转,value为脉宽,换算一下相当于转速;delay_ms为持续时间
void Car_TurnLeft(int value,int delay_ms)
{PWM_Output(0,0,0,0);PWM_Output(0,value,0,value);Delay_Ms(delay_ms);PWM_Output(0,0,0,0);
}
//右转,value为脉宽,换算一下相当于转速;delay_ms为持续时间
void Car_TurnRight(int value,int delay_ms)
{PWM_Output(0,0,0,0);PWM_Output(value,0,value,0);Delay_Ms(delay_ms);PWM_Output(0,0,0,0);
}

4、小车移动到指定街区的函数:
这一部分就是整活了,近处的街区还能将就一下,远的街区很容易跑偏。

int WaitTime = 10000;		// 小车静止等待的时间为10s
// 在小车等待的时候,视觉模块控制舵机上的激光笔照射模拟火源
void Car_Move(int position)	// position为火源id
{if(car_move_flag == 1){car_move_flag = 0;switch(position){case 0:			//无火灾,不用动break;case 1:			// 1号街区Car_Forward(500,1000);Delay_Ms(1000);Car_TurnLeft(500,1000);Delay_Ms(WaitTime);Car_TurnRight(500,1000);Delay_Ms(1000);Car_Backward(500,1000);Delay_Ms(1000);break;case 2:			// 2号街区Car_TurnRight(500,1000);Delay_Ms(500);Car_Forward(500,500);Delay_Ms(500);Car_TurnLeft(500,500);Delay_Ms(500);Car_Forward(500,3000);Car_TurnLeft(500,1000);Delay_Ms(500);Delay_Ms(WaitTime);Car_TurnRight(500,1000);Delay_Ms(500);Car_Backward(500,3000);Delay_Ms(1000);break;case 3:			// 3号街区Car_TurnRight(500,1000);Delay_Ms(500);Car_Forward(500,1000);Delay_Ms(500);Car_TurnLeft(500,1000);Delay_Ms(500);Car_Forward(500,3000);Car_TurnRight(500,1000);Delay_Ms(500);Delay_Ms(WaitTime);Car_TurnLeft(500,1000);Delay_Ms(500);Car_Backward(500,3000);Delay_Ms(1000);break;case 4:		// 最远的4号街区,瞎跑Car_TurnRight(500,2000);Delay_Ms(500);Car_Forward(500,3000);Delay_Ms(500);Delay_Ms(WaitTime);Car_Backward(500,3000);Delay_Ms(1000);break;case 5:			// 5号街区Car_TurnRight(500,2000);Delay_Ms(500);Car_Forward(500,3000);Delay_Ms(500);Delay_Ms(WaitTime);Car_Backward(500,3000);Delay_Ms(1000);break;case 6:			// 6号街区Car_TurnRight(500,1000);Delay_Ms(500);Car_Forward(500,1500);Delay_Ms(500);Delay_Ms(WaitTime);Car_Backward(500,1000);Delay_Ms(1000);break;case 7:					// 旋转测试Car_TurnRight(500,6000);Delay_Ms(1000);Car_TurnRight(500,5000);Delay_Ms(1000);break;default:break;}}
}

2.5 无人机程序设计

由于无人机程序大部分已经编写的差不多了,直接使用购买无人机的代码修改。
无人机上需要安装蓝牙、光流、OpenMV或K210、激光笔、LED灯等外设。

2.5.1 蓝牙串口程序

用来发送无人机位置信息和无人机监测到的火源信息,接收小车发来的起飞解锁信息。

这篇关于空地协同智能消防系统——无人机、小车协同的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/706851

相关文章

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

智能交通(二)——Spinger特刊推荐

特刊征稿 01  期刊名称: Autonomous Intelligent Systems  特刊名称: Understanding the Policy Shift  with the Digital Twins in Smart  Transportation and Mobility 截止时间: 开放提交:2024年1月20日 提交截止日

基于UE5和ROS2的激光雷达+深度RGBD相机小车的仿真指南(五):Blender锥桶建模

前言 本系列教程旨在使用UE5配置一个具备激光雷达+深度摄像机的仿真小车,并使用通过跨平台的方式进行ROS2和UE5仿真的通讯,达到小车自主导航的目的。本教程默认有ROS2导航及其gazebo仿真相关方面基础,Nav2相关的学习教程可以参考本人的其他博客Nav2代价地图实现和原理–Nav2源码解读之CostMap2D(上)-CSDN博客往期教程: 第一期:基于UE5和ROS2的激光雷达+深度RG

基于 YOLOv5 的积水检测系统:打造高效智能的智慧城市应用

在城市发展中,积水问题日益严重,特别是在大雨过后,积水往往会影响交通甚至威胁人们的安全。通过现代计算机视觉技术,我们能够智能化地检测和识别积水区域,减少潜在危险。本文将介绍如何使用 YOLOv5 和 PyQt5 搭建一个积水检测系统,结合深度学习和直观的图形界面,为用户提供高效的解决方案。 源码地址: PyQt5+YoloV5 实现积水检测系统 预览: 项目背景

业务协同平台--简介

一、使用场景         1.多个系统统一在业务协同平台定义协同策略,由业务协同平台代替人工完成一系列的单据录入         2.同时业务协同平台将执行任务推送给pda、pad等执行终端,通知各人员、设备进行作业执行         3.作业过程中,可设置完成时间预警、作业节点通知,时刻了解作业进程         4.做完再给你做过程分析,给出优化建议         就问你这一套下

【C++学习笔记 20】C++中的智能指针

智能指针的功能 在上一篇笔记提到了在栈和堆上创建变量的区别,使用new关键字创建变量时,需要搭配delete关键字销毁变量。而智能指针的作用就是调用new分配内存时,不必自己去调用delete,甚至不用调用new。 智能指针实际上就是对原始指针的包装。 unique_ptr 最简单的智能指针,是一种作用域指针,意思是当指针超出该作用域时,会自动调用delete。它名为unique的原因是这个

内卷时代无人机培训机构如何做大做强

在当今社会,随着科技的飞速发展,“内卷”一词频繁被提及,反映了各行业竞争日益激烈的现象。对于无人机培训行业而言,如何在这样的时代背景下脱颖而出,实现做大做强的目标,成为每个培训机构必须深思的问题。以下是从八个关键方面提出的策略,旨在帮助无人机培训机构在内卷时代中稳步前行。 1. 精准定位市场需求 深入研究市场:通过市场调研,了解无人机行业的最新趋势、政策导向及未来发展方向。 明确目标

单片机毕业设计基于单片机的智能门禁系统的设计与实现

文章目录 前言资料获取设计介绍功能介绍程序代码部分参考 设计清单具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订