旋转倒立摆stm32HAL库(pid算法,单通道adc,直流减速电机带编码器,文末有工程代码)

1.硬件部分

先给大家看看硬件部分:先是一个直流减速电机,一定要买带编码器的直流减速电机,然后是角位移传感器,就是图中黄色的,来识别摆杆的角位移,然后一个l298n,tb6612也行,两者相差不大。板子随意,没特别要求,大体的结构如下图(我主要负责软件,硬件大家可以去了解一下其他大佬的)

2.软件部分

我们需要采取两个环才能更好的控制倒立摆,一个是角位移传感器提供的角度环,一个是编码器的位置环。即要使用连个pid,假如只用角度环,那摆杆将左右摇摆,并且当偏转角较大时会一直向一个方向偏,从而无法保持平衡,也就是当偏转恨小的时候,我们不需要过大的pid控制,可以使用位置环,即两个不同的pid。

1.adc采集角位移数据:

先配置adc,因为只有一个脚,所以我们只需要开启单通道采集就行 

我使用了一个定时器中断:间隔是5ms这里和大家说一下psc和rcc的配置关系:

计算赫兹:72*10^6除以(psc+1)(arr+1)=hz  时间分之一就是赫兹‘ 

在这里我还对采集到的adc值做了归一化处理,最大限度的避免了误差的出现。 

HAL_ADCEx_Calibration_Start(&hadc1);   //校准adc

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if (htim->Instance == TIM1) 
	{
		count++;
		HAL_ADC_Start_DMA(&hadc1, (uint32_t *)(adc_data), 6); // 开始ADC采样
		if (adc_ready_flag)
		{
				adc_ready_flag = 0; // 复位标志位

				// 处理ADC数据
				max = adc_data[0];
				min = adc_data[0];
				sum = 0;
				for (int i = 0; i < 6; i++)
				{
						if (adc_data[i] > max) max = adc_data[i];
						if (adc_data[i] < min) min = adc_data[i];
						sum += adc_data[i];
				}
				average = (sum - min - max) / 4;
				data = (int)(100 * ((average - min) / (max - min + 1)));
		}
    Encoder = Read_Encoder();
		MotorControl();
	}

}		

2.直流减速电机的驱动

将定时器设置为编码器模式,因为减速电机有ab连个通道,通过两个口波形的不同可以判断其速度,这就是控制倒立摆的速度环。不了解的小伙伴可以去看看原理讲解http://t.csdnimg.cn/zzHwC

我将左右和控制pwm波的函数封装到一起,方便后面使用 

void left(int motor_speed)
{
  HAL_GPIO_WritePin(in1_GPIO_Port, in1_Pin, GPIO_PIN_RESET);
  HAL_GPIO_WritePin(in2_GPIO_Port, in2_Pin, GPIO_PIN_SET);
  __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, motor_speed);
}
void right(int motor_speed)
{
  HAL_GPIO_WritePin(in1_GPIO_Port, in1_Pin, GPIO_PIN_SET);
  HAL_GPIO_WritePin(in2_GPIO_Port, in2_Pin, GPIO_PIN_RESET);
	__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, motor_speed);
}

3.采集编码器值 

 采集后记得附零,以免被覆盖

HAL_TIM_Encoder_Start(&htim2,TIM_CHANNEL_ALL);//编码器
uint16_t getEncoder(void)
{
	 uint16_t Encoder_num = __HAL_TIM_GET_COUNTER (&htim2);
	 __HAL_TIM_SET_COUNTER(&htim2, 0);
	return Encoder_num;
}

现在我们两个值都采集到了,可以进行pid运算,使其保持平衡。(我这里展示的是手动起摆)只做了两天,时间太短了,零件都是之前小车上的,哭

4.控制摆杆(两环pid)

先是电机的控制代码(这里我对其作了一个限幅,以免速度过大,如果速度太小电机转不起来,可能是我参数每调好,所以我加了一个最小速度)

void control_motor(int motor_speed)
{
    int max_motor_speed = 3000; 
	  int min_motor_speed = 500;  // 设置一个最小速度阈值
    if (motor_speed > max_motor_speed)
    {
        motor_speed = max_motor_speed;
    }
    else if (motor_speed < -max_motor_speed)
    {
        motor_speed = -max_motor_speed;
    }
		else if (motor_speed > 0 && motor_speed < min_motor_speed)
        motor_speed = min_motor_speed;
    else if (motor_speed < 0 && motor_speed > -min_motor_speed)
        motor_speed = -min_motor_speed;
    
    if (motor_speed > 0)
    {
			left(motor_speed);
    }
    else if (motor_speed < 0)
    {
			right(-motor_speed);	
    }
}

代码中的2170是摆杆在平衡位置时测出来的量,大家可以根据自己的去测量,注意我们要调整角位移传感器突变的地方为下面。 

void function3(void)
{
	  int position_pwm, balance_pwm;
	  int encoder_value = Encoder;
    float current_angle = average;
//	  float target_angle = 1980; // 目标角度
    int stability_threshold = 300;
    
    if (abs(average - 2170) <= stability_threshold)
    {
				if(++Position_Target>4)  position_pwm = Position(encoder_value);Position_Target=0;   


        balance_pwm = PID(current_angle,2170);
			
        int motor_speed = balance_pwm-position_pwm ;
			  control_motor(motor_speed);
    }
    else
    {
        control_motor(0);
    }
}

下面是两个 pid,大家可以参考一下

int Position(int Encoder)
{  
	  int  Position_Zero = Encoder;//记得测量最初位置
	  float Position_KP=25,Position_KD=600;
    static float Position_PWM, Position_Bias, Position_Differential;
    static float Last_Position = 0.0; 

    float Position_Least = Encoder - Position_Zero;

    Position_Bias *= 0.8;
    Position_Bias += Position_Least * 0.2;

    Position_Differential = Position_Bias - Last_Position;
    Last_Position = Position_Bias;

    Position_PWM = Position_Bias * Position_KP + Position_Differential * Position_KD;

    return Position_PWM;
}

float PID(float average, float target_angle)
{
	
 	int result;
	float kp = 6000, ki = 500, kd = 1600;
	

	
	float err = 0, sum_err=0;
	static float last_err = 0;
	
	sum_err+=err;
	err = average - target_angle;
	if (sum_err > 1000) sum_err = 1000;  // 防止积分饱和
  if (sum_err < -1000) sum_err = -1000;
	result = (int) (kp * err + ki * sum_err - kd * (err - last_err));
	last_err = err;
	
	return result;
}

 

以上就是手动起摆的全部内容,其实还是很简单的。

后面的我没时间写了,我还写了一个模式,分别是 

 

先是我是用按键来区别不同的模式

void MotorControl(void) 
{
	switch (num) 
	{
	case 1:
       function1();
		break;
	case 2:left(0);right(0);
	  
		break;
	case 3:		function2();

		break;
	case 4:left(0);right(0);
		
		break;
	case 5:		function3();
		break;
	case 6:
		break;
	
	  default:
		break;
	}
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) 
{
    if(GPIO_Pin == GPIO_PIN_0) 
			{
				HAL_Delay(20);
        if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET)
				{ 
            num++;
        }
    } 
    if(GPIO_Pin == GPIO_PIN_1) 
			{
				HAL_Delay(10);
        if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET) 
				{ 
            num--;
        }
    }
}

然后在上面的中断void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)中,我自加了一个数count,因为定时器中断的时间是5ms,这时候如果我count小于20执行左转那么就相当于延时100ms,这里不能使用延时,因为延时时他不会执行任何程序,所以你使用延时,那么它将不会动 

再次注意,你的速度不能超过你配的rcc。

void function2(void) 
{
    if (count <= 80)         left(4400); 
	  //if(count>80|count<85){left(0); right(0);}

    if (count > 85)          right(4400);
    //if(count>85|count<170){left(0); right(0);}
    if(count > 170)          count = 0;
}

 

void function1(void) 
{
    if (count <= 70)           right(4400);
	//  if(count>80|count<85){left(0); right(0);}

    if (count > 75)            left(4400); 
  //  if(count>85|count<170){left(0); right(0);}
    if(count > 145)          count = 0;
}

 

我把整个文件放在百度网盘了,需要的可以自取,记得点个关注哦。

链接:https://pan.baidu.com/s/1JmoHoLRxgOekDg1x9P-JuQ 
提取码:1234

  • 19
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 倒立摆是一种在控制工程领域中常见的实验系统,它用于研究控制算法和控制器的设计与实现。在Matlab中,我们可以使用Simulink工具箱来模拟倒立摆系统。 首先,我们需要建立倒立摆的模型。倒立摆模型一般由两个旋转运动的质点组成,上部质点代表杆的质量,下部质点代表摆球的质量。这两个质点之间通过一个旋转关节相连。我们可以根据倒立摆的物理特性,使用动力学方程来描述其运动。 在Simulink中,可以使用Stateflow来定义摆的状态和控制策略。我们可以根据倒立摆的动力学方程,设计一个控制器来保持倒立摆的平衡。常见的控制算法包括PID控制器、模糊控制器和模型预测控制器等。 一旦模型和控制器设计完成,我们可以在Simulink中进行仿真实验。通过输入给定的外部扰动,观察倒立摆的响应和控制器的稳定性。可以通过调整控制器的参数,使摆能够迅速恢复平衡。 此外,通过使用CSDN作为一个技术社区平台,我们可以分享倒立摆模型和控制器的代码实现,以及问题求助和讨论。在CSDN上有很多在控制工程领域中有经验的工程师和学者,他们可以提供帮助和指导,加速我们的学习和研究进程。 总之,倒立摆的建模和控制在Matlab和CSDN上都有广泛的应用。通过Simulink工具箱和CSDN平台,我们可以学习和交流倒立摆的相关知识,促进我们在控制工程领域的研究和应用。 ### 回答2: 倒立摆是一个经典的控制系统案例,可以通过使用MATLAB进行模拟和分析。在MATLAB中,我们可以使用Simulink工具箱来建立倒立摆的数学模型,并设计相应的控制算法。 首先,我们可以根据倒立摆的动力学方程来建立数学模型。这个方程可以描述摆杆在重力的作用下的运动。然后,我们可以使用Simulink中的Stateflow来实现状态机,用于处理不同运动状态下的控制逻辑。 接着,我们可以设计合适的控制算法来让倒立摆保持平衡。常见的控制算法包括PID控制器、滑模控制器等。我们可以使用MATLAB中的控制系统工具箱来进行控制算法设计和调试。 在进行仿真之前,我们需要定义倒立摆系统的初始条件和仿真参数。这些参数可以包括摆杆长度、质量、初始位置等。 然后,我们可以在Simulink中建立倒立摆的模型,并通过设置不同的输入信号来模拟不同情况下的倒立摆运动。在仿真过程中,我们可以监测摆杆的倾斜角度和位置,以评估控制算法的效果。 最后,我们可以通过MATLAB和CSDN等渠道分享我们的倒立摆模型和仿真结果。这样可以与其他研究者交流,提出改进意见,共同促进倒立摆控制算法的发展。 总之,通过倒立摆的MATLAB仿真与CSDN等平台的分享,我们可以学习掌握倒立摆的控制原理和设计方法,并能够在实际应用中应对不同的控制任务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值