【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/begin-esp32-platformio#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 方向可视化
项目代码#include <Adafruit_BNO055.h>
#include <Adafruit_Sensor.h>
#include <ArduinoJson.h>
#include <Husarnet.h>
#include <SparkFunMPU9250-DMP.h>
#include <WebServer.h>
#include <WebSocketsServer.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <Wire.h>
/* =============== config section start =============== */
#if __has_include("credentials.h")
#include "credentials.h"
#else
// WiFi credentials
#define NUM_NETWORKS 2
// Add your networks credentials here
const char *ssidTab = {
"wifi-ssid-one",
"wifi-ssid-two",
};
const char *passwordTab = {
"wifi-pass-one",
"wifi-pass-two",
};
// Husarnet credentials
const char *hostName = "box3desp32";// this will be the name of the 1st ESP32
// device at https://app.husarnet.com
/* to get your join code go to https://app.husarnet.com
-> select network
-> click "Add element"
-> select "join code" tab
Keep it secret!
*/
const char *husarnetJoinCode = "xxxxxxxxxxxxxxxxxxxxxx";
const char *dashboardURL = "default";
#endif
#define IMU_SELECT 1// 1 - BNO055 , 0 - MPU9250
/* =============== config section end =============== */
#if IMU_SELECT == 0
#define INTERRUPT_PIN_MPU 19
// Connected to "Wire" object - 22 (SCL) & 21 (SDA)
MPU9250_DMP mpu;
#else
#define INTERRUPT_PIN_BNO 35
#define RESET_PIN_BNO 34
#define I2C_SDA 33
#define I2C_SCL 32
TwoWire I2CBNO = TwoWire(1);
Adafruit_BNO055 bno = Adafruit_BNO055(55, 0x28, &I2CBNO);
#endif
#define HTTP_PORT 8000
#define WEBSOCKET_PORT 8001
// you can provide credentials to multiple WiFi networks
WiFiMulti wifiMulti;
// HTTP server on port 8000
WebServer server(HTTP_PORT);
// WebSocket server
WebSocketsServer webSocket = WebSocketsServer(WEBSOCKET_PORT);
StaticJsonDocument<200> jsonDocTx;
extern const char index_html_start[] asm("_binary_src_index_html_start");
const String html = String((const char *)index_html_start);
bool wsconnected = false;
void onWebSocketEvent(uint8_t num, WStype_t type, uint8_t *payload,
size_t length) {
switch (type) {
case WStype_DISCONNECTED: {
wsconnected = false;
Serial.printf("[%u] Disconnected\r\n", num);
} break;
case WStype_CONNECTED: {
wsconnected = true;
Serial.printf("\r\n[%u] Connection from Husarnet \r\n", num);
} break;
case WStype_TEXT: {
Serial.printf("[%u] Text:\r\n", num);
for (int i = 0; i < length; i++) {
Serial.printf("%c", (char)(*(payload + i)));
}
Serial.println();
} break;
case WStype_BIN:
case WStype_ERROR:
case WStype_FRAGMENT_TEXT_START:
case WStype_FRAGMENT_BIN_START:
case WStype_FRAGMENT:
case WStype_FRAGMENT_FIN:
default:
break;
}
}
void onHttpReqFunc() {
server.sendHeader("Connection", "close");
server.send(200, "text/html", html);
}
void taskWifi(void *parameter);
void taskStatus(void *parameter);
SemaphoreHandle_t mtx;
const signed char orientationDefault = {0, 1, 0, 0, 0, 1, 1, 0, 0};
void setup() {
Serial.begin(115200);
mtx = xSemaphoreCreateMutex();
xSemaphoreGive(mtx);
xTaskCreatePinnedToCore(taskWifi, /* Task function. */
"taskWifi", /* String with name of task. */
20000, /* Stack size in bytes. */
NULL, /* Parameter passed as input of the task */
2, /* Priority of the task. */
NULL, /* Task handle. */
0); /* Core where the task should run */
xTaskCreatePinnedToCore(taskStatus, /* Task function. */
"taskStatus", /* String with name of task. */
20000, /* Stack size in bytes. */
NULL, /* Parameter passed as input of the task */
3, /* Priority of the task. */
NULL, /* Task handle. */
0); /* Core where the task should run */
}
void taskWifi(void *parameter) {
uint8_t stat = WL_DISCONNECTED;
/* Configure Wi-Fi */
for (int i = 0; i < NUM_NETWORKS; i++) {
wifiMulti.addAP(ssidTab, passwordTab);
Serial.printf("WiFi %d: SSID: \"%s\" ; PASS: \"%s\"\r\n", i, ssidTab,
passwordTab);
}
while (stat != WL_CONNECTED) {
stat = wifiMulti.run();
Serial.printf("WiFi status: %d\r\n", (int)stat);
delay(100);
}
Serial.printf("WiFi connected\r\n", (int)stat);
Serial.printf("IP address: ");
Serial.println(WiFi.localIP());
/* Start Husarnet */
Husarnet.selfHostedSetup(dashboardURL);
Husarnet.join(husarnetJoinCode, hostName);
Husarnet.start();
webSocket.begin();
webSocket.onEvent(onWebSocketEvent);
/* Confgiure HTTP server */
server.on("/", HTTP_GET, onHttpReqFunc);
server.on("/index.html", HTTP_GET, onHttpReqFunc);
server.begin();
while (1) {
while (WiFi.status() == WL_CONNECTED) {
if (xSemaphoreTake(mtx, 5) == pdTRUE) {
webSocket.loop();
server.handleClient();
xSemaphoreGive(mtx);
}
delay(5);
}
Serial.printf("WiFi disconnected, reconnecting\r\n");
delay(500);
stat = wifiMulti.run();
Serial.printf("WiFi status: %d\r\n", (int)stat);
}
}
void taskStatus(void *parameter) {
String output;
unsigned short fifoCnt;
inv_error_t result;
#if IMU_SELECT == 0
pinMode(INTERRUPT_PIN_MPU, INPUT_PULLUP);
if (mpu.begin() != INV_SUCCESS) {
while (1) {
Serial.println("Unable to communicate with MPU-9250");
Serial.println("Check connections, and try again.");
Serial.println();
delay(5000);
}
}
mpu.enableInterrupt();
mpu.setIntLevel(INT_ACTIVE_LOW);
mpu.setIntLatched(INT_LATCHED);
mpu.dmpBegin(DMP_FEATURE_6X_LP_QUAT | // Enable 6-axis quat
DMP_FEATURE_GYRO_CAL,// Use gyro calibration
10); // Set DMP FIFO rate to 10 Hz
mpu.dmpSetOrientation(orientationDefault);
#endif// IMU_SELECT == 0 // MPU9250
#if IMU_SELECT == 1
pinMode(INTERRUPT_PIN_BNO, INPUT_PULLUP);
pinMode(RESET_PIN_BNO, OUTPUT);
digitalWrite(RESET_PIN_BNO, 0);
delay(100);
digitalWrite(RESET_PIN_BNO, 1);
I2CBNO.begin(I2C_SDA, I2C_SCL, 100000);
if (!bno.begin()) {
while (1) {
Serial.print("No BNO055 detected");
delay(1000);
}
}
#endif// IMU_SELECT == 1 // BNO055
while (1) {
#if IMU_SELECT == 0
if (digitalRead(INTERRUPT_PIN_MPU) == LOW) {
fifoCnt = mpu.fifoAvailable();
if (fifoCnt > 0) {
result = mpu.dmpUpdateFifo();
if (result == INV_SUCCESS) {
mpu.computeEulerAngles();
output = "";
float q0 = mpu.calcQuat(mpu.qw);
float q1 = mpu.calcQuat(mpu.qx);
float q2 = mpu.calcQuat(mpu.qy);
float q3 = mpu.calcQuat(mpu.qz);
Serial.printf("Qmpu=[%f,%f,%f,%f]\r\n", q0, q1, q2, q3);
Serial.printf("---------------------\r\n");
// rootTx["roll"] = mpu.roll;
// rootTx["pitch"] = mpu.pitch;
// rootTx["yaw"] = mpu.yaw;
jsonDocTx.clear();
jsonDocTx["q0"] = q0;
jsonDocTx["q1"] = q1;
jsonDocTx["q2"] = q2;
jsonDocTx["q3"] = q3;
serializeJson(jsonDocTx, output);
// Serial.print(F("Sending: "));
// Serial.println(output);
if (wsconnected == true) {
if (xSemaphoreTake(mtx, 5) == pdTRUE) {
webSocket.sendTXT(0, output);
xSemaphoreGive(mtx);
}
}
}
} else {
Serial.println("false interrupt");
delay(20);
}
} else {
delay(20);
}
#endif// IMU_SELECT == 0 // MPU9250
#if IMU_SELECT == 1
if (digitalRead(INTERRUPT_PIN_BNO) == LOW) {
output = "";
imu::Quaternion quat = bno.getQuat();
Serial.printf("Qbno=[%f,%f,%f,%f]\r\n", quat.w(), quat.x(), quat.y(),
quat.z());
jsonDocTx.clear();
jsonDocTx["q0"] = quat.w();
jsonDocTx["q1"] = quat.x();
jsonDocTx["q2"] = quat.y();
jsonDocTx["q3"] = quat.z();
serializeJson(jsonDocTx, output);
// Serial.print(F("Sending: "));
// Serial.println(output);
if (wsconnected == true) {
if (xSemaphoreTake(mtx, 5) == pdTRUE) {
webSocket.sendTXT(0, output);
xSemaphoreGive(mtx);
}
}
delay(100);
} else {
delay(100);
}
#endif// IMU_SELECT == 1 // BNO055
}
}
void loop() {
Serial.printf("loop() running on core %d\r\n", xPortGetCoreID());
while (1) {
Serial.printf("\r\n", esp_get_free_heap_size());
delay(1000);
}
}
【Arduino 动手做】ESP32 + MPU9250:3D 方向可视化
【Arduino 动手做】ESP32 + MPU9250:3D 方向可视化项目链接:https://www.hackster.io/donowak/esp32-mpu9250-3d-orientation-visualisation-467dc1
项目作者:多米尼克
项目视频 :https://www.youtube.com/watch?v=TjDmGXQ9rK8
项目代码:https://github.com/DominikN/ESP32-MPU9250-web-view
页:
[1]