• 物联网手势控制小车所遇问题与解决方案


    LCD1602无法显示问题

    问题描述:按照开源社区教程完成LCD1602驱动显示程序的编写,成功点亮屏幕,开启背光,但无法观察到显示数据。

    分析过程与解决方案

    1.是否IIC地址不对

    使用以下代码扫描IIC总线上的设备,发现LCD1602的IIC地址并没有配置错误

    #include 
    #include 
    void setup(){
      Wire.begin();
      Serial.begin(9600);
      Serial.println("\nI2C Scanner");
    }
    void loop(){
      byte error, address;
      int nDevices;
      Serial.println("Scanning...");
      nDevices = 0;
      for (address = 1; address < 127; address++ ){
        // The i2c_scanner uses the return value of
        // the Write.endTransmisstion to see if
        // a device did acknowledge to the address.
        Wire.beginTransmission(address);
        error = Wire.endTransmission();
        if (error == 0){
          Serial.print("I2C device found at address 0x");
          if (address < 16)
            Serial.print("0");
          Serial.print(address, HEX);
          Serial.println(" !");
          nDevices++;
        }else if (error == 4){
          Serial.print("Unknow error at address 0x");
          if (address < 16)
            Serial.print("0");
          Serial.println(address, HEX);
        }
      }
      if (nDevices == 0)
        Serial.println("No I2C devices found\n");
      else
        Serial.println("done\n");
      delay(5000); // wait 5 seconds for next scan
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    2.硬件电路是否连接错误

    检查原理图后,发现IIC模块背部有调光旋钮,使用螺丝刀旋转该旋钮,背光减弱,可以正常观察到显示的数据,代码并没有错误,最后问题成功解决。

    手势识别问题

    问题描述:通过DMP库读取MPU6050的姿态角后,通过上位机观察陀螺仪翻转时的姿态数据,发现当向后翻转时,姿态角数据反向增大后,再逐渐恢复正常值,现象如下图黄线所示:
    陀螺仪数据

    这不利于设置阈值判定手势。

    解决方案:通过与同伴交流,发现应该在陀螺仪初始化时将其正向放置,即遵循电路板上丝印进行静止初始化,即可实现,向后翻转,数据直接增大至稳定值。

    通讯延时问题

    问题描述:使用UDP进行两块ESP32间的通信,但控制延时较大,且发送数据过快时,会出现更大的延时。

    解决方案

    1.通讯方式选择

    ESP32中的UDP通信原理是将自己作为UDP服务器,并通过调用库函数实现数据传输。但UDP处于计算机网络中的传输层(第四层),通信双方每次传输均需要两次数据封装与解封操作。经过仔细阅读任务文档,发现了多ESP32的通讯实例:https://randomnerdtutorials.com/esp-now-many-to-one-esp32/。该方法通过ESP私有协议ESP-NOW完成通信,传输时只需要知晓一方的MAC地址即可完成双向通信,这意味着该协议处于数据链路层,减少了数据封装过程,因此通讯速率有所提升。经测试,从UDP更换为ESP-NOW通信后,通信延时减少了一秒。

    2.数据发送频率

    原始代码中,在遥控端,每隔100ms发送一次控制数据。

    当无线通讯(ESP32间通讯)速率大于串口转发速率时,会导致遥控端发送的控制数据在小车端的ESP32和Arduino间堆积,即数据占满了串口缓存区。由于串口读取数据较慢,会导致实时的控制指令无法被实时接收,由此产生控制延时。于是减少控制数据的发送频率,通过判定上一次控制指令与当前指令是否相同来决定是否发送数据,若相同,则不发送,若不同,则发送数据。

    修改后,控制延时大幅减小,能实现控制延时在1秒内。

    字符串传输与解析

    问题描述:Arduino需要向ESP32传输温度、湿度、距离数据,实现数据上云。

    解决方案:确定通讯协议如下:A[温度数据],[湿度数据],[距离数据]F,如温度23摄氏度,湿度40%,距离50厘米即可传输字符串:A23,40,50F。其中字母A和F是数据标志位。

    最终Arduino的数据发送代码段如下:

      Serial.print('A');
      Serial.print(humidity);
      Serial.print(',');
      Serial.print(temperature);
      Serial.print(',');
      Serial.print(distance);
      Serial.print('F');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    其中humidity,temperature, distance为获取的传感器数据。

    ESP32端先接收数据到receive字符串数组中,然后使用strtok,atoi,atof函数将字符串中的传感器数据转换为float和int型。整体处理代码如下

      //接收数据
      if(Serial2.available()){
        while(Serial2.available())//读完串口中的所有数据
        {
          receive[i++]=Serial2.read();
        }
        /***调试用***/
        Serial.println("I receive this:");
        Serial.println(receive);
        i=0;  //清零,方便下一次读取数据
        Serial.println("I split this:");
        //处理数据
        data_process(receive);
      }
      
      //data_process函数原型如下
      void data_process(char *data){
      int i=0,j=0;
      while(data[i]!='A'){
        i++;
      }
      while(data[j]!='F'){
        j++;
      }
      data[j]='\0';   //字符串的结束标志位,方便后续strtok准确地分离数据
      char *p;
      const char *d = ",";
      //分离字符数据
      p = strtok((data+i+1),d);
      float hum = atof(p);
      p = strtok(NULL,d);
      float tem = atof(p);
      p = strtok(NULL,d);
      int dis = atoi(p);
      Serial.printf("%f,%f,%d\n",hum,tem,dis);
      Number1.print(hum);	//Blinker中BlinkerNumber的对象,用于上传数据至云端
      Number2.print(tem);
      Number3.print(dis);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
  • 相关阅读:
    那些你必须要知道的程序员接单平台
    反向传播详解BP
    按头安利 好看又实用的点胶机 SolidWorks模型素材看这里
    【excel密码】为什么工作表不能移动、复制了?
    docker 构建镜像和容器的流程,以及常用命令
    领域驱动设计DDD:贫血模型和充血模型(比较重要)
    Linux下编写一个C语言程序
    通过QT管理网络状态和网络连接
    探寻容器的本质
    现在软件开发app制作还值得做吗
  • 原文地址:https://blog.csdn.net/qq_30447315/article/details/130856098