项目思路:
近年来国内乘用车数量达到一个非常高的数量,但是报纸上时有儿童被忘在车内的情况,后果严重者影响儿童生命健康。本项目旨在利用部署在车内的多个超声波传感器来判断车内人员活动情况,并且结合四个车门的状态来甄别儿童单独在车内的情况。如果出现这种状态达到3min,启动报警功能。本项目提供的报警包括
1)通过MQTT服务通知驾驶员手机,其中wifi功能由现有的ESP模块来提供;
2)检测到后座上儿童活动后,触发报警,通过MQTT客户端通知家长
3)检测到后座上儿童活动后,发送给别的报警单元
项目实现:为了检测遗留车内儿童活动,本项目使用超声波传感器。在车内没有儿童活动的时候,超声波传感器的数据维持不变,但是有儿童来回活动,遮挡住超声波传感器的时候,数据摆幅非常大,以此来作为一个判断依据。在实现上,采用了一颗乐鑫公司的ESP32S3单片机来专门用于采集超声波传感器数据。
本次项目采用的传感器型号是:HC-SR04,其基本工作原理如下:
ESP32S3采集超声波数据和声音传感器的数据,开发环境使用Arduino,利用FreeRTOS创建了两个单独的线程来分别处理传感器数据和MQTT。
xTaskCreatePinnedToCore( TaskMqtt , "TaskMqtt" // A name just for humans , 10240 // This stack size can be checked & adjusted by reading the Stack Highwater , NULL , 1 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest. , NULL , 1); xTaskCreatePinnedToCore( TaskSensor , "TaskSensor" // A name just for humans , 1024 // This stack size can be checked & adjusted by reading the Stack Highwater , NULL , 2 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest. , NULL , 1);
在检测逻辑上,主要判断依据是座椅上没有人的时候,超声波传感器数据变动不会超过5cm。当前传感器固定位置距离橱窗的距离是57cm,当有物体进入检测范围后,测量距离会变化。
if(fabs((int)distance - 57) >= 5){ display.println(F("HASCHILD")); digitalWrite(WarningPin, HIGH); digitalWrite(WarningPinExt, HIGH); childDetectFlag = 1; Serial.println("Child Detected"); }else{ display.println(F("NO CHILD")); digitalWrite(WarningPin, LOW); digitalWrite(WarningPinExt, LOW); Serial.println("No Child Found"); }实物照片:
手机MQTT客户端使用的是MQTT DashBoard。
附完整源代码:
/************************************************************************** This is to detect any child alone in the car. Mainly to use ultrasonic sensors to detect the child and then report via MQTT to the parent. **************************************************************************/ #include <SPI.h> #include <Wire.h> #include <WiFi.h> #include "secrets.h" #include <PubSubClient.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) // The pins for I2C are defined by the Wire-library. // On an arduino UNO: A4(SDA), A5(SCL) // On an arduino MEGA 2560: 20(SDA), 21(SCL) // On an arduino LEONARDO: 2(SDA), 3(SCL), ... #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) #define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32. SensorYoung: 2024/1/29 0x3C Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); #define NUMFLAKES 10 // Number of snowflakes in the animation example #define LOGO_HEIGHT 16 #define LOGO_WIDTH 16 static const unsigned char PROGMEM logo_bmp[] = { 0b00000000, 0b11000000, 0b00000001, 0b11000000, 0b00000001, 0b11000000, 0b00000011, 0b11100000, 0b11110011, 0b11100000, 0b11111110, 0b11111000, 0b01111110, 0b11111111, 0b00110011, 0b10011111, 0b00011111, 0b11111100, 0b00001101, 0b01110000, 0b00011011, 0b10100000, 0b00111111, 0b11100000, 0b00111111, 0b11110000, 0b01111100, 0b11110000, 0b01110000, 0b01110000, 0b00000000, 0b00110000 }; const int TrigPin = 16; const int EchoPin = 17; const int WarningPinExt = 4; const int WarningPin = 2; //2/D9 is the User LED on ESP32,高电平点亮LED static float distance = 0; void HC_SR04_DistMeasure(void); //----------------------------MQTT Related Start --------------------- char ssid[] = SECRET_SSID; // your network SSID (name) char pass[] = SECRET_PASS; // your network password const char* mqtt_server = "broker.hivemq.com"; // hivemq 的信息中转服务 const unsigned short mqtt_server_port = 1883; const char* pubTOPIC = "car/backseat/childDetect/"; // 发布信息主题 const char* client_id = "clientId-tobeasafecar"; // 标识当前设备的客户端编号 WiFiClient espClient; PubSubClient client(espClient); // 定义PubSubClient的实例 long lastMsg = 0; // 记录上一次发送信息的时长 unsigned char childDetectFlag = 0; //----------------------------MQTT Related END --------------------- /*-------------------------------------------------------------*/ /*---------------------- Tasks - setup () ---------------------*/ /*-------------------------------------------------------------*/ void setup() { Serial.begin(115200); // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) { Serial.println(F("SSD1306 allocation failed")); for(;;); // Don't proceed, loop forever } WiFi.mode(WIFI_STA); // Show initial display buffer contents on the screen -- // the library initializes this with an Adafruit splash screen. display.display(); delay(2000); // Pause for 2 seconds pinMode(TrigPin, OUTPUT); pinMode(EchoPin, INPUT); pinMode(WarningPin, OUTPUT); digitalWrite(WarningPin, LOW); pinMode(WarningPinExt, OUTPUT); digitalWrite(WarningPinExt, LOW); Serial.println("HC-SR04 Init done."); // Now set up tasks to run independently. #if 1 xTaskCreatePinnedToCore( TaskMqtt , "TaskMqtt" // A name just for humans , 10240 // This stack size can be checked & adjusted by reading the Stack Highwater , NULL , 1 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest. , NULL , 1); #endif xTaskCreatePinnedToCore( TaskSensor , "TaskSensor" // A name just for humans , 1024 // This stack size can be checked & adjusted by reading the Stack Highwater , NULL , 2 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest. , NULL , 1); } /*-------------------------------------------------------------*/ /*---------------------- Tasks - mainloop ---------------------*/ /*-------------------------------------------------------------*/ void TaskSensor(void *pvParameters) // This is a task. { (void) pvParameters; for(;;){ digitalWrite(TrigPin, LOW); delayMicroseconds(2); digitalWrite(TrigPin, HIGH); delayMicroseconds(10); digitalWrite(TrigPin, LOW); distance = pulseIn(EchoPin, HIGH)/58.00; vTaskDelay(pdMS_TO_TICKS(1000)); //休眠1000毫秒 } } void HC_SR04_DistMeasure(void){ digitalWrite(TrigPin, LOW); delayMicroseconds(2); digitalWrite(TrigPin, HIGH); delayMicroseconds(10); digitalWrite(TrigPin, LOW); distance = pulseIn(EchoPin, HIGH)/58; } void loop() { //HC_SR04_DistMeasure(); display.clearDisplay(); display.setTextSize(2); // Draw 2X-scale text display.setTextColor(SSD1306_WHITE); display.setCursor(0, 0); // Start at top-left corner display.println(F("HC-SR04")); //display.display(); display.println(F("DISTANCE:")); //display.display(); display.println((int)distance); //display.display(); if(fabs((int)distance - 57) >= 5){ display.println(F("HASCHILD")); digitalWrite(WarningPin, HIGH); digitalWrite(WarningPinExt, HIGH); childDetectFlag = 1; Serial.println("Child Detected"); }else{ display.println(F("NO CHILD")); digitalWrite(WarningPin, LOW); digitalWrite(WarningPinExt, LOW); Serial.println("No Child Found"); } display.display(); Serial.print(distance); Serial.println("cm"); delay(1000); } /*-------------------------------------------------------------*/ /*---------------------- Tasks - TaskMqtt ---------------------*/ /*-------------------------------------------------------------*/ void reconnect() { while (!client.connected()) { Serial.print("Attempting MQTT connection..."); // Attempt to connect if (client.connect(client_id)) { Serial.println("connected"); // 连接成功时订阅主题 //client.subscribe(TOPIC); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); // Wait 5 seconds before retrying delay(5000); } } } #if 0 void TaskMqtt(void *pvParameters) // This is a task. { (void) pvParameters; for(;;){ ; } } #endif #if 1 void TaskMqtt(void *pvParameters) // This is a task. { (void) pvParameters; Serial.print("TaskMqtt 在核心 ");Serial.print(xPortGetCoreID());Serial.println(" 上运行"); // Connect or reconnect to WiFi // Connect or reconnect to WiFi if(WiFi.status() != WL_CONNECTED){ Serial.print("Attempting to connect to SSID: "); Serial.println(SECRET_SSID); while(WiFi.status() != WL_CONNECTED){ WiFi.begin(ssid, pass); // Connect to WPA/WPA2 network. Change this line if using open or WEP network Serial.print("."); delay(5000); } Serial.println("\nConnected."); } client.setServer(mqtt_server, mqtt_server_port); //设定MQTT服务器与使用的端口,1883是默认的MQTT端口 for (;;) // A Task shall never return or exit. { if (!client.connected()) { reconnect(); } client.loop(); if (childDetectFlag) { childDetectFlag = 0; if(client.publish(pubTOPIC, "Child in the CAR!!")){ Serial.println("Publish Topic:");Serial.println(pubTOPIC); Serial.println("Publish message:");Serial.println("Child in the CAR!!"); } else { Serial.println("Message Publish Failed."); } }//endif }//end for-loop }//end TaskMQTT #endif