本帖最后由 水精灵 于 2025-2-6 11:04 编辑

智慧城市的建设推动了城市各个领域的智能化发展,消防领域也不例外。智慧消防作为智慧城市的重要组成部分,其建设和发展与智慧城市的建设紧密相连。
在此背景下,ElfBoard团队完成了一个创新性的开源项目——利用ELF 1开发板打造的智慧消防车。该项目展现了物联网、数据处理等前沿技术在消防领域的应用潜力,下面就和各位小伙伴展示一下这个开源项目是怎样实现的。

一、项目简介
智能消防小车通过阿里云平台实现远程控制,使得用户可以远程控制小车到达指定地点进行灭火,或者通过火焰传感器检测到火焰时自动响应灭火操作。
二、功能特性
1.数据监测与显示:实时监测小车运行状态,并直观地显示在Web界面上。
2.Web可视化界面:用户可以通过Web界面远程控制小车的移动。
3.远程控制:通过阿里云物联网平台向小车发送指令,实现远程操作和控制。
4.自动灭火:根据火焰传感器检测到的火焰情况,自动触发小车的灭火操作。
三、环境说明
1.开发环境操作系统:Ubuntu18.04 64位版
2.交叉编译工具链:arm-poky-linux-gnueabi-gcc 5.3.0
3.开发板使用Bootloader版本:u-boot-2016.03
4.开发板内核版本:linux-4.1.15
5.开发板移植QT版本:qt5.6.2
四、硬件连接
1、小车驱动装置
小车驱动装置主要由TB6612FNG双电机驱动板、TT马达、车轮等组成。
1)TB6612FNG双电机驱动板:
1.png
2、灭火装置
灭火装置主要由火焰传感器、继电器、水泵等组成。
1)火焰传感器:
2.png
2)继电器:
3.png
3)水泵:
4.png
3、整体连接示意图
5.png
五、内核适配
为支持智能消防小车系统的各项功能,需要对内核源码进行适配。
1、实现正常驱动小车的功能
小车驱动装置主要由TB6612FNG双电机驱动板,驱动板中pwm引脚接受板卡输出的pwm信号,‌通过调整pwm信号的占空比‌来控制输出电压,‌进而控制电机的转速,从而‌控制小车速度,AIN0/AIN1:‌连接板卡的IO端口,‌用于控制电机的转动方向。‌通过控制这两个引脚的电平状态,‌可以实现电机的正转、‌反转或停止。
下面来介绍如何使用elf1板卡进行pwm复用以及gpio复用。‌
1)复用pwm
1)拷贝ELF1开发板资料包\02-Linux 源代码\02-0 出厂内核和uboot源码\内核源码\linux-4.1.15-elf1.tar.bz2内核源码到开发环境/home/elf/work/目录下解压。
elf@ubuntu:~/work$ tar -xvf linux-4.1.15-elf1.tar.bz2
2)修改顶层设备树文件arch/arm/boot/dts/imx6ull.dtsi。
elf@ubuntu:~/work$ cd linux-4.1.15-elf1/
elf@ubuntu:~/work/linux-4.1.15-elf1$ vi arch/arm/boot/dts/imx6ull.dtsi
6.png
3)修改设备树文件arch/arm/boot/dts/imx6ull-elf1-emmc.dts。
elf@ubuntu:~/work/linux-4.1.15-elf1$ vi arch/arm/boot/dts/imx6ull-elf1-emmc.dts
添加设备节点。
  1. &pwm5 {


  2.         pinctrl-names = "default";
  3.         pinctrl-0 = <&pinctrl_pwm5>;
  4.         status = "okay";
  5. };


  6. &pwm6 {


  7.         pinctrl-names = "default";
  8.         pinctrl-0 = <&pinctrl_pwm6>;
  9.         status = "okay";
  10. };


  11. &pwm7 {


  12.         pinctrl-names = "default";
  13.         pinctrl-0 = <&pinctrl_pwm7>;
  14.         status = "okay";
  15. };


  16. &pwm8 {


  17.         pinctrl-names = "default";
  18.         pinctrl-0 = <&pinctrl_pwm8>;
  19.         status = "okay";
  20. };
复制代码
7.png
在iomux节点下面添加引脚复用。
  1. pinctrl_pwm5: pwm5grp {
  2.        fsl,pins = <
  3.              MX6UL_PAD_ENET1_TX_DATA1__PWM5_OUT     0x110b0
  4.       >;
  5. };


  6. pinctrl_pwm6: pwm6grp {
  7.        fsl,pins = <
  8.              MX6UL_PAD_ENET1_TX_EN__PWM6_OUT     0x110b0
  9.       >;
  10. };


  11. pinctrl_pwm7: pwm7grp {
  12.        fsl,pins = <
  13.              MX6UL_PAD_CSI_VSYNC__PWM7_OUT     0x110b0
  14.       >;
  15. };


  16. pinctrl_pwm8: pwm8grp {
  17.        fsl,pins = <
  18.              MX6UL_PAD_CSI_HSYNC__PWM8_OUT     0x110b0
  19.       >;
  20. };
复制代码
8.png
取消其它用到csi、enet1功能的地方。
9.png
10.png
11.png
至此pwm已经复用完成。
2)复用gpio
1)修改设备树文件arch/arm/boot/dts/imx6ull-elf1-emmc.dts。
elf@ubuntu:~/work$ cd linux-4.1.15-elf1/
elf@ubuntu:~/work/linux-4.1.15-elf1$ vi arch/arm/boot/dts/imx6ull-elf1-emmc.dts
在iomux节点下面添加引脚复用。
  1. MX6UL_PAD_CSI_DATA00__GPIO4_IO21        0x17059
  2. MX6UL_PAD_CSI_DATA01__GPIO4_IO22        0x17059
  3. MX6UL_PAD_CSI_DATA02__GPIO4_IO23        0x17059
  4. MX6UL_PAD_CSI_DATA03__GPIO4_IO24        0x17059
  5. MX6UL_PAD_CSI_DATA04__GPIO4_IO25        0x17059
  6. MX6UL_PAD_CSI_DATA05__GPIO4_IO26        0x17059
  7. MX6UL_PAD_CSI_DATA06__GPIO4_IO27        0x17059
  8. MX6UL_PAD_CSI_DATA07__GPIO4_IO28        0x17059
  9. MX6UL_PAD_UART2_TX_DATA__GPIO1_IO20     0x17059
  10. MX6UL_PAD_UART2_RX_DATA__GPIO1_IO21     0x17059
  11. MX6UL_PAD_CSI_MCLK__GPIO4_IO17          0x17059
  12. MX6UL_PAD_CSI_PIXCLK__GPIO4_IO18        0x17059
复制代码
12.png
取消其它用到csi、uart2功能的地方。
13.png
14.png
15.png
至此gpio已经复用完成。
3)编译并替换设备树
1)执行环境变量。
elf@ubuntu:~/work/linux-4.1.15-elf1$ . /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi
2)编译设备树和内核。
elf@ubuntu:~/work/linux-4.1.15-elf1$ make imx6ull_elf1_defconfig
elf@ubuntu:~/work/linux-4.1.15-elf1$ make dtbs
3)将arch/arm/boot/dts/路径下的imx6ull-elf1-emmc.dtb放到U盘,通过U盘拷贝到开发板。
root@ELF1:~# cp /run/media/sda1/imx6ull-elf1-emmc.dtb /run/media/mmcblk1p1/
4)保存并重启开发板。
root@ELF1:~# sync                                            
root@ELF1:~# reboot                                          
六、基于云平台的远程数据监测和设备控制
1、配置阿里云物联网平台
1)注册并登录阿里云账号。
2)开通物联网平台服务。
3)开通公共实例。
4)创建产品。
5)添加设备。
6)发布产品。
2、配置IoT Stdio
1)领取IoT Stdio体验版免费试用机会。
2)新建项目。
3)关联物联网平台产品、设备。
4)新建Web应用。
5)配置Web显示界面。
6)发布应用。
3、程序设计
16.png
主函数的实现main.cpp。
  1. int main(int argc, char *argv[])
  2. {
  3.     pthread_t gpio_tid, mqtt_tid;
  4.     // 信号处理
  5.     signal(SIGTERM, SignHandler);
  6.     signal(SIGINT, SignHandler);


  7.     // 初始化控制参数
  8.     if (-1 == init_controller_data())
  9.         goto to_end;


  10.     // 初始化MQTT并建立连接
  11.     init_mqtt();
  12.     // 将设备数据同步到MQTT服务器
  13.     demo_mqtt_send_handler(SET_STRAIGHT_TO_SEND);
  14.     demo_mqtt_send_handler(SET_LEFT_TO_SEND);
  15.     demo_mqtt_send_handler(SET_RIGHT_TO_SEND);
  16.     demo_mqtt_send_handler(SET_BACK_TO_SEND);
  17.     demo_mqtt_send_handler(SET_STOP_TO_SEND);
  18.     demo_mqtt_send_handler(SET_WATER_TO_SEND);


  19.     set_controller(Upperleft, 5.0);
  20.     set_controller(Lowerleft, 5.0);
  21.     set_controller(Upperright, 5.0);
  22.     set_controller(Lowerright, 5.0);
  23.     set_controller(left, 1.0);
  24.     set_controller(right, 1.0);
  25.     set_controller(c8, 1.0);


  26.     demo_mqtt_send_handler(SET_UPPERLEFT_TO_SEND);
  27.     demo_mqtt_send_handler(SET_LOWERLEFT_TO_SEND);
  28.     demo_mqtt_send_handler(SET_UPPERRIGHT_TO_SEND);
  29.     demo_mqtt_send_handler(SET_LOWERRIGHT_TO_SEND);
  30.     // 创建GPIO线程
  31.     if (pthread_create(&gpio_tid, NULL, gpio_thread, NULL) != 0) {
  32.         perror("pthread_create for gpio_thread");
  33.         goto to_end;
  34.     }


  35.     // 创建MQTT线程
  36.     if (pthread_create(&mqtt_tid, NULL, mqtt_thread, NULL) != 0) {
  37.         perror("pthread_create for mqtt_thread");
  38.         goto to_end;
  39.     }


  40.     pthread_join(gpio_tid, NULL);
  41.     pthread_join(mqtt_tid, NULL);
  42. to_end:
  43. // 遇到异常,退出进程前,回收资源
  44.     release_mqtt();
  45.     release_controller_devices();
  46.     sleep(1);
  47.     exit(1);


  48. }
  49. 初始化控制器参数。
  50. int init_controller_data(void)
  51. {
  52.     controller.left.value = 0;
  53.     controller.right.value = 0;
  54.     controller.Upperleft.value = 0;
  55.     controller.Upperright.value = 0;
  56.     controller.Lowerleft.value = 0;
  57.     controller.Lowerright.value = 0;
  58.     controller.go_straight.value = 0;
  59.     controller.turn_left.value = 0;
  60.     controller.turn_right.value = 0;
  61.     controller.go_back.value = 0;
  62.     controller.go_stop.value = 0;
  63.     controller.spray_water.value = 0;


  64.     controller.left.flag = 0;
  65.     controller.right.flag = 0;
  66.     controller.Upperleft.flag = 0;
  67.     controller.Upperright.flag = 0;
  68.     controller.Lowerleft.flag = 0;
  69.     controller.Lowerright.flag = 0;
  70.     controller.go_straight.flag = 0;
  71.     controller.turn_left.flag = 0;
  72.     controller.turn_right.flag = 0;
  73.     controller.go_back.flag = 0;
  74.     controller.go_stop.flag = 0;
  75.     controller.spray_water.flag = 0;


  76.     return 0;
  77. }
复制代码
初始化MQTT。
  1. /* init_mqtt, 初始化,跟mqtt服务器建立链接,设置订阅,创建通道管理线程,创建接收处理线程 */
  2. int init_mqtt(void)
  3. {
  4.     int32_t res = STATE_SUCCESS;
  5.     uint16_t port = 443;             /* 无论设备是否使用TLS连接阿里云平台, 目的端口都是443 */
  6.     aiot_sysdep_network_cred_t cred; /* 安全凭据结构体, 如果要用TLS, 这个结构体中配置CA证书等参数 */
  7.     char sub_topic[100] = {0};


  8.     /* 配置SDK的底层依赖 */
  9.     aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile);
  10.     /* 配置SDK的日志输出 */
  11.     aiot_state_set_logcb(demo_state_logcb);


  12.     /* 创建SDK的安全凭据, 用于建立TLS连接 */
  13.     memset(&cred, 0, sizeof(aiot_sysdep_network_cred_t));
  14.     cred.option = AIOT_SYSDEP_NETWORK_CRED_SVRCERT_CA; /* 使用RSA证书校验MQTT服务端 */
  15.     cred.max_tls_fragment = 16384;                     /* 最大的分片长度为16K, 其它可选值还有4K, 2K, 1K, 0.5K */
  16.     cred.sni_enabled = 1;                              /* TLS建连时, 支持Server Name Indicator */
  17.     cred.x509_server_cert = ali_ca_cert;               /* 用来验证MQTT服务端的RSA根证书 */
  18.     cred.x509_server_cert_len = strlen(ali_ca_cert);   /* 用来验证MQTT服务端的RSA根证书长度 */


  19.     /* 创建1个MQTT客户端实例并内部初始化默认参数 */
  20.     mqtt_handle = aiot_mqtt_init();
  21.     if (mqtt_handle == NULL)
  22.     {
  23.         printf("aiot_mqtt_init failed\n");
  24.         return -1;
  25.     }


  26.     /* TODO: 如果以下代码不被注释, 则例程会用TCP而不是TLS连接云平台 */


  27.     {
  28.         memset(&cred, 0, sizeof(aiot_sysdep_network_cred_t));
  29.         cred.option = AIOT_SYSDEP_NETWORK_CRED_NONE;
  30.     }
  31.     /* 配置MQTT服务器地址 */
  32.     aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_HOST, (void *)mqtt_host);
  33.     /* 配置MQTT服务器端口 */
  34.     aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_PORT, (void *)&port);
  35.     /* 配置设备productKey */
  36.     aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_PRODUCT_KEY, (void *)product_key);
  37.     /* 配置设备deviceName */
  38.     aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_DEVICE_NAME, (void *)device_name);
  39.     /* 配置设备deviceSecret */
  40.     aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_DEVICE_SECRET, (void *)device_secret);
  41.     /* 配置网络连接的安全凭据, 上面已经创建好了 */
  42.     aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_NETWORK_CRED, (void *)&cred);
  43.     /* 配置MQTT默认消息接收回调函数 */
  44.     aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_RECV_HANDLER, (void *)demo_mqtt_default_recv_handler);
  45.     /* 配置MQTT事件回调函数 */
  46.     aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_EVENT_HANDLER, (void *)demo_mqtt_event_handler);
  47.     /* 与服务器建立MQTT连接 */
  48.     res = aiot_mqtt_connect(mqtt_handle);
  49.     if (res < STATE_SUCCESS)
  50.     {
  51.         /* 尝试建立连接失败, 销毁MQTT实例, 回收资源 */
  52.         aiot_mqtt_deinit(&mqtt_handle);
  53.         printf("aiot_mqtt_connect failed: -0x%04X\n\r\n", -res);
  54.         printf("please check variables like mqtt_host, produt_key, device_name, device_secret in demo\r\n");
  55.         return -1;
  56.     }


  57.     /* MQTT 订阅topic功能示例, 请根据自己的业务需求进行使用 */
  58.     {
  59.         strcpy(sub_topic, "/sys/k1l0mrfjkHG/control_unit_1/thing/service/property/set");
  60.         res = aiot_mqtt_sub(mqtt_handle, sub_topic, NULL, 1, NULL);
  61.         if (res < 0)
  62.         {
  63.             printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res);
  64.             return -1;
  65.         }
  66.     }
  67.     /* 创建一个单独的线程, 专用于执行aiot_mqtt_process, 它会自动发送心跳保活, 以及重发QoS1的未应答报文 */
  68.     g_mqtt_process_thread_running = 1;
  69.     res = pthread_create(&g_mqtt_process_thread, NULL, demo_mqtt_process_thread, mqtt_handle);
  70.     if (res < 0)
  71.     {
  72.         printf("pthread_create demo_mqtt_process_thread failed: %d\n", res);
  73.         return -1;
  74.     }


  75.     /* 创建一个单独的线程用于执行aiot_mqtt_recv, 它会循环收取服务器下发的MQTT消息, 并在断线时自动重连 */
  76.     g_mqtt_recv_thread_running = 1;
  77.     res = pthread_create(&g_mqtt_recv_thread, NULL, demo_mqtt_recv_thread, mqtt_handle);
  78.     if (res < 0)
  79.     {
  80.         printf("pthread_create demo_mqtt_recv_thread failed: %d\n", res);
  81.         return -1;
  82.     }
  83.     return 0;
  84. }
复制代码
同步设备数据到MQTT服务器。
  1. demo_mqtt_send_handler(SET_STRAIGHT_TO_SEND);
  2. demo_mqtt_send_handler(SET_LEFT_TO_SEND);
  3. demo_mqtt_send_handler(SET_RIGHT_TO_SEND);
  4. demo_mqtt_send_handler(SET_BACK_TO_SEND);
  5. demo_mqtt_send_handler(SET_STOP_TO_SEND);
  6. demo_mqtt_send_handler(SET_WATER_TO_SEND);


  7. demo_mqtt_send_handler(SET_UPPERLEFT_TO_SEND);
  8. demo_mqtt_send_handler(SET_LOWERLEFT_TO_SEND);
  9. demo_mqtt_send_handler(SET_UPPERRIGHT_TO_SEND);
  10. demo_mqtt_send_handler(SET_LOWERRIGHT_TO_SEND);
复制代码
设置控制器参数。
  1. set_controller(Upperleft, 5.0);
  2. set_controller(Lowerleft, 5.0);
  3. set_controller(Upperright, 5.0);
  4. set_controller(Lowerright, 5.0);
  5. set_controller(left, 1.0);
  6. set_controller(right, 1.0);
  7. set_controller(c8, 1.0);
复制代码
GPIO线程。
  1. // GPIO线程函数
  2. void *gpio_thread(void *arg) {
  3.     while (1) {
  4.         int value = 0;
  5.         set_gpio(c9, 114);
  6.         value = read_gpio_value(c9_GPIO_VALUE);


  7.         pthread_mutex_lock(&gpio_mutex);
  8.         printf("Value: %d\n", value);
  9.         if (value == -1) {
  10.             printf("Error occurred while reading file: %s\n", c9_GPIO_VALUE);
  11.         }
  12.         if (value == 0) {
  13.             cspray_water();
  14.         }
  15.         pthread_mutex_unlock(&gpio_mutex);


  16.         usleep(100000);
  17.     }
  18.     return NULL;
  19. }
  20.     // 创建GPIO线程
  21.     if (pthread_create(&gpio_tid, NULL, gpio_thread, NULL) != 0) {
  22.         perror("pthread_create for gpio_thread");
  23.         goto to_end;
  24.     }
复制代码
MQTT线程。
  1. // MQTT线程函数
  2. void *mqtt_thread(void *arg) {
  3.     while (1) {
  4.         pthread_mutex_lock(&mqtt_mutex);
  5.         if (controller.Upperleft.flag == 1) {
  6.             demo_mqtt_send_handler(SET_UPPERLEFT_TO_SEND);
  7.             controller.Upperleft.flag = 0;
  8.         }
  9.         if (controller.Lowerleft.flag == 1) {
  10.             demo_mqtt_send_handler(SET_LOWERLEFT_TO_SEND);
  11.             controller.Lowerleft.flag = 0;
  12.         }
  13.         if (controller.Upperright.flag == 1) {
  14.             demo_mqtt_send_handler(SET_UPPERRIGHT_TO_SEND);
  15.             controller.Upperright.flag = 0;
  16.         }
  17.         if (controller.Lowerright.flag == 1) {
  18.             demo_mqtt_send_handler(SET_LOWERRIGHT_TO_SEND);
  19.             controller.Lowerright.flag = 0;
  20.         }
  21.         if (controller.go_straight.flag == 1) {
  22.             demo_mqtt_send_handler(SET_STRAIGHT_TO_SEND);
  23.             controller.go_straight.flag = 0;
  24.         }
  25.         if (controller.turn_left.flag == 1) {
  26.             demo_mqtt_send_handler(SET_LEFT_TO_SEND);
  27.             controller.turn_left.flag = 0;
  28.         }
  29.         if (controller.turn_right.flag == 1) {
  30.             demo_mqtt_send_handler(SET_RIGHT_TO_SEND);
  31.             controller.turn_right.flag = 0;
  32.         }
  33.         if (controller.go_back.flag == 1) {
  34.             demo_mqtt_send_handler(SET_BACK_TO_SEND);
  35.             controller.go_back.flag = 0;
  36.         }
  37.         if (controller.go_stop.flag == 1) {
  38.             demo_mqtt_send_handler(SET_STOP_TO_SEND);
  39.             controller.go_stop.flag = 0;
  40.         }
  41.         if (controller.spray_water.flag == 1) {
  42.             demo_mqtt_send_handler(SET_WATER_TO_SEND);
  43.             controller.spray_water.flag = 0;
  44.         }
  45.         pthread_mutex_unlock(&mqtt_mutex);


  46.         usleep(100000);
  47.     }
  48.     return NULL;
  49. }
  50.     // 创建MQTT线程
  51.     if (pthread_create(&mqtt_tid, NULL, mqtt_thread, NULL) != 0) {
  52.         perror("pthread_create for mqtt_thread");
  53.         goto to_end;
  54.     }
复制代码
4、应用编译
1)拷贝car.tar.bz2到开发环境/home/elf/work目录下解压。
elf@ubuntu:~/work$ tar xvf car.tar.bz2
2)执行环境变量。
elf@ubuntu:~/work$ . /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi
3)编译。
elf@ubuntu:~/work$ cd car/
elf@ubuntu:~/work/car$ make
4)拷贝mqtt_test到开发板/home/root路径下。
root@ELF1:~# cp /run/media/sda1/mqtt_test ./
七、项目测试
1.设置Wi-Fi连接。
root@ELF1:~# elf1_cmd_wifi.sh -i 8723 -s 账号 -p 密码
2.执行应用。
root@ELF1:~# ./mqtt_test
17.png
此时可以通过Web界面下发指令控制小车运行。
18.png
Web界面将实时显示小车的运行状态。

19.png
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    Powered by Discuz! X3.5  © 2001-2013 Comsenz Inc.