我是靠谱客的博主 愉快长颈鹿,最近开发中收集的这篇文章主要介绍STM32实现多步进电机的加减速运动控制,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目标:

1、指定简单的电机控制协议,支持通过串口通讯对多步进电机进行运动控制

2、支持详细参数输入的运动控制模式:控制方向、转速、加减速率、细分等

3、支持位置控制模式,按照协议格式,输入电机编号和位置,对多电机进行控制

先展示下最终效果:通过3条指令控制三个电机,在不同的加减速曲线下运行

(这里只展示逻辑分析仪结果,实测和调试效果一致)

 加减速曲线的积分计算matlab仿真(为了研究下步数和加减速的关系)

-------------------------------------------------设计部分---------------------------------------------------

硬件设计:

主控芯片: STM32F1 或 STM32F4 (支持多IO多计时器中断即可,最好能跑freeRTOS)

电机驱动芯片:DRV8825 - 使用PWM+DIR+EN进行电机控制 (占用资源较少)

电机:5-36V输入范围的所有步进电机均可

软件设计:

制定控制协议: 

 

 代码(水平有限供参考):

【串口初始化】

uint8_t aRxBuffer[1];  // HAL库使用的串口接收缓冲
uint8_t USART2_RX_BUF[100];	//接收缓冲,最大100字节
uint16_t USART_RX_STA = 0;       //接收状态标志
//bit15			接收完成标志 0x55
//bit14			接收开始标志 0xAA
//bit13~bit0	接收到的有效字节数目

void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  HAL_UART_Receive_IT(&huart2, (uint8_t *)aRxBuffer, 1);	//该函数会�??启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量

  /* USER CODE END USART2_Init 2 */

}

void USART2_IRQHandler(void)
{
  /* USER CODE BEGIN USART2_IRQn 0 */

  /* USER CODE END USART2_IRQn 0 */
  HAL_UART_IRQHandler(&huart2);
  /* USER CODE BEGIN USART2_IRQn 1 */

  uint32_t timeout=0;
  timeout=0;
  while (HAL_UART_GetState(&huart2) != HAL_UART_STATE_READY)	//等待就绪
  {
	  timeout++;		//超时处理
	  if(timeout>HAL_MAX_DELAY) break;
  }

  timeout=0;
  while(HAL_UART_Receive_IT(&huart2, (uint8_t *)aRxBuffer, 1) != HAL_OK)//�?次处理完成之后,重新�?启中断并设置RxXferCount�?1
  {
	 timeout++; 	//超时处理
	 if(timeout>HAL_MAX_DELAY) break;
  }

  /* USER CODE END USART2_IRQn 1 */
}


void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) //串口2的中断回调函�?
{
	if(huart->Instance==USART2)
	{
		if((USART_RX_STA&0x8000)==0)	//如果USART_RX_STA的bit15=0:接收未完成
		{
			if((USART_RX_STA&0x4000)==0)	//如果没有收到起始标志,USART_RX_STA的bit15�?0
			{
				if(aRxBuffer[0]==0xAA)		//如果收到起始标志
				{
					USART_RX_STA|=0x4000;
					USART2_RX_BUF[USART_RX_STA&0X3FFF]=aRxBuffer[0] ;
					USART_RX_STA++;
					HAL_TIM_Base_Start_IT(&htim7);
				}
				else
				{
					USART_RX_STA=0;
				}
			}
			else if(aRxBuffer[0]==0x55)
			{
				USART_RX_STA|=0x8000;
				USART2_RX_BUF[USART_RX_STA&0X3FFF]=aRxBuffer[0] ;
				USART_RX_STA++;
			}
			else
			{
				USART2_RX_BUF[USART_RX_STA&0X3FFF]=aRxBuffer[0] ;
				USART_RX_STA++;
			}
		}

	}

}

【协议解析】

#define Forward 1
#define Backward 0

struct MotorDefine Motor_Temp ;

void deal_buffer_motorCtrl_data(struct MotorDefine *a)
{

		a->MotorNumber = USART2_RX_BUF[1];

		if ( USART2_RX_BUF[3] == 0b10000000 )  // 0x80
		{
			a->MotorDirection = Forward ;
		}
		else if (USART2_RX_BUF[3] == 0b01000000)	// 0x40
		{
			a->MotorDirection = Backward ;
		}

		a->DesiredSpeedInRads =  (float)USART2_RX_BUF[4] / 10;
		a->NumberofRads = (float)USART2_RX_BUF[5] + (float)USART2_RX_BUF[6] / 100 ;
		a->StartupSpeedInRads = (float)USART2_RX_BUF[7] / 10 ;
		a->accelerationRate = USART2_RX_BUF[8] * 100 ;
		a->decelerationRate = USART2_RX_BUF[9] * 100 ;

		printf("rnInput Information:rn");
		printf("  MotorNumber:%ld  MotorDirection:%ldrn  DesiredSpeedInRads:%.2frn  NumberofRads:%.2frn  StartupSpeedInRads:%.2frn  accelerationRate:%ld /Hzrn  decelerationRate:%ld /Hzrn"
		,a->MotorNumber,a->MotorDirection,a->DesiredSpeedInRads,a->NumberofRads,a->StartupSpeedInRads,a->accelerationRate,a->decelerationRate);

}

void deal_buffer_motorCtrl_position(struct MotorDefine *a)
{
	//等待添加代码

	printf("rnMotor Control - Position Mode  rn");
}



void StartUartCommondTask(void *argument)
{
	uint8_t len = 0;
	osDelay(10);
	printf("Uart Commond Receive Task starts! rnrn");

	for(;;)
	{
		osDelay(1);

	    if(USART_RX_STA&0x8000)
		{
	    	len=USART_RX_STA&0x3fff;

			switch ( USART2_RX_BUF[2] )
			{

			case 0b10000000: 					// 电机控制-位置模式 ,16进制0x80
				deal_buffer_motorCtrl_position(&Motor_Temp);
				USART_RX_STA=0;
			break;


			case 0b01000000:  					// 电机控制-参数模式 ,16进制0x40
				deal_buffer_motorCtrl_data(&Motor_Temp);
				MotorMove_steps(&Motor_Temp);
				USART_RX_STA=0;
			break;


			case 0b00000001: 					// 打印回传接收到的协议数据 , 16进制0x01
				HAL_UART_Transmit(&huart2, USART2_RX_BUF,len,1000);
				while(__HAL_UART_GET_FLAG(&huart2,UART_FLAG_TC)!=SET);
				USART_RX_STA=0;
			break;

			}

		}
	}

}

【加减速计算函数(参考TI建议设计思路)】

uint32_t AccelDecelTimeCompute(uint32_t AccelDecelRate)  //根据输入的加减速率,计算加减速计时器的TMR
{
	uint32_t temp_AccelDecelTimeTMR;
	if(AccelDecelRate > MOTORTIM_TMR)
	{
		printf("[WRONG]AccelDecel Rate Oversize!rn"); //如果加减速超过20000Hz/s,判断过快报错
		return 10000;
	}
	temp_AccelDecelTimeTMR = MOTORTIM_TMR / AccelDecelRate ;  // 计算对应的加减速计时器TMR
	return temp_AccelDecelTimeTMR;
}

void AccelDecel(uint32_t AccelDecelState,struct MotorDefine *a)
{
	switch (AccelDecelState)
	{
	case 0:

	break;

	case 1: // 加速
		a->ActualSpeedInHz ++ ;
		if (a->ActualSpeedInHz >= a->DesiredSpeedInHz)
		{
			a->ActualSpeedInHz = a->DesiredSpeedInHz;
			AccelDecelState = 0;
		}
		a->StepperSpeedTMR = MOTORTIM_TMR / a->ActualSpeedInHz;
	break;

	case 2: // 减速
		a->ActualSpeedInHz -- ;
		if (a->ActualSpeedInHz <= a->StartupSpeedInHz)
		{
			a->ActualSpeedInHz = a->StartupSpeedInHz;
			AccelDecelState = 0;
		}
		a->StepperSpeedTMR = MOTORTIM_TMR / a->ActualSpeedInHz;
	}
}

【电机控制-参数控制模式】

void MotorMove_steps(struct MotorDefine *temp)
{

	if (temp->MotorNumber == 1)
	{
		temp->deceleration_ratio = Motor1.deceleration_ratio ;
		temp->step_angle = Motor1.step_angle ;
		temp->mircro_steps = Motor1.mircro_steps ;
		//temp->StartupSpeedInRads = Motor1.StartupSpeedInRads ;
		temp->MaxSpeedInRads = Motor1.MaxSpeedInRads ;
	}
	else if (temp->MotorNumber == 2)
	{
		temp->deceleration_ratio = Motor2.deceleration_ratio ;
		temp->step_angle = Motor2.step_angle ;
		temp->mircro_steps = Motor2.mircro_steps ;
		//temp->StartupSpeedInRads = Motor2.StartupSpeedInRads ;
		temp->MaxSpeedInRads = Motor2.MaxSpeedInRads ;
	}
	else if (temp->MotorNumber == 3)
	{
		temp->deceleration_ratio = Motor3.deceleration_ratio ;
		temp->step_angle = Motor3.step_angle ;
		temp->mircro_steps = Motor3.mircro_steps ;
		//temp->StartupSpeedInRads = Motor3.StartupSpeedInRads ;
		temp->MaxSpeedInRads = Motor3.MaxSpeedInRads ;
	}

	if(temp->DesiredSpeedInRads > temp->MaxSpeedInRads)  // 判断电机设置速度是否超过最大转速
	{
		printf("[WRONG] Setup Speed faster than max speed:%.2f rad/s !rn",temp->MaxSpeedInRads);
		return ;
	}

	temp->StepsInOneCircle = 360 / temp->step_angle * temp->deceleration_ratio * temp->mircro_steps;
	temp->StartupSpeedInHz = temp->StepsInOneCircle * temp->StartupSpeedInRads ;
	temp->ActualSpeedInHz = temp->StartupSpeedInHz;						// 设定初始实际频率为启动频率
	temp->DesiredSpeedInHz = temp->StepsInOneCircle * temp->DesiredSpeedInRads ;
	temp->StepperSpeedTMR = MOTORTIM_TMR / temp->ActualSpeedInHz;
	temp->NumberofSteps = temp->NumberofRads * temp->StepsInOneCircle ;
	temp->AccelerationTimeTMR = AccelDecelTimeCompute(temp->accelerationRate);
	temp->DecelerationTimeTMR = AccelDecelTimeCompute(temp->decelerationRate);

	//根据电机设定的转速、加速度率、减速度率、运行距离,计算电机的加减速曲线
	uint32_t DesiredNumberofSteptoAccel ;
	uint32_t DesiredNumberofSteptoDecel ;
	float DesiredAccellTimeInSeconds ;
	float DesiredDecellTimeInSeconds ;

	DesiredAccellTimeInSeconds = ((float)temp->DesiredSpeedInHz-temp->StartupSpeedInHz) / temp->accelerationRate;
	DesiredDecellTimeInSeconds = ((float)temp->DesiredSpeedInHz-temp->StartupSpeedInHz) / temp->decelerationRate;
	DesiredNumberofSteptoAccel =  DesiredAccellTimeInSeconds * (temp->DesiredSpeedInHz-temp->StartupSpeedInHz) /2 + temp->StartupSpeedInHz*DesiredAccellTimeInSeconds; //对速度曲线求积分,理论计算完成加速需要的步数
	DesiredNumberofSteptoDecel =  DesiredDecellTimeInSeconds * (temp->DesiredSpeedInHz-temp->StartupSpeedInHz) /2 + temp->StartupSpeedInHz*DesiredDecellTimeInSeconds ; //对速度曲线求积分,理论计算完成减速需要的步数

	if ( (DesiredNumberofSteptoAccel + DesiredNumberofSteptoDecel) <= temp->NumberofSteps ) //如果加减速需要的步数和,小于总步数,则进行完整加减速
	{
		temp->NumberofSteps_StopAccel = temp->NumberofSteps - DesiredNumberofSteptoAccel ;
		temp->NumberofSteps_BeginDecel =  DesiredNumberofSteptoDecel ;
		printf("Complete AccelDecel rn");
	}
	else  // 如果行进距离不能完成完整的加减速曲线,则前1/3加速,后2/3减速
	{
		temp->NumberofSteps_StopAccel = temp->NumberofSteps /3*2 ;
		temp->NumberofSteps_BeginDecel = temp->NumberofSteps /3*2 ;
		printf("Incomplete AccelDecel rn");
	}
	printf("  DesiredNumberofSteptoAccel:%ldrn  DesiredNumberofSteptoDecel:%ld rn",DesiredNumberofSteptoAccel,DesiredNumberofSteptoDecel);

	printf("rnMotor Move Information:rn");
	printf("  MotorNumber:%ldrn  Direction:%ldrn  DesiredSpeedInRads:%.2frn  DesiredSpeedInHz:%ldrn  NumberofRads:%.2frn  NumberofSteps:%ldrn  accelerationRate:%ld Hz/srn  decelerationRate:%ld Hz/srn",
	temp->MotorNumber,temp->MotorDirection,temp->DesiredSpeedInRads,temp->DesiredSpeedInHz,temp->NumberofRads,temp->NumberofSteps,temp->accelerationRate,temp->decelerationRate);
	printf("  DesiredAccellTimeInSeconds:%.2f srn  DesiredDecellTimeInSeconds:%.2f srn",
			DesiredAccellTimeInSeconds,DesiredDecellTimeInSeconds);

	if (temp->MotorNumber == 1)
	{
		Motor1 = *temp ;
		if(Motor1.MotorDirection == 1)
		{
			Motor1_Dir_Forward();
		}
		else
		{
			Motor1_Dir_Backward();
		}
		HAL_TIM_Base_Start_IT(&htim2);
	}
	else if (temp->MotorNumber == 2)
	{
		Motor2 = *temp ;
		if(Motor2.MotorDirection == 1)
		{
			Motor2_Dir_Forward();
		}
		else
		{
			Motor2_Dir_Backward();
		}
		HAL_TIM_Base_Start_IT(&htim3);
	}
	else if (temp->MotorNumber == 3)
	{
		Motor3 = *temp ;
		if(Motor3.MotorDirection == 1)
		{
			Motor3_Dir_Forward();
		}
		else
		{
			Motor3_Dir_Backward();
		}
		HAL_TIM_Base_Start_IT(&htim4);
	}


}

最后

以上就是愉快长颈鹿为你收集整理的STM32实现多步进电机的加减速运动控制的全部内容,希望文章能够帮你解决STM32实现多步进电机的加减速运动控制所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(48)

评论列表共有 0 条评论

立即
投稿
返回
顶部