HonestQiao 发表于 2024-11-22 17:23

【Follow me第二季第4期】任务二:IMU知识+IMU数据读取+IMU控制立方体

<p>在&nbsp;Arduino&reg; Nano RP2040 Connect 上,板载了一颗IMU传感器,集速度计、陀螺仪于一体,可以用于运动状态的获取和分析。</p>

<p>这篇分享,就来一起研究研究这个IMU传感器的使用。</p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p><span style="font-size:18px;"><strong>一、认识板载IMU传感器</strong></span></p>

<p>通过&nbsp;Arduino&reg; Nano RP2040 Connect 的官方资料,可以了解到板载的IMU传感器为LSM6DSOXTR:</p>

<p>&nbsp;其具体位置,如下图所示:</p>

<p> &nbsp;&nbsp;</p>

<p>&nbsp;</p>

<p>LSM6DSOXTR 是ST 生产的,从ST官方资料可以了解其功能:</p>

<p> &nbsp;</p>

<p>IMU传感器通过检测加速度和角速度,从而感知在三维空间中的运动:【参考:<a href="https://towardsdatascience.com/what-is-imu-9565e55b44c">IMU是什么? IMU(惯性测量单元)是一个&hellip;&hellip; |作者:Barak Or 博士 |走向数据科学</a>】</p>

<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*jrCMzg-wXGSdwbXmLrAGrQ.jpeg" /></p>

<p>&nbsp;</p>

<p><span style="font-size:18px;"><strong>二、从IMU传感器读取数据</strong></span></p>

<p>在Arduino&reg; Nano RP2040 Connect适配的micropython环境中,已经默认提供了该传感器的驱动程序,可以很方便的调用。</p>

<p>从Pinout可以了解,其使用IIC连接:</p>

<p></p>

<p>&nbsp;</p>

<p>要从其读取数据,使用下面的代码即可:</p>

<pre>
<code class="language-python">import time
from machine import Pin, I2C
from lsm6dsox import LSM6DSOX

i2c = I2C(0, scl=Pin(13), sda=Pin(12))
lsm = LSM6DSOX(i2c)

while True:
    accx, accy, accz = lsm.accel()
    print(f"accel: x:{accx:.2f}m/s2, y:{accy:.2f}m/s2, z{accz:.2f}m/s2")
    gyrox, gyroy, gyroz = lsm.gyro()
    print(f"gyro: x:{gyrox:.2f}°/s, y:{gyroy:.2f}°/s, z{gyroz:.2f}°/s")
    print("")
    time.sleep(0.5)
</code></pre>

<p>上面的代码逻辑如下:</p>

<ol>
        <li>引入需要的模块:LSM6DSOX</li>
        <li>实例化IIC接口</li>
        <li>实例化传感器对象LSM6DSOX</li>
        <li>在循环中读取加速度值和角速度值并输出</li>
</ol>

<p>运行后,输出结果如下:</p>

<p> &nbsp;</p>

<p>&nbsp;</p>

<p>此时如果拿起来板子,就会看到上数值快速发生了变化。</p>

<p>可以尝试不同的运动方式,观察数值变化的规律。</p>

<p>参考下面的图,沿不同轴向运动,则能够观察出更好的规律:</p>

<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*jrCMzg-wXGSdwbXmLrAGrQ.jpeg" /></p>

<p>&nbsp;</p>

<p><span style="font-size:18px;"><strong>三、使用IMU数据控制立方体</strong></span></p>

<p>1.&nbsp;Arduino&reg; Nano RP2040 Connect 运行程序:</p>

<p>光看从IMU读取输出的数据,有点乏味,可以通过电脑结合,读取IMU的数据,在程序中控制一个立方体的呈现。</p>

<p>为了让电脑程序更好的获取IMU数据,开发板运行的程序,稍微修改一下:</p>

<pre>
<code class="language-python">import time
from machine import Pin, I2C
from lsm6dsox import LSM6DSOX

i2c = I2C(0, scl=Pin(13), sda=Pin(12))
lsm = LSM6DSOX(i2c)

while True:
    accx, accy, accz = lsm.accel()
    print(f"accel: x:{accx:.2f}m/s2, y:{accy:.2f}m/s2, z{accz:.2f}m/s2", end="")
    gyrox, gyroy, gyroz = lsm.gyro()
    print(f"\tgyro: x:{gyrox:.2f}°/s, y:{gyroy:.2f}°/s, z{gyroz:.2f}°/s")
    #print("")
    time.sleep(0.1)</code></pre>

<p>&nbsp;</p>

<p>把数据在一行输出,方便电脑上面读取和解析,实际输出的数据如下:</p>

<pre>
<code>accel: x:-0.16m/s2, y:-0.40m/s2, z0.91m/s2    gyro: x:0.06°/s, y:0.31°/s, z0.12°/s</code></pre>

<p>&nbsp;</p>

<p>电脑上要读取&nbsp;Arduino&reg; Nano RP2040 Connect 输出的数据,可以直接使用 USB 串口,这样就不能和micropython 编辑器同时使用。</p>

<p>把上面的程序,保存到&nbsp;Arduino&reg; Nano RP2040 Connect 上的main.py,然后断开IDE的设备串口连接,并重新插拔开发板,即可开机自动运行。</p>

<p>此时,用串口工具查看&nbsp;Arduino&reg; Nano RP2040 Connect 的输出:</p>

<p> &nbsp;</p>

<p>这样开发板的工作,就准备好了。</p>

<p>确保正常输出后,要关闭串口工具,这样子后面的程序才能使用串口和读取数据,否则会冲突。</p>

<p>&nbsp;</p>

<p>2. 电脑程序编写</p>

<p>在电脑上,使用Python,可以很快编写一个从串口读取数据,解析数据,然后控制立方体的程序。</p>

<p>&nbsp;</p>

<p>在电脑上使用Python来呈现3D物体和控制,需要用到:matplotlib、mpl_toolkits、numpy库,从串口读取数据还需要pyserial,可以使用下面的命令安装:</p>

<pre>
<code class="language-bash">pip install numpy
pip install matplotlib
pip install mpl_toolkits
pip install pyserial</code></pre>

<p>然后编写对应的程序:</p>

<pre>
<code class="language-python">import serial
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import re
import time

# 串口配置
port = '/dev/cu.usbmodem14201'# 根据实际情况修改串口号
baud_rate = 115200

# 初始化串口
ser = serial.Serial(port, baud_rate, timeout=1)

# 初始化3D图形
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

# 固定位置
x, y, z = 0, 0, 0
roll, pitch, yaw = 0, 0, 0

# 更新3D物体的位置和姿态
def update_3d_object(ax, x, y, z, roll, pitch, yaw):
    ax.clear()
    ax.set_xlim([-10, 10])
    ax.set_ylim([-10, 10])
    ax.set_zlim([-10, 10])

    # 绘制3D物体(这里用一个更大的立方体表示)
    size = 2# 立方体的边长
    cube = np.array([
      ,
      ,
      ,
      ,
      ,
      ,
      ,
      
    ])

    # 应用旋转矩阵
    R = rotation_matrix(roll, pitch, yaw)
    cube_rotated = np.dot(cube, R.T)

    # 绘制立方体
    colors = ['r', 'g', 'b', 'c', 'm', 'y']# 不同的颜色
    for i in range(4):
      ax.plot(, cube_rotated[(i+1) % 4, 0]],
                , cube_rotated[(i+1) % 4, 1]],
                , cube_rotated[(i+1) % 4, 2]], colors)
      ax.plot(, cube_rotated[(i+1) % 4 + 4, 0]],
                , cube_rotated[(i+1) % 4 + 4, 1]],
                , cube_rotated[(i+1) % 4 + 4, 2]], colors)
      ax.plot(, cube_rotated],
                , cube_rotated],
                , cube_rotated], colors)

    plt.draw()
    plt.pause(0.001)

# 旋转矩阵
def rotation_matrix(roll, pitch, yaw):
    Rx = np.array([,
                   ,
                   ])
    Ry = np.array([,
                   ,
                   [-np.sin(pitch), 0, np.cos(pitch)]])
    Rz = np.array([,
                   ,
                   ])
    return np.dot(Rz, np.dot(Ry, Rx))

# 读取并解析串口数据
def read_imu_data():
    global roll, pitch, yaw
    if ser.in_waiting &gt; 0:
      data = ser.readline().decode('utf-8').strip()
      match = re.match(r'accel: x:(.*?)m/s2, y:(.*?)m/s2, z(.*?)m/s2\t?gyro: x:(.*?)°/s, y:(.*?)°/s, z(.*?)°/s', data)
      if match:
            accel_x, accel_y, accel_z, gyro_x, gyro_y, gyro_z = map(float, match.groups())
            # 仅根据角速度更新姿态
            dt = 0.1# 假设采样间隔为0.1秒
            roll += gyro_x * dt
            pitch += gyro_y * dt
            yaw += gyro_z * dt
            print(data)
            print("")

# 主循环
while True:
    read_imu_data()
    update_3d_object(ax, x, y, z, roll, pitch, yaw)
    time.sleep(0.01)</code></pre>

<p>&nbsp;</p>

<p>上面程序的具体逻辑,就不详细说明了,感兴趣的可以研究一下。</p>

<p>重点在最后的主循环中的处理,先读取IMU的数据,就是前面输出的一行数据,然后使用读取到的数据,更新3D立方体的显示,然后延时继续。</p>

<p>&nbsp;</p>

<p>运行上面的程序,具体效果如下:</p>

<p> &nbsp;</p>

<p>视频如下:</p>

<p>a69f37f82c5e9bf95b8d35c264a74eb1</p>

<p>参考前面的测试,沿着不同的轴向运动,看到的效果会更好。</p>

<p>&nbsp;</p>

<p><span style="font-size:18px;"><strong>四、小结</strong></span></p>

<p>上面只是演示了在&nbsp;Arduino&reg; Nano RP2040 Connect 上,LSM6DSOXTR IMU传感器的简单使用。</p>

<p>更进一步的,还可以通过该IMU传感器,来进行振动的检测、手势的识别、计步、倾斜度检测、自由落体、唤醒、单击和双击等等,其用途是非常广泛的。</p>

wangerxian 发表于 2024-11-22 17:51

<p>6啊,如果把立方体换成一个物体,这样更有感觉。</p>

HonestQiao 发表于 2024-11-22 19:14

本帖最后由 HonestQiao 于 2024-11-22 19:44 编辑

<div class="quote">
<blockquote><font size="2"><a href="forum.php?mod=redirect&amp;goto=findpost&amp;pid=3376414&amp;ptid=1299917" target="_blank"><font color="#999999">wangerxian 发表于 2024-11-22 17:51</font></a></font> 6啊,如果把立方体换成一个物体,这样更有感觉。</blockquote>
</div>

<p>例如换成一架飞机,直接可以玩模拟飞行了<img height="52" src="https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/pleased.gif" width="48" /></p>

秦天qintian0303 发表于 2024-11-22 21:00

<p>再来一个就完成了,前三个传感器学习还是挺不错得&nbsp;</p>

HonestQiao 发表于 2024-11-23 10:41

秦天qintian0303 发表于 2024-11-22 21:00
再来一个就完成了,前三个传感器学习还是挺不错得&nbsp;

<p>是的是的,这几个传感器,多个环境都能很方便的调用。</p>

wangerxian 发表于 2024-11-25 09:07

HonestQiao 发表于 2024-11-22 19:14
例如换成一架飞机,直接可以玩模拟飞行了

<p>是的,那样就很炫酷。</p>

hellokitty_bean 发表于 2024-11-25 19:38

HonestQiao 发表于 2024-11-22 19:14
例如换成一架飞机,直接可以玩模拟飞行了

<p>Microsoft貌似有一个模拟飞行的游戏,配合手柄玩。。。。。。。<img height="48" src="https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/smile.gif" width="48" /></p>

hellokitty_bean 发表于 2024-11-25 19:38

<p>貌似马航的那个失事飞机飞行员,玩的就是那个软件。。。。。。。。是不是飞行员都在用那个模拟飞行软件就不得人知了。。。。<img height="48" src="https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/smile.gif" width="48" /></p>
页: [1]
查看完整版本: 【Follow me第二季第4期】任务二:IMU知识+IMU数据读取+IMU控制立方体