智慧城市的建設(shè)推動了城市各個領(lǐng)域的智能化發(fā)展,消防領(lǐng)域也不例外。智慧消防作為智慧城市的重要組成部分,其建設(shè)和發(fā)展與智慧城市的建設(shè)緊密相連。
在此背景下,ElfBoard團隊完成了一個創(chuàng)新性的開源項目——利用ELF 1開發(fā)板打造的智慧消防車。該項目展現(xiàn)了物聯(lián)網(wǎng)、數(shù)據(jù)處理等前沿技術(shù)在消防領(lǐng)域的應(yīng)用潛力,下面就和各位小伙伴展示一下這個開源項目是怎樣實現(xiàn)的。
項目簡介
智能消防車通過阿里云平臺實現(xiàn)遠(yuǎn)程控制,使得用戶可以遠(yuǎn)程控制車到達(dá)指定地點進(jìn)行滅火,或者通過火焰傳感器檢測到火焰時自動響應(yīng)滅火操作。
功能特性
1、數(shù)據(jù)監(jiān)測與顯示:實時監(jiān)測車運行狀態(tài),并直觀地顯示在Web界面上。
2、Web可視化界面:用戶可以通過Web界面遠(yuǎn)程控制車的移動。
3、遠(yuǎn)程控制:通過阿里云物聯(lián)網(wǎng)平臺向車發(fā)送指令,實現(xiàn)遠(yuǎn)程操作和控制。
4、自動滅火:根據(jù)火焰?zhèn)鞲衅鳈z測到的火焰情況,自動觸發(fā)滅火操作。
環(huán)境說明
1、開發(fā)環(huán)境操作系統(tǒng):Ubuntu18.04 64位版
2、交叉編譯工具鏈:arm-poky-linux-gnueabi-gcc 5.3.0
3、開發(fā)板使用Bootloader版本:u-boot-2016.03
4、開發(fā)板內(nèi)核版本:linux-4.1.15
5、開發(fā)板移植QT版本:qt5.6.2
硬件配置
1、小車驅(qū)動裝置
小車驅(qū)動裝置主要由TB6612FNG雙電機驅(qū)動板、TT馬達(dá)、車輪等組成。
(1)TB6612FNG雙電機驅(qū)動板
2、滅火裝置
滅火裝置主要由火焰?zhèn)鞲衅鳌⒗^電器、水泵等組成。
(1)火焰?zhèn)鞲衅?/p>
(2)繼電器
(3)水泵
3、整體連接示意圖
內(nèi)核適配
1、實現(xiàn)正常驅(qū)動小車的功能
消防車驅(qū)動裝置主要由TB6612FNG雙電機驅(qū)動板,驅(qū)動板中pwm引腳接受板卡輸出的pwm信號,?通過調(diào)整pwm信號的占空比?來控制輸出電壓,?進(jìn)而控制電機的轉(zhuǎn)速,從而?控制小車速度,AIN0/AIN1:?連接板卡的IO端口,?用于控制電機的轉(zhuǎn)動方向。?通過控制這兩個引腳的電平狀態(tài),?可以實現(xiàn)電機的正轉(zhuǎn)、?反轉(zhuǎn)或停止。下面來介紹如何使用EFL 1板卡進(jìn)行pwm復(fù)用以及gpio復(fù)用。
(1)復(fù)用pwm
1)拷貝
ELF1開發(fā)板資料包\02-Linux 源代碼\02-0 出廠內(nèi)核和uboot源碼\內(nèi)核源碼\linux-4.1.15-elf1.tar.bz2內(nèi)核源碼到開發(fā)環(huán)境/home/elf/work/目錄下解壓。
elf@ubuntu:~/work$ tar -xvf linux-4.1.15-elf1.tar.bz2
2)修改頂層設(shè)備樹文件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
3)修改設(shè)備樹文件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
添加設(shè)備節(jié)點
&pwm5 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pwm5>; status = "okay"; }; &pwm6 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pwm6>; status = "okay"; }; &pwm7 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pwm7>; status = "okay"; }; &pwm8 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pwm8>; status = "okay"; };
在iomux節(jié)點下面添加引腳復(fù)用
pinctrl_pwm5: pwm5grp { fsl,pins = < MX6UL_PAD_ENET1_TX_DATA1__PWM5_OUT 0x110b0 >; }; pinctrl_pwm6: pwm6grp { fsl,pins = < MX6UL_PAD_ENET1_TX_EN__PWM6_OUT 0x110b0 >; }; pinctrl_pwm7: pwm7grp { fsl,pins = < MX6UL_PAD_CSI_VSYNC__PWM7_OUT 0x110b0 >; }; pinctrl_pwm8: pwm8grp { fsl,pins = < MX6UL_PAD_CSI_HSYNC__PWM8_OUT 0x110b0 >; };
取消其它用到csi、enet1功能的地方
至此pwm已經(jīng)復(fù)用完成。
(2)復(fù)用gpio
1)修改設(shè)備樹文件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節(jié)點下面添加引腳復(fù)用
MX6UL_PAD_CSI_DATA00__GPIO4_IO21 0x17059 MX6UL_PAD_CSI_DATA01__GPIO4_IO22 0x17059 MX6UL_PAD_CSI_DATA02__GPIO4_IO23 0x17059 MX6UL_PAD_CSI_DATA03__GPIO4_IO24 0x17059 MX6UL_PAD_CSI_DATA04__GPIO4_IO25 0x17059 MX6UL_PAD_CSI_DATA05__GPIO4_IO26 0x17059 MX6UL_PAD_CSI_DATA06__GPIO4_IO27 0x17059 MX6UL_PAD_CSI_DATA07__GPIO4_IO28 0x17059 MX6UL_PAD_UART2_TX_DATA__GPIO1_IO20 0x17059 MX6UL_PAD_UART2_RX_DATA__GPIO1_IO21 0x17059 MX6UL_PAD_CSI_MCLK__GPIO4_IO17 0x17059 MX6UL_PAD_CSI_PIXCLK__GPIO4_IO18 0x17059
取消其它用到csi、uart2功能的地方
至此gpio已經(jīng)復(fù)用完成
(3)編譯并替換設(shè)備樹
1)執(zhí)行環(huán)境變量
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)編譯設(shè)備樹和內(nèi)核
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盤拷貝到開發(fā)板
root@ELF1:~# cp /run/media/sda1/imx6ull-elf1-emmc.dtb /run/media/mmcblk1p1/
4)保存并重啟開發(fā)板
root@ELF1:~# sync root@ELF1:~# reboot
配基于云平臺的遠(yuǎn)程數(shù)據(jù)監(jiān)測和設(shè)備控制
1、配置阿里云物聯(lián)網(wǎng)平臺
(1)注冊并登錄阿里云賬號(2)開通物聯(lián)網(wǎng)平臺服務(wù)(3)開通公共實例(4)創(chuàng)建產(chǎn)品(5)添加設(shè)備(6)發(fā)布產(chǎn)品
2、配置IoT Stdio
(1)領(lǐng)取IoT Stdio體驗版免費試用機會(2)新建項目(3)關(guān)聯(lián)物聯(lián)網(wǎng)平臺產(chǎn)品、設(shè)備(4)新建Web應(yīng)用(5)配置Web顯示界面(6)發(fā)布應(yīng)用
3、程序設(shè)計
主函數(shù)的實現(xiàn)main.cpp
int main(int argc, char *argv[]) { pthread_t gpio_tid, mqtt_tid; // 信號處理 signal(SIGTERM, SignHandler); signal(SIGINT, SignHandler); // 初始化控制參數(shù) if (-1 == init_controller_data()) goto to_end; // 初始化MQTT并建立連接 init_mqtt(); // 將設(shè)備數(shù)據(jù)同步到MQTT服務(wù)器 demo_mqtt_send_handler(SET_STRAIGHT_TO_SEND); demo_mqtt_send_handler(SET_LEFT_TO_SEND); demo_mqtt_send_handler(SET_RIGHT_TO_SEND); demo_mqtt_send_handler(SET_BACK_TO_SEND); demo_mqtt_send_handler(SET_STOP_TO_SEND); demo_mqtt_send_handler(SET_WATER_TO_SEND); set_controller(Upperleft, 5.0); set_controller(Lowerleft, 5.0); set_controller(Upperright, 5.0); set_controller(Lowerright, 5.0); set_controller(left, 1.0); set_controller(right, 1.0); set_controller(c8, 1.0); demo_mqtt_send_handler(SET_UPPERLEFT_TO_SEND); demo_mqtt_send_handler(SET_LOWERLEFT_TO_SEND); demo_mqtt_send_handler(SET_UPPERRIGHT_TO_SEND); demo_mqtt_send_handler(SET_LOWERRIGHT_TO_SEND); // 創(chuàng)建GPIO線程 if (pthread_create(&gpio_tid, NULL, gpio_thread, NULL) != 0) { perror("pthread_create for gpio_thread"); goto to_end; } // 創(chuàng)建MQTT線程 if (pthread_create(&mqtt_tid, NULL, mqtt_thread, NULL) != 0) { perror("pthread_create for mqtt_thread"); goto to_end; } pthread_join(gpio_tid, NULL); pthread_join(mqtt_tid, NULL); to_end: // 遇到異常,退出進(jìn)程前,回收資源 release_mqtt(); release_controller_devices(); sleep(1); exit(1); }
int init_controller_data(void) { controller.left.value = 0; controller.right.value = 0;
controller.Upperleft.value = 0; controller.Upperright.value = 0;
controller.Lowerleft.value = 0; controller.Lowerright.value = 0;
controller.go_straight.value = 0; controller.turn_left.value = 0;
controller.turn_right.value = 0;
controller.go_back.value = 0; controller.go_stop.value = 0;
controller.spray_water.value = 0; controller.left.flag = 0;
controller.right.flag = 0; controller.Upperleft.flag = 0;
controller.Upperright.flag = 0; controller.Lowerleft.flag = 0; controller.Lowerright.flag = 0; controller.go_straight.flag = 0;
controller.turn_left.flag = 0; controller.turn_right.flag = 0;
controller.go_back.flag = 0; controller.go_stop.flag = 0;
controller.spray_water.flag = 0; return 0; }
初始化MQTT
/* init_mqtt, 初始化,跟mqtt服務(wù)器建立鏈接,設(shè)置訂閱,創(chuàng)建通道管理線程,創(chuàng)建接收處理線程 */ int init_mqtt(void)
{ int32_t res = STATE_SUCCESS; uint16_t port = 443; /* 無論設(shè)備是否使用TLS連接阿里云平臺, 目的端口都是443 */
aiot_sysdep_network_cred_t cred; /* 安全憑據(jù)結(jié)構(gòu)體, 如果要用TLS, 這個結(jié)構(gòu)體中配置CA證書等參數(shù) */ char sub_topic[100] = {0}; /* 配置SDK的底層依賴 */
aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile); /* 配置SDK的日志輸出 */
aiot_state_set_logcb(demo_state_logcb); /* 創(chuàng)建SDK的安全憑據(jù), 用于建立TLS連接 */ memset(&cred, 0, sizeof(aiot_sysdep_network_cred_t)); cred.option = AIOT_SYSDEP_NETWORK_CRED_SVRCERT_CA; /* 使用RSA證書校驗MQTT服務(wù)端 */ cred.max_tls_fragment = 16384; /* 最大的分片長度為16K, 其它可選值還有4K, 2K, 1K, 0.5K */
cred.sni_enabled = 1; /* TLS建連時, 支持Server Name Indicator */ cred.x509_server_cert = ali_ca_cert; /* 用來驗證MQTT服務(wù)端的RSA根證書 */ cred.x509_server_cert_len = strlen(ali_ca_cert);
/* 用來驗證MQTT服務(wù)端的RSA根證書長度 */ /* 創(chuàng)建1個MQTT客戶端實例并內(nèi)部初始化默認(rèn)參數(shù) */
mqtt_handle = aiot_mqtt_init(); if (mqtt_handle == NULL) { printf("aiot_mqtt_init failed\n"); return -1; } /* TODO: 如果以下代碼不被注釋, 則例程會用TCP而不是TLS連接云平臺 */
{ memset(&cred, 0, sizeof(aiot_sysdep_network_cred_t)); cred.option = AIOT_SYSDEP_NETWORK_CRED_NONE; } /* 配置MQTT服務(wù)器地址 */ aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_HOST, (void *)mqtt_host); /* 配置MQTT服務(wù)器端口 */ aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_PORT, (void *)&port); /* 配置設(shè)備productKey */
aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_PRODUCT_KEY, (void *)product_key);
/* 配置設(shè)備deviceName */
aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_DEVICE_NAME, (void *)device_name);
/* 配置設(shè)備deviceSecret */ aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_DEVICE_SECRET, (void *)device_secret); /* 配置網(wǎng)絡(luò)連接的安全憑據(jù), 上面已經(jīng)創(chuàng)建好了 */
aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_NETWORK_CRED, (void *)&cred); /* 配置MQTT默認(rèn)消息接收回調(diào)函數(shù) */ aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_RECV_HANDLER, (void *)demo_mqtt_default_recv_handler); /* 配置MQTT事件回調(diào)函數(shù) */
aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_EVENT_HANDLER, (void *)demo_mqtt_event_handler);
/* 與服務(wù)器建立MQTT連接 */
res = aiot_mqtt_connect(mqtt_handle);
if (res < STATE_SUCCESS) { /* 嘗試建立連接失敗, 銷毀MQTT實例, 回收資源 */ aiot_mqtt_deinit(&mqtt_handle); printf("aiot_mqtt_connect failed: -0x%04X\n\r\n", -res); printf("please check variables like mqtt_host, produt_key, device_name, device_secret in demo\r\n"); return -1; }?
/* MQTT 訂閱topic功能示例, 請根據(jù)自己的業(yè)務(wù)需求進(jìn)行使用 */
{ strcpy(sub_topic, "/sys/k1l0mrfjkHG/control_unit_1/thing/service/property/set"); res = aiot_mqtt_sub(mqtt_handle, sub_topic, NULL, 1, NULL); if (res < 0) { printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res); return -1; } }?
/* 創(chuàng)建一個單獨的線程, 專用于執(zhí)行aiot_mqtt_process, 它會自動發(fā)送心跳?;? 以及重發(fā)QoS1的未應(yīng)答報文 */
g_mqtt_process_thread_running = 1; res = pthread_create(&g_mqtt_process_thread, NULL, demo_mqtt_process_thread, mqtt_handle); if (res < 0) { printf("pthread_create demo_mqtt_process_thread failed: %d\n", res); return -1; } /* 創(chuàng)建一個單獨的線程用于執(zhí)行aiot_mqtt_recv, 它會循環(huán)收取服務(wù)器下發(fā)的MQTT消息, 并在斷線時自動重連 */ g_mqtt_recv_thread_running = 1; res = pthread_create(&g_mqtt_recv_thread, NULL, demo_mqtt_recv_thread, mqtt_handle); if (res < 0) { printf("pthread_create demo_mqtt_recv_thread failed: %d\n", res); return -1; } return 0; }
同步設(shè)備數(shù)據(jù)到MQTT服務(wù)器
demo_mqtt_send_handler(SET_STRAIGHT_TO_SEND); demo_mqtt_send_handler(SET_LEFT_TO_SEND); demo_mqtt_send_handler(SET_RIGHT_TO_SEND); demo_mqtt_send_handler(SET_BACK_TO_SEND); demo_mqtt_send_handler(SET_STOP_TO_SEND); demo_mqtt_send_handler(SET_WATER_TO_SEND); demo_mqtt_send_handler(SET_UPPERLEFT_TO_SEND); demo_mqtt_send_handler(SET_LOWERLEFT_TO_SEND); demo_mqtt_send_handler(SET_UPPERRIGHT_TO_SEND); demo_mqtt_send_handler(SET_LOWERRIGHT_TO_SEND);
設(shè)置控制器參數(shù)
set_controller(Upperleft, 5.0); set_controller(Lowerleft, 5.0); set_controller(Upperright, 5.0); set_controller(Lowerright, 5.0); set_controller(left, 1.0); set_controller(right, 1.0); set_controller(c8, 1.0);
GPIO線程
// GPIO線程函數(shù) void *gpio_thread(void *arg) { while (1) { int value = 0; set_gpio(c9, 114); value = read_gpio_value(c9_GPIO_VALUE); pthread_mutex_lock(&gpio_mutex); printf("Value: %d\n", value); if (value == -1) { printf("Error occurred while reading file: %s\n", c9_GPIO_VALUE); } if (value == 0) { cspray_water(); } pthread_mutex_unlock(&gpio_mutex); usleep(100000); } return NULL; } // 創(chuàng)建GPIO線程 if (pthread_create(&gpio_tid, NULL, gpio_thread, NULL) != 0) { perror("pthread_create for gpio_thread"); goto to_end; }
MQTT線程
// MQTT線程函數(shù) void *mqtt_thread(void *arg) { while (1) { pthread_mutex_lock(&mqtt_mutex); if (controller.Upperleft.flag == 1) { demo_mqtt_send_handler(SET_UPPERLEFT_TO_SEND); controller.Upperleft.flag = 0; } if (controller.Lowerleft.flag == 1) { demo_mqtt_send_handler(SET_LOWERLEFT_TO_SEND); controller.Lowerleft.flag = 0; } if (controller.Upperright.flag == 1)
{ demo_mqtt_send_handler(SET_UPPERRIGHT_TO_SEND); controller.Upperright.flag = 0; } if (controller.Lowerright.flag == 1) { demo_mqtt_send_handler(SET_LOWERRIGHT_TO_SEND); controller.Lowerright.flag = 0; } if (controller.go_straight.flag == 1)
{ demo_mqtt_send_handler(SET_STRAIGHT_TO_SEND); controller.go_straight.flag = 0;
} if (controller.turn_left.flag == 1) { demo_mqtt_send_handler(SET_LEFT_TO_SEND);
controller.turn_left.flag = 0; } if (controller.turn_right.flag == 1) { demo_mqtt_send_handler(SET_RIGHT_TO_SEND); controller.turn_right.flag = 0;
} if (controller.go_back.flag == 1) { demo_mqtt_send_handler(SET_BACK_TO_SEND);
controller.go_back.flag = 0; } if (controller.go_stop.flag == 1) { demo_mqtt_send_handler(SET_STOP_TO_SEND);
controller.go_stop.flag = 0; } if (controller.spray_water.flag == 1) { demo_mqtt_send_handler(SET_WATER_TO_SEND); controller.spray_water.flag = 0; } pthread_mutex_unlock(&mqtt_mutex); usleep(100000); } return NULL; } // 創(chuàng)建MQTT線程 if (pthread_create(&mqtt_tid, NULL, mqtt_thread, NULL) != 0) { perror("pthread_create for mqtt_thread"); goto to_end; }
4、應(yīng)用編譯
(1)拷貝car.tar.bz2到開發(fā)環(huán)境/home/elf/work目錄下解壓
elf@ubuntu:~/work$ tar xvf car.tar.bz2
(2)執(zhí)行環(huán)境變量
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到開發(fā)板/home/root路徑下
root@ELF1:~# cp /run/media/sda1/mqtt_test ./
設(shè)項目測試
1、設(shè)置Wi-Fi連接
root@ELF1:~# elf1_cmd_wifi.sh -i 8723 -s 賬號 -p 密碼
2、執(zhí)行應(yīng)用
root@ELF1:~# ./mqtt_test
此時可以通過Web界面下發(fā)指令控制小車運行
Web界面將實時顯示小車的運行狀態(tài)
至此,就已完成了對智能消防車這一開源項目的詳細(xì)介紹。衷心希望這份指南能為有志于學(xué)習(xí)嵌入式技術(shù)的小伙伴們提供實質(zhì)性的幫助與啟發(fā)。
-
單片機
+關(guān)注
關(guān)注
6039文章
44573瀏覽量
636294 -
嵌入式
+關(guān)注
關(guān)注
5086文章
19142瀏覽量
306035 -
開發(fā)板
+關(guān)注
關(guān)注
25文章
5078瀏覽量
97671 -
智慧城市
+關(guān)注
關(guān)注
21文章
4269瀏覽量
97445 -
開源項目
+關(guān)注
關(guān)注
0文章
38瀏覽量
7209
發(fā)布評論請先 登錄
相關(guān)推薦
評論