智慧城市的建設(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)遠程控制,使得用戶可以遠程控制車到達指定地點進行滅火,或者通過火焰?zhèn)鞲衅鳈z測到火焰時自動響應(yīng)滅火操作。
功能特性
1、數(shù)據(jù)監(jiān)測與顯示:實時監(jiān)測車運行狀態(tài),并直觀地顯示在Web界面上。
2、Web可視化界面:用戶可以通過Web界面遠程控制車的移動。
3、遠程控制:通過阿里云物聯(lián)網(wǎng)平臺向車發(fā)送指令,實現(xià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
硬件連接
小車驅(qū)動裝置主要由TB6612FNG雙電機驅(qū)動板、TT馬達、車輪等組成。
(1)TB6612FNG雙電機驅(qū)動板

滅火裝置主要由火焰?zhèn)鞲衅?、繼電器、水泵等組成。
(1)火焰?zhèn)鞲衅?/p>

(2)繼電器

(3)水泵

3、整體連接示意圖

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ù)用完成。
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功能的地方



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
基于云平臺的遠程數(shù)據(jù)監(jiān)測和設(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);
? ? // 設(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);
? ? // 同步控制器狀態(tài)到MQTT服務(wù)器
? ? 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;
? ? }
? ? // 等待線程結(jié)束
? ? pthread_join(gpio_tid, NULL);
? ? pthread_join(mqtt_tid, NULL);
to_end:
? ? // 遇到異常,退出進程前,回收資源
? ? release_mqtt();
? ? release_controller_devices();
? ? sleep(1);
? ? exit(1);
}
初始化控制器參數(shù)
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)部初始化默認參數(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默認消息接收回調(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ù)需求進行使用 */
? ? {
? ? ? ? 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);? // 設(shè)置GPIO
? ? ? ? value = read_gpio_value(c9_GPIO_VALUE);? // 讀取GPIO值
? ? ? ? pthread_mutex_lock(&gpio_mutex);? // 鎖定互斥鎖
? ? ? ? printf("Value: %d\n", value);? // 打印GPIO值
? ? ? ? if (value == -1)?
? ? ? ? {
? ? ? ? ? ? printf("Error occurred while reading file: %s\n", c9_GPIO_VALUE);? // 錯誤處理
? ? ? ? }
? ? ? ? if (value == 0)?
? ? ? ? {
? ? ? ? ? ? cspray_water();? // 調(diào)用噴水函數(shù)
? ? ? ? }
? ? ? ? pthread_mutex_unlock(&gpio_mutex);? // 解鎖互斥鎖
? ? ? ? usleep(100000);? // 線程休眠100ms
? ? }
? ? 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);? // 鎖定互斥鎖
? ? ? ? // 檢查各控制器標志位并發(fā)送對應(yīng)的MQTT消息
? ? ? ? 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);? // 線程休眠100ms
? ? }
? ? 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 ./
項目測試
1、設(shè)置Wi-Fi連接
root@ELF1:~# elf1_cmd_wifi.sh -i 8723 -s 賬號 -p 密碼

此時可以通過Web界面下發(fā)指令控制小車運行

Web界面將實時顯示小車的運行狀態(tài)

至此,就已完成了對智能消防車這一開源項目的詳細介紹。衷心希望這份指南能為有志于學習嵌入式技術(shù)的小伙伴們提供實質(zhì)性的幫助與啟發(fā)。
