2022-11-11 15:22:41 [显示全部楼层]
6792浏览
查看: 6792|回复: 2

[ESP8266/ESP32] 自动闸门装置-基于ESP32 & 物联网

[复制链接]
本帖最后由 France 于 2022-11-14 14:08 编辑

我的家门口对着马路,所以我装了个大门,但是每次开车进出门都得自己下来打开关闭,这实在是太不方便了。网上看了下自动门的价格,额,还是自己动手做个吧!
我之前做了一版,但这次我又做了次改进。我用了新升级内置了霍尔传感器的线性执行器,新的ESP32主板,每个通道可达到15A@13.8V的新双电机驱动器模块,以及新的防水超声波传感器。

这就是最后的效果:

自动闸门装置-基于ESP32 & 物联网图1
材料清单如

5. 防水柔性LED灯带  ×2
6. LD1117V33 电源管理芯片  ×1
7. 10 µF电容 ×2
8. 12V 350W 电源 ×1
9. 霍尔线性执行器 12V/12A IP65  ×2
软件
10. NPN mos管 ×4

软件平台


工具
  • 通用型焊铁
  • 无铅焊线
  • 无绳钻孔机/驱动器

接线


接线看起来很复杂,但是你真正上手时会发现其实还好。本项目对应的接线如下:

电机驱动板 – FireBeetle 主板:

  • M2Speed - IO17
  • M2Dir - IO13
  • M1Speed - IO16
  • M1Dir - IO14
  • +5V - VCC
  • GND - GND
超声波距离传感器- FireBeetle主板:

  • +3.3V - +3.3V
  • GND - GND
  • RX - IO22
  • TX - IO21

      聚光灯 - FireBeetle:
  • 晶体管Gate - IO12
     LED 灯带 - FireBeetle:
  • 第一个晶体管gate - IO25
  • 第二个晶体管gate - IO27
  • 第三个晶体管 gate - IO5

    磁力锁- FireBeetle:
  • 晶体管 Gate - IO2


    电流传感器 - FireBeetle:
  • AO - A0
具体细节参考下图:




Blynk

这是桌面模板完成后的外观:


手机上的样例:




如果需要帮助设置Blynk,请参阅此处的文档:  https://docs.blynk.io/en/




代码

这个项目的代码很长。你要用的话可能需要更改一些内容。例如,我的左执行器似乎打开得比关闭得慢,所以我必须调整打开和关闭功能来解决这个问题。
drivewaygates.ino:

  1. #define BLYNK_TEMPLATE_ID "************"
  2. #define BLYNK_DEVICE_NAME "********"
  3. #define BLYNK_AUTH_TOKEN "*******************************"
  4. #define BLYNK_PRINT Serial
复制代码

首先,我们必须设置Blynk凭据。在指定的行中输入模板id、设备名称和身份验证令牌。

  1. #include <WiFi.h>
  2. #include <WiFiClient.h>
  3. #include <BlynkSimpleEsp32.h>
  4. #include <WiFiUdp.h>
  5. #include <ArduinoOTA.h>
  6. #include <SoftwareSerial.h>
复制代码
接下来,我们需要的所有库都包括在内;WiFi、Blynk、OTA和软件系列。

  1. #define motorAspeed   16//D11
  2. #define motorBspeed   17//D10
  3. #define motorAdir     14//D6
  4. #define motorBdir     13//D7
  5. #define hall          26//D3
  6. #define ultra1        22
  7. #define ultra2        21
  8. #define currentIn     A0
  9. #define pinRed        D4
  10. #define pinGreen      D3
  11. #define pinBlue       4//D12
  12. #define magnet        D9//D13
  13. #define light         4//D12
复制代码


在这里,我们定义了哪些引脚连接到哪些零件。任何不以“D”开头的引脚都是FireBeetle上的 IO口。

  1. /* Current Sensor (currently not working)
  2. const int numReadings = 30;
  3. float readings[numReadings];      // the readings from the analog input
  4. int inde = 0;                  // the inde of the current reading
  5. float total = 0;                  // the running total
  6. float average = 0;                // the average
  7. float currentValue = 0;
  8. */
复制代码
以下是当前传感器读数和变量,但在编写本文时,此部分不起作用。我希望尽快更新!

  1. int ppi = 300; //pulses per inch (for the PA-04 Linear Actuator).  Change this according to your specs.
  2. int usedAct = 6; //inches of actuator used
  3. char ssid[] = "************";//WiFi network name
  4. char pass[] = "********";//WiFi network password
复制代码

所有这些变量都必须更改!首先是ppi变量,它代表“每英寸脉冲数”。该值取决于所使用的线性执行器,一英寸对应的霍尔传感器的脉冲量。接下来是usedAct变量。该变量是使用的线性执行器上的英寸数。您可能需要多次调整此数字以获得所需效果。最后,是WiFi证书。输入您希望模块连接到的WiFi网络名称和密码。

  1. //Gate button value for Blynk
  2. int button;
  3. int timer;
  4. //current sensor value
  5. float voltage;
  6. //ultrasonic sensor
  7. unsigned char data[4] = {};
  8. float distance;
  9. float inches;
  10. int car;
  11. int carDist = 24;//alter this value! This value is distance in inches before something is activated
  12. int tim = 10000;
  13. long hallCount;
  14. //gate status flag
  15. boolean flag = false;
  16. //LED strip starting values
  17. int red = 255;
  18. int green = 255;
  19. int blue = 255;
复制代码

这些是使用的所有其他变量。唯一需要修改的是carDist变量。这是汽车被定义为存在之前的英寸数。

  1. SoftwareSerial ultraSerial;
复制代码

这里,我们定义了超声传感器的软件序列实例。

  1. BLYNK_WRITE(V0){
  2.   button = param.asInt();
  3. }
  4. BLYNK_WRITE(V1){
  5.   red = param.asInt();
  6. }
  7. BLYNK_WRITE(V2){
  8.   green = param.asInt();
  9. }
  10. BLYNK_WRITE(V3){
  11.   blue = param.asInt();
  12. }
  13. BLYNK_WRITE(V4){
  14.   int spotlight = param.asInt();
  15.   if (spotlight){
  16.     digitalWrite(light, HIGH);
  17.   }
  18.   else {
  19.     digitalWrite(light, LOW);
  20.   }
  21. }
  22. String string;
  23. BLYNK_WRITE(V10) {
  24.   string = param.asStr();
  25.   if (string == "restart"){
  26.     Blynk.virtualWrite(V10, "Restarting...");
  27.     Serial.println("Restarting...");
  28.     delay(2000);
  29.     ESP.restart();
  30.   }
  31. }
复制代码
这些都是用于接收值的Blynk函数

  1. //gate status flag
  2. boolean isOpen = false;
复制代码

这是一个布尔变量,用于指示门是打开还是关闭。

  1. //PWM information
  2. const int freq = 5000;
  3. const int resolution = 8;
  4. const int redChannel = 1;
  5. const int greenChannel = 2;
  6. const int blueChannel = 3;
  7. const int motorA = 4;
  8. const int motorB = 5;
复制代码

Arduino相比,ESP32上的PWM稍微复杂一些,但更易于定制。这里,我们设置频率、分辨率,然后设置需要PWM的信道。

  1. void setup() {
  2.   Serial.begin(115200);
  3.   ultraSerial.begin(9600, SWSERIAL_8N1, ultra1, ultra2, false); // RX, TX
  4.   if (!ultraSerial) { // If the object did not initialize, then its configuraiton is invalid
  5.     Serial.println("Invalid SoftwareSerial pin configuration, check config");
  6.   }
复制代码

voidsetup()中,我们首先启动串行进行调试(请记住,只有当设备通过导线连接到您的PC时,这才有效;不要用OTA),为超声波传感器启动串行口,并检查以确保传感器已启动。

  1. //set pinModes
  2.   pinMode(motorAspeed, OUTPUT);
  3.   pinMode(motorBspeed, OUTPUT);
  4.   pinMode(motorAdir, OUTPUT);
  5.   pinMode(motorBdir, OUTPUT);
  6.   pinMode(pinRed, OUTPUT);
  7.   pinMode(pinGreen, OUTPUT);
  8.   pinMode(pinBlue, OUTPUT);
  9.   pinMode(hall, INPUT_PULLUP);
  10.   pinMode(currentIn, INPUT);
  11.   pinMode(magnet, OUTPUT);
  12.   pinMode(light, OUTPUT);
复制代码

接下来,我们设置pinmodes;除霍尔传感器外,它们都是输出,霍尔传感器是一个输入上拉。

  1. //attach PWM channels to the correct pins
  2.   ledcAttachPin(pinRed, redChannel);
  3.   ledcAttachPin(pinGreen, greenChannel);
  4.   ledcAttachPin(pinBlue, blueChannel);
  5.   ledcAttachPin(motorAspeed, motorA);
  6.   ledcAttachPin(motorBspeed, motorB);
  7.   //setup the PWM channels
  8.   ledcSetup(redChannel, freq, resolution);
  9.   ledcSetup(greenChannel, freq, resolution);
  10.   ledcSetup(blueChannel, freq, resolution);
  11.   ledcSetup(motorA, freq, resolution);
  12.   ledcSetup(motorB, freq, resolution);
复制代码
这里,PWM已设置。首先,我们将引脚连接到正确的通道,然后为每个通道设置通道频率和分辨率。

  1. //connect to the WiFi
  2.   wificonnect();
  3.   //Start Blynk
  4.   Serial.println("Blynk Starting...");
  5.   Blynk.config(BLYNK_AUTH_TOKEN);
  6.   //Start OTA
  7.   Serial.println("OTA Starting...");
  8.   OTAStart();
复制代码

这三个部分能让我们的无线网络正常运行。首先,我们连接到WiFi,然后配置Blynk,最后启动OTA。OTA默认密码为“maker”;这可以在OTAStart()函数中更改。

  1. //open the gates all the way at the beginning to set the hall sensor back at 0
  2.   Serial.println("Begin opening...");
  3.   delay(1000);
  4.   beginOpen();
  5.   hallCount = ppi*usedAct;
  6.   isOpen = true;
  7.   Serial.println("Attaching interrupt...");
  8.   attachInterrupt(digitalPinToInterrupt(hall), interruptName, FALLING);//Interrupt initialization
  9.   //then close to the correct place, keeping track of the hall count
  10.   Serial.println("Closing to correct place...");
  11.   close();
  12.   Serial.println("Done closing!");
  13.   Serial.println("Ready");
  14.   isOpen = false;
复制代码
闸门设置完成了voidsetup(); 设置,首先,闸门在不使用霍尔传感器的情况下一直打开。这就像一种校准,因为当闸门完全打开到极限时,我们就能确定霍尔传感器的位置!接下来,连接霍尔传感器,因为如果我们在打开功能开始之前连接霍尔传感器中断,霍尔传感器将开始计数,我们不想在校准时这样做。现在我们可以靠近正确的位置,一边走边计数霍尔脉冲,以确保闸门正确关闭。当它们已关闭,我们将闸门状态布尔值设置为false,表示闸门已成功关闭。

  1. void loop() {
  2.   //if WiFi was lost, reconnect
  3.   if (WiFi.status() == WL_CONNECTION_LOST){
  4.     Serial.println("Connection lost...");
  5.     wificonnect();
  6.   }
  7.   //handle the OTA
  8.   ArduinoOTA.handle();
复制代码

voidloop()检查WiFi连接,处理OTA。

  1. //ultrasonic sensor reading
  2.   for (int i=0;i<4;i++){
  3.     Serial.println("Checkdist();");
  4.     ArduinoOTA.handle();
  5.     checkDist();
  6.   }
  7.   Blynk.virtualWrite(V8,inches);
  8.   if (inches <= carDist){
  9.     Serial.println("Car");
  10.     Blynk.virtualWrite(V9, HIGH);
  11.   }
  12.   else {
  13.     Blynk.virtualWrite(V9, LOW);
  14.   }
复制代码
这里,我们多次读取超声波传感器,以确保获得良好的读数。然后我们将值发送给Blynk,检查是否有车,并相应地更新Blynk的LED。

  1. //if Blynk button pressed, switch the flag
  2.   if (button == HIGH){
  3.     flag = !flag;
  4.   }
  5.   //check to see if the flag is true, then check if the gates are closed and open them
  6.   if (flag == true && isOpen == false) {
  7.     digitalWrite(magnet, LOW);
  8.     delay(100);
  9.     open();
  10.     isOpen = true;
  11.   }
  12.   //else, check to see if the gates are open, and close them
  13.   else if (flag == false && isOpen == true) {
  14.     close();
  15.     delay(100);
  16.     digitalWrite(magnet, HIGH);
  17.     isOpen = false;
复制代码

如果按下Blynk的“门”按钮,则切换标志。如果标志为真,且闸门关闭,磁铁闭合,打开闸门,并将状态设置为打开!如果标志为假且闸门打开,关闭闸门,磁铁打开,并将状态设置为关闭。

  1. //write the Blynk values to the LED strips
  2.   ledcWrite(redChannel, red);
  3.   ledcWrite(greenChannel, green);
  4.   ledcWrite(blueChannel, blue);
  5.   //run Blynk, yield() to prevent unwanted resets, and delay 1 millisecond to keep track of time
  6.   Blynk.run();
  7.   yield();
  8.   delay(1);
复制代码
voidloop()的最后一部分中,Blynk值被写入LED灯带中,Blynk运行,我们确保yield();如果我们不增加yield,ESP32将意外重启,并可能导致问题。

  1. void wificonnect(){
  2.   Serial.println("WiFi Connecting...");
  3.   WiFi.mode(WIFI_STA);
  4.   WiFi.begin(ssid, pass);
  5.   while (WiFi.status() != WL_CONNECTED){
  6.     Serial.print(".");
  7.     delay(1000);
  8.   }
  9.   Serial.println("");
  10.   while (WiFi.waitForConnectResult() != WL_CONNECTED) {
  11.     Serial.println("Connection Failed! Rebooting...");
  12.     delay(5000);
  13.     ESP.restart();
  14.   }
  15. }
  16. void checkDist(){
  17.   retry:
  18.   do {
  19.     for (int i = 0; i < 4; i++){
  20.       data[i] = ultraSerial.read();
  21.     }
  22.   }
  23.   while (ultraSerial.read() == 0xff);
  24.   ultraSerial.flush();
  25.   if (data[0] == 0xff) {
  26.     int sum;
  27.     sum = (data[0] + data[1] + data[2]) & 0x00FF;
  28.     if (sum == data[3]) {
  29.       distance = (data[1] << 8) + data[2];
  30.       if (distance > 20) {
  31.         inches = distance / 25.4; //mm to inches
  32.         Serial.print(distance / 10);
  33.         Serial.println("in");
  34.       } else {
  35.         inches = 0;
  36.         Serial.println("Below the lower limit");
  37.       }
  38.     } else goto retry;//Serial.println("ERROR");
  39.   }
  40.   delay(100);
  41. }
  42. void beginOpen(){
  43.   bodo:
  44.   digitalWrite(motorAdir, HIGH);
  45.   digitalWrite(motorBdir, HIGH);
  46.   ledcWrite(motorA, 255);
  47.   ledcWrite(motorB, 255);
  48.   yield();
  49.   timer++;
  50.   delay(1);
  51.   while (timer < 24000){
  52.     yield();
  53.     goto bodo;
  54.   }
  55.   timer = 0;
  56.   Serial.println("Done!");
  57.   ledcWrite(motorA, 0);
  58.   ledcWrite(motorB, 0);
  59. }
  60. void open(){
  61.   int times=0;
  62.   hallCount = 0;
  63.   redo:
  64.   digitalWrite(motorAdir, HIGH);
  65.   digitalWrite(motorBdir, HIGH);
  66.   ledcWrite(motorA, 255);
  67.   ledcWrite(motorB, 255);
  68.   while (hallCount < ppi*usedAct){
  69.     yield();
  70.     Serial.print("Hall count: ");
  71.     Serial.println(hallCount);
  72.     goto redo;
  73.   }
  74.   delay(500);
  75.   tedo:
  76.   digitalWrite(motorAdir, HIGH);
  77.   digitalWrite(motorBdir, HIGH);
  78.   ledcWrite(motorA, 255);
  79.   ledcWrite(motorB, 255);
  80.   times++;
  81.   delay(1);
  82.   yield();
  83.   while (times < 7000){
  84.     goto tedo;
  85.   }
  86.   times=0;
  87.   yield();
  88.   ledcWrite(motorA, 0);
  89.   ledcWrite(motorB, 0);
  90. }
  91. void close(){
  92.   hallCount = ppi*usedAct;
  93.   redone:
  94.   digitalWrite(motorAdir, LOW);
  95.   digitalWrite(motorBdir, LOW);
  96.   ledcWrite(motorA, 255);
  97.   ledcWrite(motorB, 255);
  98.   while (hallCount > 0){
  99.     yield();
  100.     Serial.print("Hall count: ");
  101.     Serial.println(hallCount);
  102.     goto redone; //goto endy;
  103.   }
  104.   yield();
  105.   ledcWrite(motorA, 0);
  106.   ledcWrite(motorB, 0);
  107.   digitalWrite(motorAdir, HIGH);
  108.   digitalWrite(motorBdir, HIGH);
  109.   Serial.println("Gates closed");
  110. }
  111. void OTAStart(){
  112.   // Port defaults to 8266
  113.   ArduinoOTA.setPort(8266);
  114.   // Hostname defaults to esp8266-[ChipID]
  115.   ArduinoOTA.setHostname("DrivewayESP");
  116.   // No authentication by default .
  117.   ArduinoOTA.setPassword("maker");
  118.   // Password can be set with it's md5 value as well
  119.   // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
  120.   // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");
  121.   ArduinoOTA.onStart([]() {
  122.   //open();
  123.   String type;
  124.   if (ArduinoOTA.getCommand() == U_FLASH) {
  125.     type = "sketch";
  126.   } else { // U_FS
  127.     type = "filesystem";
  128.   }
  129.   // NOTE: if updating FS this would be the place to unmount FS using FS.end()
  130.   Serial.println("Start updating " + type);
  131.   });
  132.   ArduinoOTA.onEnd([]() {
  133.     Serial.println("\nEnd");
  134.   });
  135.   ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
  136.     Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  137.   });
  138.   ArduinoOTA.onError([](ota_error_t error) {
  139.   Serial.printf("Error[%u]: ", error);
  140.   if (error == OTA_AUTH_ERROR) {
  141.     Serial.println("Auth Failed");
  142.   } else if (error == OTA_BEGIN_ERROR) {
  143.     Serial.println("Begin Failed");
  144.   } else if (error == OTA_CONNECT_ERROR) {
  145.     Serial.println("Connect Failed");
  146.   } else if (error == OTA_RECEIVE_ERROR) {
  147.     Serial.println("Receive Failed");
  148.   } else if (error == OTA_END_ERROR) {
  149.     Serial.println("End Failed");
  150.   }
  151.   });
  152.   ArduinoOTA.begin();
  153.   Serial.println("Ready");
  154.   Serial.print("IP address: ");
  155.   Serial.println(WiFi.localIP());
  156. }
  157. ICACHE_RAM_ATTR void interruptName() {
  158.   if (isOpen == false){
  159.     hallCount++;
  160.     if (hallCount >= ppi*usedAct){
  161.       //ledcWrite(motorA, 0);
  162.       //ledcWrite(motorB, 0);
  163.       digitalWrite(hall, HIGH);
  164.       hallCount = ppi*usedAct;
  165.       //delay(1000);
  166.     }
  167.   }
  168.   else if (isOpen == true){
  169.     hallCount--;
  170.     if (hallCount <= 0){
  171.       ledcWrite(motorA, 0);
  172.       ledcWrite(motorB, 0);
  173.       digitalWrite(hall, HIGH);
  174.       hallCount = 0;
  175.       //delay(1000);
  176.     }
  177.   }
  178.   //currentVal();
  179. }
复制代码

这些都是我为简化代码而做的所有函数。注意最后一个函数有什么不同吗?这就是中断函数。有关ESP32中断的更多信息,请查看此链接












作者:K Gray  2022/10/29
原出处:https://www.hackster.io/k-gray/automated-driveway-gates-version-2-6d9b2e









HonestQiao  初级技匠

发表于 2022-11-13 15:52:36

相当实用!!!
回复

使用道具 举报

France  高级技师
 楼主|

发表于 2022-11-14 09:55:30


  ~·~
回复

使用道具 举报

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

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail