基于StmcubeMx和Clion的stm32f4单片机的嵌入式开发
一:硬件基础
本小车主要采用轮趣科技阿克曼小车以及f407VET6单片机以及拓展板
相关淘宝链接:【淘宝】https://m.tb.cn/h.gWoFBmqRHmh52o5?tk=lsuzWEfMeUD ZH4920
部分相关资料如下:(部分没有的资料可以询问淘宝客服)
二:任务要求
1、用matlab对于目标曲线进行仿真计算,拟合目标曲线
2、使用CubeMx定义所用引脚
在本部分配置引脚的过程中,需要结合文章开始部分给出的原理图进行stm32的引脚配置,在这里我们使用原理图的motorA和motorD两个电机接口,使用PB15一个舵机接口
1)在端口的定义中,首先配置RCC和SYS
2)接着定义内部时钟的频率
3)下一步去定义电机和舵机所用的端口
这段定义为第一个motor的端口定义,在这里对下面的Parameter Settings中的PSC和ARR进行更改,这里解释一下为什么更改以及更改的数值
-
计算预分频器(PSC)和重装载值(ARR):
- 假设你想要定时器每秒计数一次。
- 如果你希望定时器的计数频率为1 kHz(即每毫秒计数一次),预分频器需要将系统时钟频率降低到1 kHz。
公式:
计数频率 = 系统时钟频率 / (PSC + 1)
所以,
1 kHz = 72 MHz / (PSC + 1)
计算得:
PSC = (72 MHz / 1 kHz) - 1 = 72000 - 1 = 71999
这样,预分频器的值就设置为71999。
-
设置ARR:
- 为了使定时器每秒计数一次,ARR的值应为1000,因为1 kHz频率下每秒会有1000次计数。
-
预分频器(PSC)用于控制定时器的频率,它是一个16位值,因此其范围在0到65535之间。配置预分频器和自动重装载寄存器时,必须确保其值在有效范围内,并正确计算以实现所需的定时功能。
简单来说,控制这个来控制电机的占空比,在本定义中,PWM为0-1000,0为不转,1000满转,数值越大占空比越大。
这段定义为第二个motor的端口定义,定义同上。
这段定义为舵机的pwm定义,在本次的小车选型中,舵机为180度舵机,以下为pwm控制舵机的计算方式,通过等比例放大缩小周期可以算出输入数值对于舵机转动的影响
4)接下来去定义自己.ioc文件的名称
更改Toolchain和Code Generator
选为STM32CubeIDE和将Generate peripheralinitiali...勾选上
5)端口配置就结束了,直接点击右上角的GENERATE CODE
3、在clion中编写代码以实现控制小车的功能
由于我们做的是开环控制,所以整体上的代码控制比较简单,只在main.c函数里添加代码即可
1.关于TIM端口的初始化并打开
首先将定义的TIM接口进行初始化
//将三个TIM端口进行初始化
MX_TIM1_Init();
MX_TIM12_Init();
MX_TIM4_Init();
接下来打开三个TIM通道
//打开TIM通道
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_3);
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_4);
HAL_TIM_PWM_Start(&htim12,TIM_CHANNEL_2);
这里的TIM_CHANNEL为cubemx配置中你选择的PWM GENERATION中的通道
2.写电机的PWM调用函数
//定义函数,输入左右两个电机的PWM值
void set_motor_pwm(uint16_t pwm_value_motor11,uint16_t pwm_value_motor21)
{
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, pwm_value_motor11);
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_4, pwm_value_motor21);
}
3.主函数的实现
//寻线主函数
__HAL_TIM_SET_COMPARE(&htim12, TIM_CHANNEL_2, 1250);//(1500-2000之间,值越大舵机偏转角度越大(右转))
set_motor_pwm(1000,1000);//控制速度,值(0-1000)越大速度越大
HAL_Delay(390);//保持上面的状态不变,值越大保持的时间越长,2000为2s
__HAL_TIM_SET_COMPARE(&htim12, TIM_CHANNEL_2, 1450);
set_motor_pwm(1000,1000);
HAL_Delay(450);
__HAL_TIM_SET_COMPARE(&htim12, TIM_CHANNEL_2, 1450);
set_motor_pwm(1000,1000);
HAL_Delay(400);
__HAL_TIM_SET_COMPARE(&htim12, TIM_CHANNEL_2, 1450);
set_motor_pwm(800,800);
HAL_Delay(250);
在主函数中,调用自己写的set_motor_pwm函数以及HAL库中PWM定义的函数来定义电机和舵机的PWM
这样就可以完成小车的走Bridge of Death的任务
如果想走线更精准速度更快可以采用二分法对于主函数进行再次迭代
三:注意
由于本任务为开环控制,所以电池电量、小车的初始摆放位置均有较大影响,多次调试、谨慎充电、充电之后面临再次调试
四、matlab代码
% 清除工作空间
clear; clc;
% 定义参数向量
a = 0.4;
l = 0.4;
u = linspace(0, pi, 100);
d = 0.16; % 轴间距
w = 0.14; % 前后距
% 计算位置向量 r
x = -2*a.*((l-cos(u)).*cos(u)+(1-l)); % 使用向量 u 计算 x 坐标
y = 2*a.*(l-cos(u)).*sin(u); % 使用向量 u 计算 y 坐标
r = [x; y]; % 合并 x 和 y 成为二维数组
% 反转路径
r = fliplr(r);
u = fliplr(u);
% 计算导数的近似值
drdu = diff(r, 1, 2) ./ diff(u);
% 计算单位切向量
That = drdu ./ sqrt(sum(drdu.^2, 1));
% 反转切向量
That = -That;
% 计算线速度
V = sqrt(sum(drdu.^2, 1));
% 计算法向量(我们需要在计算切向量的基础上再做一次差分)
dThatdu = diff(That, 1, 2) ./ diff(u(1:end-1));
N = dThatdu ./ sqrt(sum(dThatdu.^2, 1)); % 法向量计算,保持单位长度
% 准备计算角速度
% 需要确保使用 diff 后 That 的维度和 diff(u) 一致
omega = abs(sqrt(sum(diff(That, 1, 2).^2, 1)) ./ diff(u(1:end-1))); % 取绝对值以确保角速度为正
% 调整V并开始作图
V = V(1:end-1); % 为了与 omega 保持一致的长度
% 计算舵机转向角度
R = V ./ omega;
theta = (atan(w ./ R) ./ pi) .* 360;
% 为线速度和角速度绘制图像
figure;
subplot(2, 1, 1);
plot(u(1:end-2), V, 'b-'); % 线速度图
title('Line Speed vs. u');
xlabel('u');
ylabel('Line Speed (V)');
subplot(2, 1, 2);
plot(u(1:end-2), omega, 'r-'); % 角速度图
title('Angular Velocity vs. u');
xlabel('u');
ylabel('Angular Velocity (omega)');
% 调整两幅图的布局
sgtitle('Velocity and Angular Velocity Characteristics');
% 计算左右轮的线速度
VL = V + 0.5 * omega .* d;
VR = V - 0.5 * omega .* d;
% 绘制整个路径并动画显示单位切向量、法向量、线速度和角速度
for i = 1:length(u) - 3
clf
hold on
plot(r(1, :), r(2, :), 'b'); % 用蓝色绘制整个路径
quiver(r(1, i), r(2, i), That(1, i), That(2, i), 0.4, 'r', 'MaxHeadSize', 2); % 用红色绘制切向量 That
quiver(r(1, i), r(2, i), N(1, i), N(2, i), 0.4, 'g', 'MaxHeadSize', 2); % 用绿色绘制法向量 N
title(sprintf('Velocity: %.2f m/s, Angular Velocity: %.2f rad/s\nVelocity_L: %.2f m/s, Velocity_R: %.2f m/s\nSteering Angle: %.2f °', V(i), omega(i), VL(i), VR(i), theta(i)));
axis equal
drawnow
end
figure;
subplot(2, 1, 1);
plot(u(1:end-2), VL, 'b-'); % 左轮速度图
title('Velocity_L vs. u');
xlabel('u');
ylabel('Velocity_L');
subplot(2, 1, 2);
plot(u(1:end-2), VR, 'r-'); % 右轮速度图
title('Velocity_R vs. u');
xlabel('u');
ylabel('Velocity_R');