15浏览
查看: 15|回复: 2

[项目] 【Arduino 动手做】ESP32 + MPU9250:3D 方向可视化

[复制链接]
在 ESP32 托管的网页上可视化 MPU9250 3D 方向数据。使用 websockets 和 JSON 发送方向数据。

MPU9250 是市场上最受欢迎的 IMU(惯性测量单元)之一。它不仅结合了 3D 加速度计、3D 陀螺仪和 3D 指南针,还结合了 DMP(数字运动处理器)。借助 DMP,我们可以直接从芯片中读取欧拉角或四元数形式的方向数据。

ESP32 托管带有可视化 MPU9250 方向的 3D 立方体的网页。来自 MPU9250 的实时数据通过 websocket 发送到 Web 浏览器。然后,该数据被Three.js库 (https://threejs.org/) 用于实时可视化立方体的方向。借助 Husarnet,该网页可在 LAN 和 Internet 上使用。

要运行该示例,请执行以下步骤。
将 MPU9250 连接到 ESP32
ESP32 与 MPU9250 的接口如下:

ESP32 <-> MPU9250
P22   <-> SCL
P21   <-> SDA
P19   <-> INT
GND   <-> GND

还要记住为 ESP32 和 MPU9250 提供合适的电源。

使用 PlatformIO
• 克隆磁盘上的项目存储库,然后从安装了 platformio 的 Visual Studio Code 中打开它
• 打开 ESP32-MPU9250-web-view.ino 文件
• 使用您的 Husarnet 加入代码修改第 39 行 (get on https://app.husarnet.com -> [创建网络] -> [添加元素] -> [加入代码])
• 修改第 18 - 27 行以添加您的 Wi-Fi 网络凭证
• 将项目上传到 ESP32 开发板。
如果您在过程中遇到任何问题,请访问此网站:https://docs.husarnet.com/docs/b ... rmio#get-platformio

打开 ESP32 托管的网页
有两个选项:
• 在 https://app.husarnet.com 登录您的帐户,找到 您刚刚连接的设备,然后单击按钮 。您还可以单击 element 打开 “Element settings” 并选择 是否要拥有一个公开可用的地址。在这样的场景中,Husarnet 代理服务器用于为您提供 Web UI。适用于任何 Web 浏览器:桌面和移动设备。box3desp32web UIbox3desp32Make the Web UI public
• P2P 选项 - 将您的笔记本电脑添加到与 ESP32 板相同的 Husarnet 网络。在该场景中,没有使用代理服务器,您可以直接以非常低的延迟连接到 ESP32,而无需在路由器上进行端口转发。目前只有 Linux 客户端可用,因此请打开 Linux 终端并键入:
• $ curl https://install.husarnet.com/install.sh | sudo bash安装 Husarnet。
• $ husarnet join XXXXXXXXXXXXXXXXXXXXXXX mylaptop 替换 XXX...X 替换为您自己的 ,然后单击 Enter。join code
在这个阶段,您的 ESP32 和您的笔记本电脑位于同一个 VLAN 网络中。最好的主机名支持是在 Mozilla Firefox Web 浏览器中(其他浏览器也可以使用,但您必须使用设备的 IPv6 地址,该地址位于 https://app.husarnet.com)并键入: 您现在应该会看到一个 Web UI 来控制您的 ESP32。http://box3desp32:8000
我希望您会喜欢这个项目:)

【Arduino 动手做】ESP32 + MPU9250:3D 方向可视化图1

【Arduino 动手做】ESP32 + MPU9250:3D 方向可视化图3

【Arduino 动手做】ESP32 + MPU9250:3D 方向可视化图2

【Arduino 动手做】ESP32 + MPU9250:3D 方向可视化图5

【Arduino 动手做】ESP32 + MPU9250:3D 方向可视化图4

驴友花雕  中级技神
 楼主|

发表于 4 小时前

【Arduino 动手做】ESP32 + MPU9250:3D 方向可视化

项目代码

  1. #include <Adafruit_BNO055.h>
  2. #include <Adafruit_Sensor.h>
  3. #include <ArduinoJson.h>
  4. #include <Husarnet.h>
  5. #include <SparkFunMPU9250-DMP.h>
  6. #include <WebServer.h>
  7. #include <WebSocketsServer.h>
  8. #include <WiFi.h>
  9. #include <WiFiMulti.h>
  10. #include <Wire.h>
  11. /* =============== config section start =============== */
  12. #if __has_include("credentials.h")
  13. #include "credentials.h"
  14. #else
  15. // WiFi credentials
  16. #define NUM_NETWORKS 2
  17. // Add your networks credentials here
  18. const char *ssidTab[NUM_NETWORKS] = {
  19.     "wifi-ssid-one",
  20.     "wifi-ssid-two",
  21. };
  22. const char *passwordTab[NUM_NETWORKS] = {
  23.     "wifi-pass-one",
  24.     "wifi-pass-two",
  25. };
  26. // Husarnet credentials
  27. const char *hostName = "box3desp32";  // this will be the name of the 1st ESP32
  28.                                       // device at https://app.husarnet.com
  29. /* to get your join code go to https://app.husarnet.com
  30.    -> select network
  31.    -> click "Add element"
  32.    -> select "join code" tab
  33.    Keep it secret!
  34. */
  35. const char *husarnetJoinCode = "xxxxxxxxxxxxxxxxxxxxxx";
  36. const char *dashboardURL = "default";
  37. #endif
  38. #define IMU_SELECT 1  // 1 - BNO055 , 0 - MPU9250
  39. /* =============== config section end =============== */
  40. #if IMU_SELECT == 0
  41. #define INTERRUPT_PIN_MPU 19
  42. // Connected to "Wire" object - 22 (SCL) & 21 (SDA)
  43. MPU9250_DMP mpu;
  44. #else
  45. #define INTERRUPT_PIN_BNO 35
  46. #define RESET_PIN_BNO 34
  47. #define I2C_SDA 33
  48. #define I2C_SCL 32
  49. TwoWire I2CBNO = TwoWire(1);
  50. Adafruit_BNO055 bno = Adafruit_BNO055(55, 0x28, &I2CBNO);
  51. #endif
  52. #define HTTP_PORT 8000
  53. #define WEBSOCKET_PORT 8001
  54. // you can provide credentials to multiple WiFi networks
  55. WiFiMulti wifiMulti;
  56. // HTTP server on port 8000
  57. WebServer server(HTTP_PORT);
  58. // WebSocket server
  59. WebSocketsServer webSocket = WebSocketsServer(WEBSOCKET_PORT);
  60. StaticJsonDocument<200> jsonDocTx;
  61. extern const char index_html_start[] asm("_binary_src_index_html_start");
  62. const String html = String((const char *)index_html_start);
  63. bool wsconnected = false;
  64. void onWebSocketEvent(uint8_t num, WStype_t type, uint8_t *payload,
  65.                       size_t length) {
  66.   switch (type) {
  67.     case WStype_DISCONNECTED: {
  68.       wsconnected = false;
  69.       Serial.printf("[%u] Disconnected\r\n", num);
  70.     } break;
  71.     case WStype_CONNECTED: {
  72.       wsconnected = true;
  73.       Serial.printf("\r\n[%u] Connection from Husarnet \r\n", num);
  74.     } break;
  75.     case WStype_TEXT: {
  76.       Serial.printf("[%u] Text:\r\n", num);
  77.       for (int i = 0; i < length; i++) {
  78.         Serial.printf("%c", (char)(*(payload + i)));
  79.       }
  80.       Serial.println();
  81.     } break;
  82.     case WStype_BIN:
  83.     case WStype_ERROR:
  84.     case WStype_FRAGMENT_TEXT_START:
  85.     case WStype_FRAGMENT_BIN_START:
  86.     case WStype_FRAGMENT:
  87.     case WStype_FRAGMENT_FIN:
  88.     default:
  89.       break;
  90.   }
  91. }
  92. void onHttpReqFunc() {
  93.   server.sendHeader("Connection", "close");
  94.   server.send(200, "text/html", html);
  95. }
  96. void taskWifi(void *parameter);
  97. void taskStatus(void *parameter);
  98. SemaphoreHandle_t mtx;
  99. const signed char orientationDefault[9] = {0, 1, 0, 0, 0, 1, 1, 0, 0};
  100. void setup() {
  101.   Serial.begin(115200);
  102.   mtx = xSemaphoreCreateMutex();
  103.   xSemaphoreGive(mtx);
  104.   xTaskCreatePinnedToCore(taskWifi,   /* Task function. */
  105.                           "taskWifi", /* String with name of task. */
  106.                           20000,      /* Stack size in bytes. */
  107.                           NULL, /* Parameter passed as input of the task */
  108.                           2,    /* Priority of the task. */
  109.                           NULL, /* Task handle. */
  110.                           0);   /* Core where the task should run */
  111.   xTaskCreatePinnedToCore(taskStatus,   /* Task function. */
  112.                           "taskStatus", /* String with name of task. */
  113.                           20000,        /* Stack size in bytes. */
  114.                           NULL, /* Parameter passed as input of the task */
  115.                           3,    /* Priority of the task. */
  116.                           NULL, /* Task handle. */
  117.                           0);   /* Core where the task should run */
  118. }
  119. void taskWifi(void *parameter) {
  120.   uint8_t stat = WL_DISCONNECTED;
  121.   /* Configure Wi-Fi */
  122.   for (int i = 0; i < NUM_NETWORKS; i++) {
  123.     wifiMulti.addAP(ssidTab[i], passwordTab[i]);
  124.     Serial.printf("WiFi %d: SSID: "%s" ; PASS: "%s"\r\n", i, ssidTab[i],
  125.                   passwordTab[i]);
  126.   }
  127.   while (stat != WL_CONNECTED) {
  128.     stat = wifiMulti.run();
  129.     Serial.printf("WiFi status: %d\r\n", (int)stat);
  130.     delay(100);
  131.   }
  132.   Serial.printf("WiFi connected\r\n", (int)stat);
  133.   Serial.printf("IP address: ");
  134.   Serial.println(WiFi.localIP());
  135.   /* Start Husarnet */
  136.   Husarnet.selfHostedSetup(dashboardURL);
  137.   Husarnet.join(husarnetJoinCode, hostName);
  138.   Husarnet.start();
  139.   webSocket.begin();
  140.   webSocket.onEvent(onWebSocketEvent);
  141.   /* Confgiure HTTP server */
  142.   server.on("/", HTTP_GET, onHttpReqFunc);
  143.   server.on("/index.html", HTTP_GET, onHttpReqFunc);
  144.   server.begin();
  145.   while (1) {
  146.     while (WiFi.status() == WL_CONNECTED) {
  147.       if (xSemaphoreTake(mtx, 5) == pdTRUE) {
  148.         webSocket.loop();
  149.         server.handleClient();
  150.         xSemaphoreGive(mtx);
  151.       }
  152.       delay(5);
  153.     }
  154.     Serial.printf("WiFi disconnected, reconnecting\r\n");
  155.     delay(500);
  156.     stat = wifiMulti.run();
  157.     Serial.printf("WiFi status: %d\r\n", (int)stat);
  158.   }
  159. }
  160. void taskStatus(void *parameter) {
  161.   String output;
  162.   unsigned short fifoCnt;
  163.   inv_error_t result;
  164. #if IMU_SELECT == 0
  165.   pinMode(INTERRUPT_PIN_MPU, INPUT_PULLUP);
  166.   if (mpu.begin() != INV_SUCCESS) {
  167.     while (1) {
  168.       Serial.println("Unable to communicate with MPU-9250");
  169.       Serial.println("Check connections, and try again.");
  170.       Serial.println();
  171.       delay(5000);
  172.     }
  173.   }
  174.   mpu.enableInterrupt();
  175.   mpu.setIntLevel(INT_ACTIVE_LOW);
  176.   mpu.setIntLatched(INT_LATCHED);
  177.   mpu.dmpBegin(DMP_FEATURE_6X_LP_QUAT |   // Enable 6-axis quat
  178.                    DMP_FEATURE_GYRO_CAL,  // Use gyro calibration
  179.                10);                       // Set DMP FIFO rate to 10 Hz
  180.   mpu.dmpSetOrientation(orientationDefault);
  181. #endif  // IMU_SELECT == 0 // MPU9250
  182. #if IMU_SELECT == 1
  183.   pinMode(INTERRUPT_PIN_BNO, INPUT_PULLUP);
  184.   pinMode(RESET_PIN_BNO, OUTPUT);
  185.   digitalWrite(RESET_PIN_BNO, 0);
  186.   delay(100);
  187.   digitalWrite(RESET_PIN_BNO, 1);
  188.   I2CBNO.begin(I2C_SDA, I2C_SCL, 100000);
  189.   if (!bno.begin()) {
  190.     while (1) {
  191.       Serial.print("No BNO055 detected");
  192.       delay(1000);
  193.     }
  194.   }
  195. #endif  // IMU_SELECT == 1 // BNO055
  196.   while (1) {
  197. #if IMU_SELECT == 0
  198.     if (digitalRead(INTERRUPT_PIN_MPU) == LOW) {
  199.       fifoCnt = mpu.fifoAvailable();
  200.       if (fifoCnt > 0) {
  201.         result = mpu.dmpUpdateFifo();
  202.         if (result == INV_SUCCESS) {
  203.           mpu.computeEulerAngles();
  204.           output = "";
  205.           float q0 = mpu.calcQuat(mpu.qw);
  206.           float q1 = mpu.calcQuat(mpu.qx);
  207.           float q2 = mpu.calcQuat(mpu.qy);
  208.           float q3 = mpu.calcQuat(mpu.qz);
  209.           Serial.printf("Qmpu=[%f,%f,%f,%f]\r\n", q0, q1, q2, q3);
  210.           Serial.printf("---------------------\r\n");
  211.           // rootTx["roll"] = mpu.roll;
  212.           // rootTx["pitch"] = mpu.pitch;
  213.           // rootTx["yaw"] = mpu.yaw;
  214.           jsonDocTx.clear();
  215.           jsonDocTx["q0"] = q0;
  216.           jsonDocTx["q1"] = q1;
  217.           jsonDocTx["q2"] = q2;
  218.           jsonDocTx["q3"] = q3;
  219.           serializeJson(jsonDocTx, output);
  220.           //          Serial.print(F("Sending: "));
  221.           //          Serial.println(output);
  222.           if (wsconnected == true) {
  223.             if (xSemaphoreTake(mtx, 5) == pdTRUE) {
  224.               webSocket.sendTXT(0, output);
  225.               xSemaphoreGive(mtx);
  226.             }
  227.           }
  228.         }
  229.       } else {
  230.         Serial.println("false interrupt");
  231.         delay(20);
  232.       }
  233.     } else {
  234.       delay(20);
  235.     }
  236. #endif  // IMU_SELECT == 0 // MPU9250
  237. #if IMU_SELECT == 1
  238.     if (digitalRead(INTERRUPT_PIN_BNO) == LOW) {
  239.       output = "";
  240.       imu::Quaternion quat = bno.getQuat();
  241.       Serial.printf("Qbno=[%f,%f,%f,%f]\r\n", quat.w(), quat.x(), quat.y(),
  242.                     quat.z());
  243.       jsonDocTx.clear();
  244.       jsonDocTx["q0"] = quat.w();
  245.       jsonDocTx["q1"] = quat.x();
  246.       jsonDocTx["q2"] = quat.y();
  247.       jsonDocTx["q3"] = quat.z();
  248.       serializeJson(jsonDocTx, output);
  249.       // Serial.print(F("Sending: "));
  250.       // Serial.println(output);
  251.       if (wsconnected == true) {
  252.         if (xSemaphoreTake(mtx, 5) == pdTRUE) {
  253.           webSocket.sendTXT(0, output);
  254.           xSemaphoreGive(mtx);
  255.         }
  256.       }
  257.       delay(100);
  258.     } else {
  259.       delay(100);
  260.     }
  261. #endif  // IMU_SELECT == 1 // BNO055
  262.   }
  263. }
  264. void loop() {
  265.   Serial.printf("loop() running on core %d\r\n", xPortGetCoreID());
  266.   while (1) {
  267.     Serial.printf("[RAM: %d]\r\n", esp_get_free_heap_size());
  268.     delay(1000);
  269.   }
  270. }
复制代码


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 4 小时前

【Arduino 动手做】ESP32 + MPU9250:3D 方向可视化

【Arduino 动手做】ESP32 + MPU9250:3D 方向可视化
项目链接:https://www.hackster.io/donowak/ ... isualisation-467dc1
项目作者:多米尼克

项目视频 :https://www.youtube.com/watch?v=TjDmGXQ9rK8
项目代码:https://github.com/DominikN/ESP32-MPU9250-web-view

【Arduino 动手做】ESP32 + MPU9250:3D 方向可视化图1

回复

使用道具 举报

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

本版积分规则

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

硬件清单

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

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

mail