M-Design设计竞赛 - 基于STM32N6设计的人体姿态识别系统
该项目使用了STM32N6,实现了人体姿态识别的设计,它的主要功能为:人体姿态识别。
标签
M-Design
STM32N6
人体姿态识别
冷月烟
更新2025-04-01
89

项目介绍和创意介绍

当前人体姿态识别技术主要依赖云端服务器或高性能芯片,存在高延迟、高功耗、隐私泄露风险和成本高昂等问题,难以在工业安全、家庭健康监护等场景中规模化落地。基于此我设计了一款基于STM32N6设计的人体姿态识别系统,通过运行神经网络,可用于体感游戏动作捕捉、体操运动姿势纠正、老人跌倒检测等。通过“低成本硬件+轻量化算法+场景化设计”三位一体的创 新,直击边缘AI落地的核心痛点——“既要高性能,又要白菜价”。

方案框图和项目设计思路介绍

硬件框图

图片.png

设计思路

  1. 设计原理图,对使用到的电源、flash等芯片进行选型,确保能发挥STM32N6最大性能。
  2. 绘制PCB,做好高频线等长设计,确保参考面完整,阻抗连续。
  3. 焊接并测试,完成板卡焊接与基本功能验证,实现LCD、摄像头驱动开发。
  4. 训练模型,在COCO数据集上训练模型
  5. 部署模型,利用ST Edge AI 云服务对模型进行量化并转化为N6可运行的代码。使用STM32Cube.AI对模型进行部署。

硬件介绍

STM32N6核心板

  • STM32N6x7xx器件基于高性能Arm® Cortex®-M55,工作频率高达800 MHz。
  • Cortex®-M55内核采用Arm® Helium™矢量处理技术。除了标准微控制器任务外,该内核还能实现高能效的数字信号处理。Cortex®-M55配备浮点运算单元 (FPU),支持单精度和半精度(符合IEEE 754标准)数据处理。
  • ST Neural-ART加速器运行频率高达1 GHz,可提供600 Gops,利用优化的硬件单元实现DNN(深度神经网络)推理功能,同时优化功耗效率。
  • Neo-Chrom图形加速器通过提供缩放、高质量插值、自由旋转、Alpha混合、纹理映射和透视变换等功能的硬件加速,确保高效的2.5D图形处理。
  • 对于摄像头应用,集成了并行和CSI接口,并前瞻性地配备了硬件ISP。

STM32N6底板

搭配核心板使用,引出两路USB,RGB接口,CSI摄像头接口。

RGB屏幕

4.3寸电容触摸屏,分辨率为800×480, 支持24位RGB接口显示,可显示1678万种色彩,支持I2C接口控制电容触摸,5点触控。

IMX335模块

高分辨率5-Mpx IMX335LQN CMOS RGB图像传感器、ISM330DLC惯性运动单元和VL53L5CX ToF传感器。它可与任何具有MIPI CSI-2®接口和22引脚FFC连接器的STM32开发板一起使用,在STM32微控制器和微处理器上轻松实现全功能计算机视觉。

整体图

原理图和PCB介绍

核心板

Top部分

image.png

核心供电部分

为N6核心部分提供供电,通过PWR_LP脚控制输出电压,当核心供电为0.81V时,芯片可运行在600MHz,当核心供电为0.89V时,芯片可运行在800MHz。

image.png

其他供电部分

为芯片提供3.3V和1.8V供电电压,其中VDDIO和VDDA1V8_AON需要提前上电,之后PWR_ON控制VDD3V3、VDDA1V8和VDDCORE进行上电。

image.png

PSRAM部分

采用APS256XXN芯片,运行在x16 DDR 200MHz模式。

image.png

Flash部分

采用MX66UW1G45GXD100T芯片,1.8V电压,8线1Gbit容量。

image.png

接口部分

基本引出所有IO,CSI和USB接口尽量最近引出。

image.png

PCB部分

采用6层板设计,3个走线层、2个电源层、1个地层。尺寸为3.94*3.31cm。

image.png

底板

CSI摄像头接口

兼容树莓派5CSI接口设计,可直接连接树莓派5摄像头进行使用。

image.png

屏幕接口

RGB屏幕接口,支持PWM背光控制,电容触摸。

image.png

PCB部分

采用4层板设计,2个走线层、1个电源层、1个地层。尺寸为7.67*6.07cm。

image.png

软件流程图和关键代码介绍

流程图

图片.png

NN初始化部分

LL_ATON_DECLARE_NAMED_NN_INSTANCE_AND_INTERFACE(Default);
const LL_Buffer_InfoTypeDef *nn_in_info = LL_ATON_Input_Buffers_Info_Default();
const LL_Buffer_InfoTypeDef *nn_out_info = LL_ATON_Output_Buffers_Info_Default();

nn_in = (uint8_t *) LL_Buffer_addr_start(&nn_in_info[0]);
float32_t *nn_out[MAX_NUMBER_OUTPUT];
int32_t nn_out_len[MAX_NUMBER_OUTPUT];

int number_output = 0;

/* Count number of outputs */
while (nn_out_info[number_output].name != NULL)
{
number_output++;
}
assert(number_output <= MAX_NUMBER_OUTPUT);

for (int i = 0; i < number_output; i++)
{
nn_out[i] = (float32_t *) LL_Buffer_addr_start(&nn_out_info[i]);
nn_out_len[i] = LL_Buffer_len(&nn_out_info[i]);
}

uint32_t nn_in_len = LL_Buffer_len(&nn_in_info[0]);
uint32_t pitch_nn = 0;

UNUSED(nn_in_len);

图像识别

while (1)
{
CAM_IspUpdate();

if (pitch_nn != (NN_WIDTH * NN_BPP))
{
/* Start NN camera single capture Snapshot */
CAM_NNPipe_Start(dcmipp_out_nn, CMW_MODE_SNAPSHOT);
}
else
{
/* Start NN camera single capture Snapshot */
CAM_NNPipe_Start(nn_in, CMW_MODE_SNAPSHOT);
}

while (cameraFrameReceived == 0) {};
cameraFrameReceived = 0;

uint32_t ts[2] = { 0 };

if (pitch_nn != (NN_WIDTH * NN_BPP))
{
SCB_InvalidateDCache_by_Addr(dcmipp_out_nn, sizeof(dcmipp_out_nn));
img_crop(dcmipp_out_nn, nn_in, pitch_nn, NN_WIDTH, NN_HEIGHT, NN_BPP);
SCB_CleanInvalidateDCache_by_Addr(nn_in, nn_in_len);
}

ts[0] = HAL_GetTick();
/* run ATON inference */
LL_ATON_RT_Main(&NN_Instance_Default);
ts[1] = HAL_GetTick();

int32_t ret = app_postprocess_run((void **) nn_out, number_output, &pp_output, &pp_params);
assert(ret == 0);

Display_NetworkOutput(&pp_output, ts[1] - ts[0]);
/* Discard nn_out region (used by pp_input and pp_outputs variables) to avoid Dcache evictions during nn inference */
for (int i = 0; i < number_output; i++)
{
float32_t *tmp = nn_out[i];
SCB_InvalidateDCache_by_Addr(tmp, nn_out_len[i]);
}
}

识别信息显示

显示识别到的人体姿势与单帧识别时间。

static void Display_NetworkOutput(void *p_postprocess, uint32_t inference_ms)
{
#if POSTPROCESS_TYPE == POSTPROCESS_MPE_YOLO_V8_UF
mpe_pp_outBuffer_t *rois = ((mpe_pp_out_t *) p_postprocess)->pOutBuff;
uint32_t nb_rois = ((mpe_pp_out_t *) p_postprocess)->nb_detect;
#elif POSTPROCESS_TYPE == POSTPROCESS_SPE_MOVENET_UF
spe_pp_outBuffer_t *roi = ((spe_pp_out_t *) p_postprocess)->pOutBuff;
#endif
int ret;

ret = HAL_LTDC_SetAddress_NoReload(&hlcd_ltdc, (uint32_t) lcd_fg_buffer[lcd_fg_buffer_rd_idx], LTDC_LAYER_2);
assert(ret == HAL_OK);

/* Draw bounding boxes */
UTIL_LCD_FillRect(lcd_fg_area.X0, lcd_fg_area.Y0, lcd_fg_area.XSize, lcd_fg_area.YSize, 0x00000000); /* Clear previous boxes */
#if POSTPROCESS_TYPE == POSTPROCESS_MPE_YOLO_V8_UF
for (int i = 0; i < nb_rois; i++)
Display_mpe_Detection(&rois[i]);
UTIL_LCD_SetBackColor(0x40000000);
UTIL_LCDEx_PrintfAt(0, LINE(2), CENTER_MODE, "Objects %u", nb_rois);
UTIL_LCDEx_PrintfAt(0, LINE(20), CENTER_MODE, "Inference: %ums", inference_ms);
UTIL_LCD_SetBackColor(0);
#elif POSTPROCESS_TYPE == POSTPROCESS_SPE_MOVENET_UF
Display_spe_Detection(roi);
UTIL_LCD_SetBackColor(0x40000000);
UTIL_LCDEx_PrintfAt(0, LINE(20), CENTER_MODE, "Inference: %ums", inference_ms);
UTIL_LCD_SetBackColor(0);
#endif

Display_WelcomeScreen();

SCB_CleanDCache_by_Addr(lcd_fg_buffer[lcd_fg_buffer_rd_idx], LCD_FG_FRAMEBUFFER_SIZE);
ret = HAL_LTDC_ReloadLayer(&hlcd_ltdc, LTDC_RELOAD_VERTICAL_BLANKING, LTDC_LAYER_2);
assert(ret == HAL_OK);
lcd_fg_buffer_rd_idx = 1 - lcd_fg_buffer_rd_idx;
}

运行模型

void LL_ATON_RT_Main(NN_Instance_TypeDef *network_instance)
{
LL_ATON_RT_RetValues_t ll_aton_rt_ret;

/*** Start of user initialization code ***/

/*** End of user initialization code ***/

LL_ATON_ASSERT(network_instance != NULL);
LL_ATON_ASSERT(network_instance->network != NULL);
LL_ATON_RT_RuntimeInit(); // Initialize runtime
LL_ATON_RT_Init_Network(network_instance); // Initialize passed network instance object

do
{
/* Execute first/next step of Cube.AI/ATON runtime */
ll_aton_rt_ret = LL_ATON_RT_RunEpochBlock(network_instance);

/*** Start of user event handling code ***/

/*** End of user event handling code ***/

/* Wait for next event */
if (ll_aton_rt_ret == LL_ATON_RT_WFE)
{ /*** subject to change to fit also user code requirements ***/
LL_ATON_OSAL_WFE();
}
} while (ll_aton_rt_ret != LL_ATON_RT_DONE); /*** subject to change to fit also user code requirements ***/

LL_ATON_RT_DeInit_Network(network_instance); // De-initialize the network instance object
LL_ATON_RT_RuntimeDeInit(); // De-initialize runtime

/*** Start of user de-initialization code ***/

/*** End of user de-initialization code ***/
}

功能展示及说明

识别人体姿势,并显示到屏幕上,单帧处理时间约为18ms

图片.png

图片.png


设计中遇到的难题和解决方法

问题:焊接完PCB测试时,上电后发现可以识别到SWD接口,但是无法下载

解决办法:测试发现有一种电容的型号弄错了,全部更换后正常。

对本次竞赛的心得体会

比赛很好,盲盒很喜欢,建议多多举办。


附件下载
STM32N6底板.zip
代码.zip
团队介绍
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号