[作品提交] 【得捷电子Follow me第2期】任务4分任务5:AI功能应用LIS3DH/MPU6050手势识别姿态解算

怀66   2023-9-10 17:22 楼主

 分任务5:AI功能应用——结合运动传感器,完成手势识别功能,至少要识别三种手势(如水平左右、前后、垂直上下、水平画圈、垂直画圈,或者更复杂手势

    这个任务可难,可简单我也有两个思路。

    ①就是简单的判断加速度xyz轴是否超过规定的阈值,从而实现上下左右前后,6个方向的识别。买来的LIS3DH是个三轴加速度计,有STEMMAQT接口,买好对应的线可以直接和板子上的接口接在一起,其实就是IIC通信接口,很方便。但是注意的是,一开始我在淘宝搜的时候就搜索的jst SH 4 pin,买回来后插上去LIS3DH的led灯不亮,原因是这个线是同向的,而其实是要求反向的。这么说大家可能没理解,大概意思是二esp32的gnd,vcc,sda,scl连接了传感器的scl,sda,vcc,gnd。第二次我重新买线,搜索的是STEMMAQT并观察了接口方向才买的,倒霉的是一根线几毛钱,运费却要4块😔。

image.png  

image.png  

    第二次买来的线是对的,接上去就亮了。首先我们尝试读取数据,有官方的库提供参考。

    效果:注意区别方向,这里我是x轴正方向朝右

lis3dh加速度数据读取

 

可以看到,随着传感器只朝者一个方向来回运动的时候,某一轴的加速度会变化。

数据读取代码:

import time
import board
import busio
import adafruit_lis3dh

i2c = board.I2C()  
lis3dh = adafruit_lis3dh.LIS3DH_I2C(i2c)

# Set range of accelerometer (can be RANGE_2_G, RANGE_4_G, RANGE_8_G or RANGE_16_G).
lis3dh.range = adafruit_lis3dh.RANGE_2_G

while True:
    # Read accelerometer values (in m / s ^ 2).  Returns a 3-tuple of x, y,
    # z axis values.  Divide them by 9.806 to convert to Gs.
    x, y, z = [
        value / adafruit_lis3dh.STANDARD_GRAVITY for value in lis3dh.acceleration
    ]
    print("x = %0.3f G, y = %0.3f G, z = %0.3f G" % (x, y, z))
    # Small delay to keep things responsive but give time for interrupt processing.
    time.sleep(0.1)


接下来,我们就给每个方向设置阈值,把识别的方向通过屏幕显示出来,本来我也准备了rgb小灯的亮灭来展示识别的方向的,奈何视像头太差了拍不出效果。

简单动作识别效果:

简单动作识别

 

可以看出,确实可以识别动作,但是影响太大。

代码:

import time
import board
import busio
import adafruit_lis3dh
import displayio
from adafruit_display_text import label
from adafruit_st7789 import ST7789
from adafruit_bitmap_font import bitmap_font

#-----------------------显示设置-------------------------------------------------
# First set some parameters used for shapes and text
BORDER = 20
FONTSCALE = 3
BACKGROUND_COLOR = 0x000000  # Bright Green
TEXT_COLOR = 0xffffff
font_file = "wenquanyi_13px.pcf"
font = bitmap_font.load_font(font_file)

# Release any resources currently in use for the displays
displayio.release_displays()

spi = board.SPI()
tft_cs = board.TFT_CS
tft_dc = board.TFT_DC

display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs)
display = ST7789(
    display_bus, rotation=270, width=240, height=135, rowstart=40, colstart=53
)

# Make the display context
splash = displayio.Group()
display.show(splash)

color_bitmap = displayio.Bitmap(display.width, display.height, 1)
color_palette = displayio.Palette(1)
color_palette[0] = BACKGROUND_COLOR

bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)

# Draw a label
text = "动作识别"
text_area = label.Label(font, text=text, color=TEXT_COLOR)
text_width = text_area.bounding_box[2] * FONTSCALE
text_group = displayio.Group(
    scale=FONTSCALE,
    x=display.width // 2 - text_width // 2,
    y=display.height // 2,
)
text_group.append(text_area)  # Subgroup for text scaling
splash.append(text_group)
#------------------------------分割线-----------------------------------------------------

#传感器通信初始化
i2c = board.I2C()  
lis3dh = adafruit_lis3dh.LIS3DH_I2C(i2c)
lis3dh.range = adafruit_lis3dh.RANGE_2_G

time.sleep(2)
text_area.text = '开始'
text_group.scale = 8
while True:
    acc_x, acc_y, acc_z = [value / adafruit_lis3dh.STANDARD_GRAVITY for value in lis3dh.acceleration]
    text_group.scale = 8
    if acc_x >= 1:
#         print('right')
        text_area.text = '右'
        time.sleep(1)
    elif acc_x <= -1:
#         print('left')
        text_area.text = '左'
        time.sleep(1)
    elif acc_y >= 1:
#         print('qian')
        text_area.text = '前'
        time.sleep(1)
    elif acc_y <= -1:
#         print('hou')
        text_area.text = '后'
        time.sleep(1)
    elif acc_z >= 1.8:
#         print('up')
        text_area.text = '上'
        time.sleep(1)
    elif acc_z <= 0.2:
#         print('down')
       text_area.text = '下'
       time.sleep(1)
#     print(acc_x, acc_y, acc_z)



 

②接下来使用DTW算法,这个算是AI功能应用了,我觉得所谓AI其实就是算法+数据。DTW算法简单来说,就是比较序列之间的相似性,记录测试动作为一段时间序列,其内容是三轴加速度数据,通过比较测试动作的序列与已知动作的序列,找到最相似的,从而实现动作识别。

    我主要参考的资料:bugyu_ld的个人空间_哔哩哔哩_bilibili树莓派-MPU6050+DTW算法实现简单动作识别_哔哩哔哩_bilibili。原作者使用的是树莓派+MPU6050,这里我使用的是ESP32S3+LIS3DH,原作者使用python编程,这里我将其代码移植了过来,可以使用micropython/circuitpython跑,由于后两者都是python3语法,改动起来很方便,如库的区别,比如要使用的是ulab里的numpy库等等内容。

    特别注意,由于需要向esp32中写数据。需要禁用u盘模式,否者无法写入文件。操作也很简单,在boot.py中:

     image.png  

    加入storage.disable_usb_drive()语句就可以了。

    接下来运行主函数,第一次运行的话,我们需要先录制动作,输入动作名称,记录动作,数据保存在npy_data文件夹里(需要自己先创建个空文件夹),文件结尾是.npy其实就是npy数组,这个形式可以存储也可以方便numpy计算。

image.png  

    在原作者的程序里,是可以将一个动作录制多次的,最后会计算一个动作多个序列的平均值作为距离评估。但是由于单片机和micropython/circuitpython性能有限,这里我就将一个动作只记录一次了。而且如果记录的数据过多,计算起来是真的很慢,就像上面我有10组数据,计算起来10几20秒都有了吧。

    所以这里我是我将分为两组动作演示,一个是简单动作组:上下左右前后;一个是复杂动作组:圆形,三角形,方形,五角星,垂直的圆。

    简单动作DTW算法识别:

    
    由于down一直没识别出来所以就重新录了一次。

    复杂动作DTW算法识别:

可以看出,识别效果不是很佳,但是能跑就行!😂🤣🤡

代码:

from ulab import numpy as np 
import os
import adafruit_lis3dh
import time
import board

def MIN(a,b,c):
    return np.min([a,b,c])

def dis_abs(x, y):
    return abs(x-y)[0]
    
def NORM(x):
    return np.sqrt(np.dot(x,x))
    
def dis_ACC(x,y):
    scale = 0.5
    diff = x-y
    dis = np.dot(x,y)/( NORM(x) * NORM(y) + 1e-8)
    
    dis = (1-scale*dis) * NORM(diff)
    
    return dis
    
def estimate_dtw(A,B,dis_func=dis_ACC):
    
    N_A = len(A)
    N_B = len(B)
    
    D = np.zeros([N_A,N_B])
    D[0,0] = dis_func(A[0],B[0])
    
    # 左边一列
    for i in range(1,N_A):
        D[i,0] = D[i-1,0]+dis_func(A[i],B[0])
    # 下边一行
    for j in range(1,N_B):
        D[0,j] = D[0,j-1]+dis_func(A[0],B[j])
    # 中间部分
    for i in range(1,N_A):
        for j in range(1,N_B):        
            D[i,j] = dis_func(A[i],B[j])+min(D[i-1,j],D[i,j-1],D[i-1,j-1])
            
    # 路径回溯
    i = N_A-1
    j = N_B-1
    count =0
    d = np.zeros(max(N_A,N_B)*3)
    path = []
    while True:
        if i>0 and j>0:
            path.append((i,j))
            m = min(D[i-1, j],D[i, j-1],D[i-1,j-1])
            if m == D[i-1,j-1]:
                d[count] = D[i,j] - D[i-1,j-1]
                i = i-1
                j = j-1
                count = count+1
                
            elif m == D[i,j-1]:
                d[count] = D[i,j] - D[i,j-1]
                j = j-1
                count = count+1
    
            elif m == D[i-1, j]:
                d[count] = D[i,j] - D[i-1,j]
                i = i-1
                count = count+1
                
        elif i == 0 and j == 0:
            path.append((i,j))
            d[count] = D[i,j]
            count = count+1
            break
        
        elif i == 0:
            path.append((i,j))
            d[count] = D[i,j] - D[i,j-1]
            j = j-1
            count = count+1
        
        elif j == 0:
            path.append((i,j))
            d[count] = D[i,j] - D[i-1,j]
            i = i-1
            count = count+1
            
    mean = np.sum(d) / count
    return mean, path[::-1],D
    

def mov_record(MPU):
    data_record = []
    print('请在1.5s内完成动作')
    time.sleep(0.1)
    for i in range(50):
        time.sleep(0.03)
        accs= [value / adafruit_lis3dh.STANDARD_GRAVITY for value in lis3dh.acceleration]
        data_record.append(accs)
    print('动作结束')    
    return data_record

def get_mov_list():
    try:
        os.chdir('npy_data')
    except:
        pass
    list_files = []
    list_labs = []
    
    for i in os.listdir():
        if i.endswith('.npy'):
           list_files.append(i)
        
    for file in list_files:
        lab = file.split('.')[0]
        list_labs.append(lab)
    
    return list_files,list_labs




if __name__ == "__main__":
    try:
        os.chdir('npy_data')
    except:
        pass
    i2c = board.I2C()
    lis3dh = adafruit_lis3dh.LIS3DH_I2C(i2c)
    lis3dh.range = adafruit_lis3dh.RANGE_2_G
    try:
        while True:
            print('1 录制 2 测试 3 退出')
            opt = input()
            
            if opt == '1':
                str_mov = input('请输入动作名称')
                print('3 秒后开始录制动作 %s'%(str_mov))
                time.sleep(3)
                # 录制动作
                mov_data = mov_record(lis3dh)
                
                # 进行保存
                file_name = str(str_mov)+".npy"
                np.save(file_name,np.array(mov_data))
                continue
            
            elif opt == '2':
                print('3 秒后开始录制测试动作')
                time.sleep(3)
                test_mov = mov_record(lis3dh)
                print('计算结果中,请耐心等待')
                
              
                scores = []
                files,labs = get_mov_list()
                
                if len(files)<1:
                    print('没有找到存储动作,请先进行动作录制')
                    continue
                
                # 计算捕捉的动作与存储动作的距离
                for file in files:
                    # 加载动作数据
                    data_train = np.load(file)
                    # 计算测试动作与存储动作之间的距离
                    score,_,_ = estimate_dtw(np.array(test_mov),data_train)
                    scores.append(score)
                
                # 找到最小值的距离
                for lab in labs:
                    print('{:^9}'.format(lab),end=' ')
                print('\n')
                for lab in labs:
                    print('{:^9}'.format('|'),end=' ')
                print('\n')
                print(scores)
                index = scores.index(min(scores))
                print('测试动作为 '+labs[index])
               
                continue
                
            elif opt == '3':
                break
                
    except KeyboardInterrupt:
        print('\n Ctrl + C QUIT')            
                

第二部分:MPU6050

MPU6050可以记录三轴加速度,三轴加速度。所以上面的工作它也可以做,这里就不多赘述了。官方资料里搜索MPU6050就可以实现读取其6轴信息还有温度,再结合我上面的步骤也可以实现功能。注意单位区别,好像两个传感器读取的数据范围不太一样,我记得LIS3DH代码会除去重力作用吧(除以重力),我没太注意,但发现有区别。

下面是官方的例子读取MPU6050代码:

# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

import time
import board
import adafruit_mpu6050

i2c = board.I2C()  # uses board.SCL and board.SDA
# i2c = board.STEMMA_I2C()  # For using the built-in STEMMA QT connector on a microcontroller
mpu = adafruit_mpu6050.MPU6050(i2c)

while True:
    print("Acceleration: X:%.2f, Y: %.2f, Z: %.2f m/s^2" % (mpu.acceleration))
    print("Gyro X:%.2f, Y: %.2f, Z: %.2f rad/s" % (mpu.gyro))
    print("Temperature: %.2f C" % mpu.temperature)
    print("")
    time.sleep(1)

mpu6050 dtw算法代码:

from ulab import numpy as np 
import os
import uuid
import adafruit_mpu6050
import time
import board

def MIN(a,b,c):
    return np.min([a,b,c])

def dis_abs(x, y):
    return abs(x-y)[0]
    
def NORM(x):
    return np.sqrt(np.dot(x,x))
    
def dis_ACC(x,y):
    scale = 0.5
    diff = x-y
    dis = np.dot(x,y)/( NORM(x) * NORM(y) + 1e-8)
    
    dis = (1-scale*dis) * NORM(diff)
    
    return dis
    
def estimate_dtw(A,B,dis_func=dis_ACC):
    
    N_A = len(A)
    N_B = len(B)
    
    D = np.zeros([N_A,N_B])
    D[0,0] = dis_func(A[0],B[0])
    
    # 左边一列
    for i in range(1,N_A):
        D[i,0] = D[i-1,0]+dis_func(A[i],B[0])
    # 下边一行
    for j in range(1,N_B):
        D[0,j] = D[0,j-1]+dis_func(A[0],B[j])
    # 中间部分
    for i in range(1,N_A):
        for j in range(1,N_B):        
            D[i,j] = dis_func(A[i],B[j])+min(D[i-1,j],D[i,j-1],D[i-1,j-1])
            
    # 路径回溯
    i = N_A-1
    j = N_B-1
    count =0
    d = np.zeros(max(N_A,N_B)*3)
    path = []
    while True:
        if i>0 and j>0:
            path.append((i,j))
            m = min(D[i-1, j],D[i, j-1],D[i-1,j-1])
            if m == D[i-1,j-1]:
                d[count] = D[i,j] - D[i-1,j-1]
                i = i-1
                j = j-1
                count = count+1
                
            elif m == D[i,j-1]:
                d[count] = D[i,j] - D[i,j-1]
                j = j-1
                count = count+1
    
            elif m == D[i-1, j]:
                d[count] = D[i,j] - D[i-1,j]
                i = i-1
                count = count+1
                
        elif i == 0 and j == 0:
            path.append((i,j))
            d[count] = D[i,j]
            count = count+1
            break
        
        elif i == 0:
            path.append((i,j))
            d[count] = D[i,j] - D[i,j-1]
            j = j-1
            count = count+1
        
        elif j == 0:
            path.append((i,j))
            d[count] = D[i,j] - D[i-1,j]
            i = i-1
            count = count+1
            
    mean = np.sum(d) / count
    return mean, path[::-1],D
    

def mov_record(MPU):
    data_record = []
    print('请在1.5s内完成动作')
    time.sleep(0.1)
    for i in range(50):
        time.sleep(0.03)
        accs=MPU.acceleration
        data_record.append(accs)
    print('动作结束')    
    return data_record

def get_mov_list():
    try:
        os.chdir('npy_data')
    except:
        pass
    list_files = []
    list_labs = []
    
    for i in os.listdir():
        if i.endswith('.npy'):
           list_files.append(i)
        
    for file in list_files:
        lab = file.split('.')[0]
        list_labs.append(lab)
    
    return list_files,list_labs




if __name__ == "__main__":
    try:
        os.chdir('npy_data')
    except:
        pass
    i2c = board.I2C()
    m_MPU = adafruit_mpu6050.MPU6050(i2c) 
    try:
        while True:
            print('1 录制 2 测试 3 退出')
            opt = input()
            
            if opt == '1':
                str_mov = input('请输入动作名称')
                print('3 秒后开始录制动作 %s'%(str_mov))
                time.sleep(3)
                # 录制动作
                mov_data = mov_record(m_MPU)
                
                # 进行保存
                file_name = str(str_mov)+".npy"
                np.save(file_name,np.array(mov_data))
                continue
            
            elif opt == '2':
                print('3 秒后开始录制测试动作')
                time.sleep(3)
                test_mov = mov_record(m_MPU)
                
              
                scores = []
                files,labs = get_mov_list()
                
                if len(files)<1:
                    print('没有找到存储动作,请先进行动作录制')
                    continue
                
                # 计算捕捉的动作与存储动作的距离
                for file in files:
                    # 加载动作数据
                    data_train = np.load(file)
                    # 计算测试动作与存储动作之间的距离
                    score,_,_ = estimate_dtw(np.array(test_mov),data_train)
                    scores.append(score)
                
                # 找到最小值的距离
                print(scores)
                index = scores.index(min(scores))
                print('测试动作为 '+labs[index])
               
                continue
                
            elif opt == '3':
                break
                
    except KeyboardInterrupt:
        print('\n Ctrl + C QUIT')            
                

 

mpu6050可以读取6轴信息,可以拿来做姿态解算,就是算出俯仰角、翻滚角和航向角。

参考链接:FallPrevent: Raspberry-pico micro-python读取mpu6050 老人防跌倒 (gitee.com)GitHub - narutogo/micropython-mpu6050-: micropython mpu6050 用四元数或者一节互补滤波解算角度

解算部分我当然是不会的啦,主要就是大概看了下原理,云里雾里的,然后使用了大佬的库,自己随便写了点代码,然后通过串口传输给电脑,电脑上位机展示效果。

上位机参考链接:esp32系列(11):ESP32 IDF平台 mpu6050 DMP 驱动移植及测试上位机开发_esp-idf写mpu6050驱动_lu-ming.xyz的博客-CSDN博客

效果展示:效果一般,我的评价是能用就行。俯仰角,翻滚角倒是还能用,航向角就效果很差了,看资料说如果配合磁力计得到9轴陀螺仪数据再加上一个好的算法,姿态解算结果是很好的。

姿态

 

代码:主函数

from zitai_slove import Update_IMU
from q4 import IMUupdate
from One_filter import one_filter
import board  
import busio  
uart = busio.UART(board.TX, board.RX, baudrate=115200, receiver_buffer_size=2048)

import time
import board
import adafruit_mpu6050

i2c = board.I2C()  # uses board.SCL and board.SDA
# i2c = board.STEMMA_I2C()  # For using the built-in STEMMA QT connector on a microcontroller
mpu = adafruit_mpu6050.MPU6050(i2c)

while True:
    acc_x, acc_y, acc_z = [value for value in mpu.acceleration]
    gyro_x, gyro_y, gyro_z = [value for value in mpu.gyro]
#     print('加速度', acc_x, acc_y, acc_z, '\n', '角速度', gyro_x, gyro_y, gyro_z)
#     print("Acceleration: X:%.2f, Y: %.2f, Z: %.2f m/s^2" % (mpu.acceleration))
#     print("Gyro X:%.2f, Y: %.2f, Z: %.2f rad/s" % (mpu.gyro))
#     print("Temperature: %.2f C" % mpu.temperature)
#     print("")
    zitai = Update_IMU(acc_x, acc_y, acc_z, gyro_x, gyro_y, gyro_z)
#     zitai = IMUupdate(acc_x, acc_y, acc_z, gyro_x, gyro_y, gyro_z) #q4
#     zitai = one_filter(acc_x, acc_y, acc_z, gyro_x, gyro_y, gyro_z)  #one_filter
    print(zitai)
    zitai = bytearray(f'pitch:{zitai[0]}, roll:{zitai[1]}, yaw:{zitai[2]}')     #pitch:, roll:, yaw:
    uart.write(zitai)#发送一条数据
#     time.sleep(0.1)
   


库zitai_slove

#coding:utf-8

import math

#IMU算法更新


Kp = 100 #比例增益控制加速度计/磁强计的收敛速度
Ki = 0.002 #积分增益控制陀螺偏差的收敛速度
halfT = 0.001 #采样周期的一半

#传感器框架相对于辅助框架的四元数(初始化四元数的值)
q0 = 1
q1 = 0
q2 = 0
q3 = 0

#由Ki缩放的积分误差项(初始化)
exInt = 0
eyInt = 0
ezInt = 0

def Update_IMU(ax,ay,az,gx,gy,gz):
    global q0
    global q1
    global q2
    global q3
    global exInt
    global eyInt
    global ezInt
    # print(q0)
    
    #测量正常化
    norm = math.sqrt(ax*ax+ay*ay+az*az)
    #单元化
    ax = ax/norm
    ay = ay/norm
    az = az/norm
    
    #估计方向的重力
    vx = 2*(q1*q3 - q0*q2)
    vy = 2*(q0*q1 + q2*q3)
    vz = q0*q0 - q1*q1 - q2*q2 + q3*q3
    
    #错误的领域和方向传感器测量参考方向之间的交叉乘积的总和
    ex = (ay*vz - az*vy)
    ey = (az*vx - ax*vz)
    ez = (ax*vy - ay*vx)
    
    #积分误差比例积分增益
    exInt += ex*Ki
    eyInt += ey*Ki
    ezInt += ez*Ki
    
    #调整后的陀螺仪测量
    gx += Kp*ex + exInt
    gy += Kp*ey + eyInt
    gz += Kp*ez + ezInt
    
    #整合四元数
    q0 += (-q1*gx - q2*gy - q3*gz)*halfT
    q1 += (q0*gx + q2*gz - q3*gy)*halfT
    q2 += (q0*gy - q1*gz + q3*gx)*halfT
    q3 += (q0*gz + q1*gy - q2*gx)*halfT
    
    #正常化四元数
    norm = math.sqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3)
    q0 /= norm
    q1 /= norm
    q2 /= norm
    q3 /= norm
    
    #获取欧拉角 pitch、roll、yaw
    pitch = math.asin(-2*q1*q3+2*q0*q2)*57.3
    roll = math.atan2(2*q2*q3+2*q0*q1,-2*q1*q1-2*q2*q2+1)*57.3
    yaw = math.atan2(2*(q1*q2 + q0*q3),q0*q0+q1*q1-q2*q2-q3*q3)*57.3
    return pitch,roll,yaw

其他的库可以看我给出的参考连接,这个库贴出来是因为我自己不知道在哪找的啦。

 

另外还可以使用mpu6050自带的dmp处理数据得出姿态角。这里这位大佬有做,链接如下:(演示)mpu6050+esp32 mpy,dmp姿态角运算。三行代码实现调用_哔哩哔哩_bilibili可以去群里找代码哦。这里我不贴出来了,不太好。这里我没复刻成功,原因是栈溢出了,我不知道怎么解决。😥

但是我参考了那个大佬树莓派+mpu6050的成功了,我手头刚好有个树莓派3b+就试了一下,dmp解算姿态角效果挺好的(航向角除外)。

 

综上,这个任务就结束了。

 

 

 

 

 

 

 

 

 

 

本帖最后由 怀66 于 2023-9-10 21:31 编辑

回复评论 (5)

DTW算法录入路径的时候需要录入多少条?

点赞  2023-9-11 09:24
引用: wangerxian 发表于 2023-9-11 09:24 DTW算法录入路径的时候需要录入多少条?

按自己需要啊,你记录了几个动作,测试时就会拿测试动作去记录的动作里找最像的,从而实现识别。所以不能记录太多动作,否者算起来会很慢。

点赞  2023-9-11 10:32
引用: 怀66 发表于 2023-9-11 10:32 按自己需要啊,你记录了几个动作,测试时就会拿测试动作去记录的动作里找最像的,从而实现识别。所以不能 ...

一个动作只记录一次嘛?我认知里,一个动作要重复多次,才能提高识别的鲁棒性。

点赞 (1) 2023-9-11 15:30
引用: wangerxian 发表于 2023-9-11 15:30 一个动作只记录一次嘛?我认知里,一个动作要重复多次,才能提高识别的鲁棒性。

是的是的,你所的对。原作者里一个动作是可以记录多次的,记录分数时取均值就行,但是我移植过来的时候,一开始没考虑这么多,写储存文件的代码的时候没有考虑,如果将同一个动作记录在动作名称的文件夹下即可,原作者是用uuid避免同一动作文件夹下文件重复的。另一个原因就是因为性能了,单片机性能可能真处理不了那么多序列,太慢了,加上micro python/circuitpython也比较慢的原因。具体可参考我发的链接,原作者是用树莓派做的,我自己也是现在树莓派上做了验证才移植到esp32上的。树莓派-MPU6050+DTW算法实现简单动作识别_哔哩哔哩_bilibili,算法核心层面上我都没动的,我就修改了一部分让其能跑,自己也偷懒了没重新写记录重复动作的文件,其实我也不知道如何在circuitpython/mpy里生成不会重复的名称,(不过好像random就可以用),原作者用的uuid,mpy/cpy里没有这个库我就简单弄了。

点赞  2023-9-11 16:18
非常好,内容很详细,图文并茂,学习了。!!!!!
点赞  2023-11-29 20:57
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复