记录|智能视觉人体追随
前言
本设计为本人的本科毕设,此文用于记录分享。相关设计指标如下:
- 设计主控电路及合适的底部运动结构;设计箱体的整体结构。
- 设计符合航空托运标准的USB接口的充电结构及电源电路的设计,并能够提供在0.5m/s的运行速度下3小时的续航。
- 设计跟随模块选择合适的跟随识别方案,要求能够设置保持跟随距离分别在50cm、100cm、200cm并且预设跟随值与实际测量距离值误差不高于15%。
- 选择合适的控制方法进行运动结构的驱动设计,要求设计时速可以达到0.15m/s~0.5m/s。
- 设计避障模块,可识别200cm内的障碍物,精度±2cm。
- 设计语音播报模块,当用户与行李箱距离超过300cm或超出30s无识别时发出红色LED灯并有声音警报声。
- 上位机/APP终端:
最终所有设计任务均已实现。
MaixCam
MaixCam是sipeed于24年推出的一款嵌入式智能摄像头,具有强大的AI计算能力,本设计与AI相关的功能都运行在此平台上。
MaixCam支持两种开发方式:MaixVision与MaixCDK,前者使用python方便快捷,后者使用C/C++效率高(事实上使用python一般也都是cpython,即底层轮子为C编译出来的库,效率也可以达到很高)。使用CDK的话主要参考下列几篇文章:
- 环境搭建与编译测试
- 点灯测试
- LVGL的使用
视觉追踪
经调研后,发现有两种方法能实现对特定目标(如人体)的识别与追踪:目标检测算法+deepsort或者自学习追踪算法,本次设计使用的后者。
官方Git地址,在MaixCam中,官方已经移植完成,我们直接使用即可目标测距
使用单目测距 其中D是目标到摄像机的距离, F是摄像机焦距(焦距需要自己进行标定获取), W是目标的宽度或者高度(行人检测一般以人的身高为基准), P是指目标在图像中所占据的像素,参考文章。实现上极为简单,对应精度也很有限,如有精度、稳定性要求还是应该使用双目测距、激光雷达或者TOF。1
2
3
4
5
6
7
8# 首先基于实际测量数据计算出K值,再在后续中调用K值计算距离即可,简单的等比例计算
def caculate_k(width, distance):
return width * distance
def caculate_distance(width, k):
return k / width
k = caculate_k(46, 120) # 46个像素点对应120cm控制
小车电机控制使用经典的stm32c8t6即可实现。PID
电机转速控制使用增量式PID,转向环使用位置式PD,距离环使用位置式PID1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76int Motor_PID1(int input_speed,int setspeed) //增量式PID,PI用于速度闭环控制
{
static double pwmout=0,last_error=0,last_last_error=0,dpwmout= 0;
float a=0.7;
float error =setspeed - input_speed; // 误差
error = (1-a)*error + a*last_error; // 使得波形更加平滑,滤除高频干扰,防止速度突变
float d_error=error-last_error;
float dd_error = -2*last_error+error+last_last_error;
pwmout+=PID1.KP*d_error + PID1.KI*error + PID1.KD*dd_error; // 输出pwm信号
last_last_error=last_error;
last_error = error;
if(pwmout > 100) pwmout = 100;
else if(pwmout < -100) pwmout = -100;
return pwmout;
}
int Turn_PID(int input,int target) //位置式PD,用于速度闭环控制
{
static double pwmout=0, last_error=0;
float a=0.7;
double error =target - input; // 误差
// error = (1-a)*error + a*last_error; // 使得波形更加平滑,滤除高频干扰,防止速度突变
double d_error=error-last_error;
pwmout = PID_Turn.KP*error + PID_Turn.KD*d_error; // 输出pwm信号
last_error = error;
if(pwmout > 5) pwmout = 5;
else if(pwmout < -5) pwmout = -5;
return (int)round(pwmout);
}
int Dis_PID(int input,int target) //位置式PID,用于距离闭环控制
{
static double pwmout=0, last_error=0, integral_sum=0;
float a=0.7;
float error =target - input; // 误差
error = (1-a)*error + a*last_error; // 使得波形更加平滑,滤除高频干扰,防止速度突变
float d_error=error-last_error;
integral_sum += error;
if (integral_sum > 2)
{
integral_sum = 2;
}
else if (integral_sum < -2)
{
integral_sum = -2;
}
pwmout = PID_Dis.KP*error + PID_Dis.KI*integral_sum + PID_Dis.KD*d_error; // 输出pwm信号
last_error = error;
if(pwmout > 10) pwmout = 10;
else if(pwmout < -10) pwmout = -10;
if(pwmout>=-1 && pwmout<=1) pwmout = 0;
return (int)round(pwmout);
}硬件
在本次设计中,需绘制PCB,电路简单,但为了布线方便仍使用四层板设计。
开关电源部分有两个要点:
- 通畅,即电流的路径
- 防干扰
在整体上,还要打地孔
硬件选型:
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 DIKLE | 记录!