前言
用超声波先避个障,日后改成激光雷达。
GPIO配置
需要配置一个定时器,一个外部中断(上升沿和下降沿都可以触发)
- 给脉冲触发引脚(trig)输入一个长为20us的高电平方波
- 输入方波后,模块会自动发射8个40KHz的声波,与此同时回波引脚(echo)端的电平会由0变为1;(此时应该启动定时器计时)
3.当超声波返回被模块接收到时,回波引 脚端的电平会由1变为0;(此时应该停止定时器计数),定时器记下的这个时间即为超声波由发射到返回的总时长。
4.根据声音在空气中的速度为344米/秒,即可计算出所测的距离。
TRIG 配置为GPIO_OUTPUT
ECHO配置为 中断模式
简而言之:就是定时器计算时间,外部中断判断超声波返回,时间X声速就是路程
实现代码
代码如下(示例):
void HC_SRC04_Start(void)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
delay_us(20);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
}
//中断处理函数 溢出的时候注意time_cnt+1
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
int time = 0;
if(GPIO_Pin == GPIO_PIN_1 )
{
if(ECHO_IRQ_FLAG == 0) //上升沿中断
{
ECHO_IRQ_FLAG = 1;
time_cnt = 0;
TIM7->CNT =0;
HAL_TIM_Base_Start_IT(&htim7); //启动定时器,开始计时
}
else //下降沿中断
{
ECHO_IRQ_FLAG = 0;
HAL_TIM_Base_Stop_IT(&htim7); //关闭定时器,计时完毕
time = (time_cnt*1000 + TIM7->CNT) /2 ; //统计声音单次传播的时间
Distence = 34000 * time /1000000; //计算距离
//过滤掉可能出现0这种错误情况
if(Distence == 0) Distence = last_distence;
else last_distence = Distence;
}
}
}
contrl.c代码:
#include "math.h"
#include "stdlib.h"
#include "stm32f4xx_hal.h"
#include "contrl.h"
int Dead_Zone=1200; //电机死区
int control_turn=64; //转向控制
//PID调节参数
struct pid_arg PID = {
.Balance_Kp= 200,
.Balance_Kd=1,
.Velocity_Kp= -56,
.Velocity_Ki= -0.28,
.Turn_Kp = 18,
.Turn_Kd = 0.18,
};
/**************************************************************************************************************
*函数名:Read_Encoder()
*功能:读取编码器值(当作小车当前前进的速度)
*形参:(u8 TIMX):x为编码器1或者2
*返回值:无
*************************************************************************************************************/
int Read_Encoder(u8 TIMX)
{
int Encoder_TIM;
switch(TIMX)
{
case 1: Encoder_TIM= (short)TIM1 -> CNT; TIM1 -> CNT=0;break;
case 2: Encoder_TIM= (short)TIM2 -> CNT; TIM2 -> CNT=0;break;
default: Encoder_TIM=0;
}
return Encoder_TIM;
}
/**************************************************************************************************************
*函数名:Vertical_Ring_PD()
*功能:直立环PD控制
*形参:(float Angle):x轴的角度/(float Gyro):x轴的角速度
*返回值:经过PID转换之后的PWM值
**************************************************************************************************************/
//直立环的PD
int Vertical_Ring_PD(float Angle,float Gyro)
{
float Bias;
int balance;
Bias=Angle-Mechanical_balance;
balance=PID.Balance_Kp*Bias+ Gyro*PID.Balance_Kd;
return balance;
//printf("balance = %f\n",balance);
}
/**************************************************************************************************************
*函数名:Vertical_speed_PI()
*功能;速度环PI控制
*形参:(int encoder_left):左轮编码器值/(int encoder_right):编码器右轮的值/(float Angle):x轴角度值
*返回值:
**************************************************************************************************************/
int Vertical_speed_PI(int encoder_left,int encoder_right,float Angle,float Movement )
{
static float Velocity,Encoder_Least,Encoder;
static float Encoder_Integral;
Encoder_Least =(encoder_left+encoder_right)-0; //获取最新速度偏差=测量速度(左右编码器之和)-目标速度(此处为零)
Encoder *= 0.8f; //一阶低通滤波器 ,上次的速度占85%
Encoder += Encoder_Least*0.2f; //一阶低通滤波器, 本次的速度占15%
Encoder_Integral +=Encoder; //积分出位移 积分时间:10ms
Encoder_Integral=Encoder_Integral-Movement;
if(Encoder_Integral>10000) Encoder_Integral=10000; //积分限幅
if(Encoder_Integral<-10000) Encoder_Integral=-10000; //积分限幅
Velocity=Encoder*PID.Velocity_Kp+Encoder_Integral*PID.Velocity_Ki; //速度控制
if(Turn_off(Angle)==1) Encoder_Integral=0; //电机关闭后清除积分
return Velocity;
}
/**************************************************************************************************************
*函数名:Vertical_turn_PD()
*功能:转向环PD
*形参:无 CCD小于64左转、CCD大于64右转。 yaw = z轴陀螺仪数值
*返回值:无
***************************************************************************************************************/
int Vertical_turn_PD(u8 CCD,short yaw)
{
float Turn;
float Bias;
Bias=CCD-64;
Turn=-Bias*PID.Turn_Kp-yaw*PID.Turn_Kd;
return Turn;
}
/**************************************************************************************************************
*函数名:PWM_Limiting()
*功能:PWM限幅函数
*形参:无
*返回值:无
***************************************************************************************************************/
void PWM_Limiting(int *motor1,int *motor2)
{
int Amplitude=5800;
if(*motor1<-Amplitude) *motor1=-Amplitude;
if(*motor1>Amplitude) *motor1=Amplitude;
if(*motor2<-Amplitude) *motor2=-Amplitude;
if(*motor2>Amplitude) *motor2=Amplitude;
}
/**************************************************************************************************************
*函数名:Turn_off()
*功能:关闭电机
*形参:(const float Angle):x轴角度值
*返回值:1:小车当前处于停止状态/0:小车当前处于正常状态
***************************************************************************************************************/
u8 FS_state;
u8 Turn_off(const float Angle)
{
u8 temp;
if(fabs(Angle)>80){
FS_state=1;
temp=1;
AIN2(0), AIN1(0);
BIN1(0), BIN2(0);
}
else
temp=0;
FS_state=0;
return temp;
}
/**************************************************************************************************************
*函数名:Set_PWM()
*功能:输出PWM控制电机
*形参;(int motor1):电机1对应的PWM值/(int motor2):电机2对应的PWM值
*返回值:无
*************************************************************************************************************/
void Set_PWM(int motor1,int motor2)
{
if(motor1>0) AIN2(1), AIN1(0);
else AIN2(0), AIN1(1);
PWMA=Dead_Zone+(abs(motor1))*1.17;
if(motor2>0) BIN1(1), BIN2(0);
else BIN1(0), BIN2(1);
PWMB=Dead_Zone+(abs(motor2))*1.17;
// printf("PWMA = %d\n",PWMA);
// printf("PWMB = %d\n",PWMB);
}