搜索代码

ESP32-S3 RGB LED矩阵项目4 - 倾斜点

ESP32-S3 RGB LED矩阵项目4 - 倾斜点

项目4 - 倾斜点(通过倾斜ESP32-S3 RGB LED矩阵移动点)

项目 4 引入了内置于 ESP32-S3 RGB LED 矩阵模块中的运动传感器。与自动移动点(如项目 1)或滚动文字(项目 2 和 3)不同,该项目允许您通过倾斜电路板来控制点的位置。点根据模块背面的 QMI8658C 加速度计的实时读取,平稳移动于 8×8 RGB 显示屏上。

该系列中的所有六个项目都在一个YouTube视频中演示。视频嵌入在此页面上,因此您可以看到当板子倾斜时,点如何实时移动。该项目的完整代码会自动加载在文章下方,模块的联属购买链接出现在代码部分下方。

ESP32-S3 RGB LED矩阵模块概述

该项目使用ESP32-S3 RGB LED矩阵模块,包括:

  • ESP32-S3 微控制器带有Wi-Fi和蓝牙
  • 8×8 RGB LED 矩阵(64个可单独控制的LED灯)
  • QMI8658C 加速度计用于倾斜和运动检测的背面
  • USB接口用于编程和电力
  • 启动 / 重置按钮
  • 可用的 GPIO 引脚用于未来扩展

QMI8658C传感器读取X,Y,和Z加速度和方向值,允许点根据板子的倾斜程度向上/下/左/右移动。:contentReference[oaicite:0]{index=0}

视频中涵盖的项目(时间戳)

  • 00:00- 介绍
  • 02:01- 安装ESP32板
  • 03:32- 安装库
  • 05:32- 项目 1:移动点
  • 11:11- 项目 2:文本滚动
  • 12:59- 项目 3:HTTP 文本
  • 16:41-项目 4:倾斜点 (此项目)
  • 18:55- 项目 5:向上箭头
  • 20:02- 项目6:目标游戏

强烈推荐观看视频中的倾斜演示,因为您可以看到点如何平滑地响应板的方向。:contentReference[oaicite:1]{index=1}

在Arduino IDE中安装ESP32开发板

如果您已经完成了任何早期项目,板载支持已安装。否则,请按照以下步骤进行操作:

  1. 打开File > Preferences→ 添加ESP32开发板的URL。
  2. Tools > Board > Boards Manager…并安装ESP32.
  3. 在下方选择您的ESP32-S3开发板Tools > Board.
  4. 在下面选择正确的COM端口Tools > Port.

安装所需库

该项目需要以下库:

  • Adafruit NeoMatrix
  • Adafruit NeoPixel
  • Adafruit GFX Library
  • QMI8658(运动传感器)

在库管理器中安装它们:

  1. 打开Sketch > Include Library > Manage Libraries….
  2. 搜索Adafruit NeoMatrix→ 安装。
  3. 允许自动安装Adafruit GFXAdafruit 彩灯.
  4. 搜索QMI8658由其列出的作者 → 安装.:contentReference[oaicite:2]{index=2}

项目4的工作原理

QMI8658C传感器持续提供沿X、Y和Z轴的加速度数据。在这个项目中,我们仅使用X和Y轴来决定:

  • 点在左右(X轴)移动多远
  • 将点向上或向下移动多少 (Y 轴)

传感器值被映射到从 0 到 7 的坐标范围(适用于 8×8 LED 矩阵)。点的位置每秒更新多次,随着模块的倾斜,产生平滑的滑动效果。:contentReference[oaicite:3]{index=3}

项目 4 - 代码设置(倾斜点)

以下是项目代码顶部附近的用户可编辑设置。完整的草图会在文章下方自动显示。

矩阵销和尺寸


// 8×8 RGB matrix configuration
const int MATRIX_PIN    = 14;   // fixed pin for this board
const int MATRIX_WIDTH  = 8;
const int MATRIX_HEIGHT = 8;

离开MATRIX_PIN14它与机载矩阵直接连接。

亮度


// Overall brightness (0–255)
uint8_t matrixBrightness = 40;

如有必要,可以增加亮度,但在近距离观看时避免极端的亮度。

点颜色


// Dot color (R, G, B)
uint8_t dotRed   = 0;
uint8_t dotGreen = 200;   // light green (default)
uint8_t dotBlue  = 0;

更改这些值以创建任意颜色。例如:

  • 红色:(255, 0, 0)
  • 黄色:(255, 255, 0)
  • 白色(255, 255, 255)

运动敏感度

为了防止极端的跳变,加速度计的值通常会被限制或缩放。典型的设置如下:


// How aggressively tilt affects movement
float sensitivity = 4.0f;   // larger = faster movement across screen

如果点移动得太慢 → 增加值。如果点移动得太突然 → 减少值。

更新速度(刷新率)

您可以在更新之间添加小的延迟,以平滑运动:


// Delay between position updates (ms)
int refreshDelayMs = 20;   // lower = smoother and faster response

10-30毫秒之间的数值感觉非常灵敏。

摘要

项目4通过让您用物理动作控制LED矩阵,赋予ESP32-S3内置的QMI8658C加速度计生命。电路板的小幅倾斜使点在相同方向移动,使这个项目成为更高级的“箭头向上”和“靶子游戏”项目的完美跳板。

本文下方自动加载了完整的Tilt Dot草图。为了更好地理解,请观看视频中的倾斜演示,您可以看到点在旋转板子时移动得多么顺畅。在代码部分下方包含了购买ESP32-S3 RGB LED矩阵模块的链接。

图像

ESP32 S3 Matrix
ESP32 S3 Matrix
ESP32 S3 Matrix  pin out
ESP32 S3 Matrix pin out
ESP32-S3_RGB_8x8_matrix-3
ESP32-S3_RGB_8x8_matrix-3
ESP32 S3 Matrix displaying rainbow heart
ESP32 S3 Matrix displaying rainbow heart
ESP32-S3_RGB_8x8_matrix1
ESP32-S3_RGB_8x8_matrix1
ESP32-S3_RGB_8x8_matrix-2
ESP32-S3_RGB_8x8_matrix-2
802-ESP32-S3 RGB LED Matrix Project 4 - Tilt dot
语言: C++
/*
 * 项目 4:Tilt Dot - ESP32-S3 RGB LED 矩阵(Waveshare)
 * 
 * 该示例从 QMI8658C IMU 读取倾斜数据,并根据板子方向平滑移动 8×8 RGB LED 矩阵上的点。
 * 
 * ▶️ 视频教程:
 * https://youtu.be/JKLuYrRcLMI
 * 
 * 📚⬇️ 资源与代码页面:
 * https://robojax.com/RJT829
 * 
 * QMI8658_RGB_2
 */
#include <Arduino.h>
#include <math.h>

#include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h>
#include <Adafruit_NeoPixel.h>

#include <QMI8658.h> // 拉哈夫·加哈利

 // -------- LED 矩阵设置 --------
#define MATRIX_PIN    14
#define MATRIX_WIDTH  8
#define MATRIX_HEIGHT 8

Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(
  MATRIX_WIDTH, MATRIX_HEIGHT, MATRIX_PIN,
  NEO_MATRIX_TOP + NEO_MATRIX_LEFT +
  NEO_MATRIX_ROWS + NEO_MATRIX_PROGRESSIVE,
  NEO_RGB + NEO_KHZ800
);

 // -------- QMI8658 IMU 设置 --------
QMI8658 imu;
QMI8658_Data imuData;

 // -------- 用户设置 --------

 // 真正 -> 对面上的点: USB↔OUSB, 34↔15
 // 假 -> 点与上方在同一侧
bool useOppositeMapping = false;

 // 点颜色(每个 0-255)
uint8_t dotRed   = 0;
uint8_t dotGreen = 100;
uint8_t dotBlue  = 0;

 // 侧板
enum Side {
  SIDE_CENTER = 0,
  SIDE_USB,
  SIDE_OUSB,
  SIDE_15,
  SIDE_34
};

 // 平滑点位置(以像素坐标表示,但保持为浮点数以便于缓动)
float dotPosX = 3.0f; // 从中心开始
float dotPosY = 3.0f;

 // 平滑因子:更小=更慢的移动(0.1 非常慢,0.5 较快)
const float dotSmooth = 0.25f;


bool isFlat = false;

const char* sideName(Side s) {
  switch (s) {
    case SIDE_CENTER: return "CENTER";
    case SIDE_USB:    return "USB";
    case SIDE_OUSB:   return "OUSB";
    case SIDE_15:     return "15";
    case SIDE_34:     return "34";
    default:          return "?";
  }
}

 // 使用校准轴检测哪个面是上面:
 // +X = USB,-X = OUSB,+Y = 34,-Y = 15
Side detectSideUp(float ax_g, float ay_g, float az_g) {
 // 平面检测
  const float flatThreshXY = 0.15f;
  const float flatThreshZ  = 0.15f;

  if (fabs(ax_g) < flatThreshXY &&
      fabs(ay_g) < flatThreshXY &&
      fabs(az_g - 1.0f) < flatThreshZ) {
    isFlat = true;
    return SIDE_CENTER;
  }
  isFlat = false;

 // 说“这个轴真的倾斜”的阈值
  const float tiltThreshY = 0.5f;
  const float tiltThreshX = 0.5f;

 // 如果明显倾斜,优先选择 15 / 34 的 Y 轴。
  if (fabs(ay_g) >= tiltThreshY) {
    if (ay_g > 0) {
      return SIDE_15; // +Y = 34 向上
    } else {
      return SIDE_34; // -Y = 15 向上
    }
  }

 // 2) 否则,检查 X 轴上的 USB / OUSB
  if (fabs(ax_g) >= tiltThreshX) {
    if (ax_g > 0) {
      return SIDE_USB; // +X = USB 向上
    } else {
      return SIDE_OUSB; // -X = OUSB 向上
    }
  }

 // 3) 如果没有明显倾斜,就称之为中心。
  return SIDE_CENTER;
}

 // 从UP侧到点应该去的地方的地图
Side dotSideFromUpSide(Side upSide) {
  switch (upSide) {
    case SIDE_USB:
      return useOppositeMapping ? SIDE_OUSB : SIDE_USB;

    case SIDE_OUSB:
      return useOppositeMapping ? SIDE_USB : SIDE_OUSB;

    case SIDE_34:
      return useOppositeMapping ? SIDE_15 : SIDE_34;

    case SIDE_15:
      return useOppositeMapping ? SIDE_34 : SIDE_15;

    case SIDE_CENTER:
    default:
      return SIDE_CENTER;
  }
}

 // 将点侧转换为矩阵坐标
void getDotPixel(Side dotSide, int &px, int &py) {
 // 矩阵 (0,0) = 左上角
 // 顶部中心: (3,0) → USB
 // 底部中心: (3,7) → OUSB
 // 左中心: (0,3) → 15
 // 右中: (7,3) → 34
 // 中心: (3,3)

  switch (dotSide) {
    case SIDE_USB:   px = 3; py = 0; break;
    case SIDE_OUSB:  px = 3; py = 7; break;
    case SIDE_15:    px = 0; py = 3; break;
    case SIDE_34:    px = 7; py = 3; break;
    case SIDE_CENTER:
    default:         px = 3; py = 3; break;
  }
}

void setup() {
  Serial.begin(115200);
  delay(500);

  matrix.begin();
  matrix.setBrightness(20);
  matrix.fillScreen(0);
  matrix.show();

 // IMU:SDA=11,SCL=12 适用于 ESP32-S3-Matrix
  if (!imu.begin(11, 12)) {
    Serial.println("Failed to initialize QMI8658!");
    while (1) { delay(1000); }
  }

  imu.setAccelUnit_mg(true);
  imu.setGyroUnit_dps(true);
  imu.setDisplayPrecision(4);

  Serial.print("QMI8658 initialized. useOppositeMapping = ");
  Serial.println(useOppositeMapping ? "TRUE" : "FALSE");
}

void loop() {
  if (!imu.readSensorData(imuData)) {
    return;
  }

  float ax_g = imuData.accelX / 1000.0f;
  float ay_g = imuData.accelY / 1000.0f;
  float az_g = imuData.accelZ / 1000.0f;

  Side upSide  = detectSideUp(ax_g, ay_g, az_g);
  Side dotSide = dotSideFromUpSide(upSide);

  int targetX, targetY;
  getDotPixel(dotSide, targetX, targetY);

 // --- 向目标的平滑移动 ---
  dotPosX += (targetX - dotPosX) * dotSmooth;
  dotPosY += (targetY - dotPosY) * dotSmooth;

 // 转换为整数像素坐标
  int px = (int)round(dotPosX);
  int py = (int)round(dotPosY);

 // 以防万一夹紧
  if (px < 0) px = 0;
  if (px > 7) px = 7;
  if (py < 0) py = 0;
  if (py > 7) py = 7;

 // --- 绘制点 ---
  matrix.fillScreen(0);
  uint16_t color = matrix.Color(dotRed, dotGreen, dotBlue);
  matrix.drawPixel(px, py, color);
  matrix.show();

 // 调试
  Serial.print("AX="); Serial.print(ax_g, 3);
  Serial.print(" AY="); Serial.print(ay_g, 3);
  Serial.print(" AZ="); Serial.print(az_g, 3);
  Serial.print(" | UP=");  Serial.print(sideName(upSide));
  Serial.print(" | DOT="); Serial.print(sideName(dotSide));
  Serial.print(" | px=");  Serial.print(px);
  Serial.print(" py=");    Serial.println(py);

  delay(80);
}




|||您可能需要的东西

资源与参考

文件📁

Fritzing 文件