对步科增量式举升电机进行加减速梯形控制

背景:自己移植代码后,可以实现举升控制,但速度是恒定的,查找bug的思路
解决:1、自己单位换算有问题;2、手动和举升任务出现干扰
应用工具:1、CAN分析仪过滤数据;2、步科上位机机监控速度变化;
1)机械参数参数:
举升电机SMC80S-0075-30ABK-3DKH
减速比10
导程10
最大有效形成686(实际测量600)
2)公式
电机转速转丝杠行程速度 rpm ——> mm/s

rotate * motor_param.lead_screw / (motor_param.reduction_ratio * motor_param.teeth_ratio * 60.0f)

丝杠行程速度转电机转速 mm/s ——> rpm

speed * (motor_param.reduction_ratio * motor_param.teeth_ratio * 60.0f) / motor_param.lead_screw

下面正向逆向运算(公式中的齿数比为1)
在这里插入图片描述
二、具体程序中实现
2.1需要电机实时高度数据,步科增量式电机:编码器精度是10000,那速度就是2730=1rpm
此时的实时高度由拉线编码器获取,拉线获取值为mm;

在这里插入图片描述
梯形速度控制
在这里插入图片描述
在这里插入图片描述
具体速度输出
在这里插入图片描述
在这里插入图片描述
三、遇到问题时如何排查
3.1查询速度单位不统一
打断点实时监控自己下发的速度,与实际电机(步科上位机获取的速度)做对比->自己下发速度特别小0.05->查询上方计算加减速部分;
发现是在自己限制幅度内,说明自己计算的速度值有问题,仔细查看单位弄错了;
3.2速度正常下发后,立即减速,应该是缓慢减速的,而且还有异响
初步判断:有0和减速度来回切换导致的;数据依据:通过CAN卡抓取数据,分析得出减速时203帧ID筛选出来的,一帧0一帧其他速度;
自己速度下发,由最根本往上查找,发现手动也调用该速度下发函数了,问题得以解决;
四、具体代码

void LoadingUnload_Task(void const * argument)
{
	uint32_t PreviousWakeTime;
	uint64_t current_time_ms = 0;

//	int32_t current_pose=0;
//	float current_speed=0;
	platform_command.platform_Lift_CMD = STOP;


	PreviousWakeTime = osKernelSysTick();
	while(1)
	{
		osDelayUntil(&PreviousWakeTime,10);
		xEventGroupSetBits(EventGroupHandler_WWDG,EVENTBIT_AXIS_TASK);

		if(OperatingStatus == EMY_STOP)
		{

		}
		else
		{
			/*计算平台当前高度和当前角度*/
			Axis_Motor_Feedback();
			if( fabs(encoder1_length-platform_par.platform_max_height) < 0.004f) //拉线编码器读取数值在举升丝杆最大行程附近
			{
				platform_status.platform_height_flag = TOP;
			}
			else if(fabs(encoder1_length) < 0.004f)  //平台位于最低位 && Platform_Down_Limit
			{
				platform_status.platform_height_flag = LOWEST;
			}
			else  //平台位于中间位置
			{

			}
			/***************************各料轴货物计数*****************************************/



			Photoelectric_State_Updata();  //获取料轴光电信号;
			/***************************取放货处理*****************************************/
			if(auto_mannual_switch == (GPIO_PinState)MANUAL_MODE) //手动模式
			{
				if(Mannual_load_up == 0) //升叉
				{
					TrapezoidalVelocity_Control(PlatformUpDownMotor,platform_par.platform_max_height,&platform_command.platform_LiftSpeed_set,0.01f);
				}
				else if(Mannual_load_down == 0)//降叉
				{
					TrapezoidalVelocity_Control(PlatformUpDownMotor,0.0f,&platform_command.platform_LiftSpeed_set,0.01f);
				}
				else
				{
					ActionStop_f(&platform_command.platform_LiftSpeed_set,0.5f);
				}
			}
			else
			{
//				Agv_MotorSpeed_Set(PlatformUpDownMotor,0.0f);
			}
			Agv_MotorSpeed_Set(PlatformUpDownMotor,-platform_command.platform_LiftSpeed_set * 60.0f / platform_par.platform_lift_screwLead * platform_par.platform_lift_reduction_ratio);
		}
			/***************************传感器状态上报*****************************************/
		if(current_time_ms % 10 == 0)
			Sensors_statues_response();
		current_time_ms ++;
	}
}

//上装平台相关参数定义
const Platform_ParaStruct platform_par = {
	.platform_lift_encoderZero = 0,
	.platform_spin_encoderZero = 0,
	.platform_max_height = 600.0f,                //mm丝杆行程 0.63
	.platform_max_encoder = 2730.0f,//8222500/526,//65536/360*270,//8222500
	.platform_max_speed = 10000.0f,
	.platform_rotate_maxencoding = 59964.2f,  //65536.0f*64.0f*188.0f/25.0f/526.0f,
	.platform_rotate_gear_ratio = 188.0f / 25.0f,
	.platform_rotate_reduction_ratio = 64,
	.platform_lift_reduction_ratio = 10.0f,       //减速比
	.platform_lift_screwLead = 10.0f              //丝杠导程
};
Platform_CommandStruct platform_command;
Platform_StatusStruct  platform_status;
/*******************************************************************************
* 函数名 : uint8_t TrapezoidalVelocity_Control(uint8_t MotorNum,float targetValue,float *speed,float period)
* 描  述 : 梯形速度控制
* 输  入 : MotorNum:需要控制的轴
*		targetValue:目标值
*		*speed:速度
*		period:周期
* 输  出 : *speed:计算后的速度
* 返回值 : 无
*******************************************************************************/
float distance_Remaining1=0;
uint8_t TrapezoidalVelocity_Control(uint8_t MotorNum,float targetValue,float *speed,float period)
{
	//加速度调整值   刹车距离   刹车距离+1个周期距离   加速距离
	float acc_Adjust,distance_Braking,distance_v_Brake,distance_acc_Brake;
	float dec_DrivMotor,acc_DrivMotor,reci_acc_DrivMotor,distance_Remaining,deadBand,V_MAX;
	uint8_t movingDireciton;
	switch(MotorNum)
	{
		//平台升降电机速度控制
		case PlatformUpDownMotor:
			targetValue =MaxMinLimit(targetValue,0.0,platform_par.platform_max_height);
//			distance_Remaining = (targetValue - platform_status.platform_current_height) * 1000.0f;     //绝对值电机获取高度 单位:mm
			distance_Remaining = targetValue - lift_CurrentDistance;                        //拉线编码器获取高度 单位:mm
			distance_Remaining1 = distance_Remaining;
			V_MAX = (2500.0f * platform_par.platform_lift_screwLead / (platform_par.platform_lift_reduction_ratio * 60.0f));
			acc_DrivMotor = (V_MAX * period);//mm/ti
			dec_DrivMotor = acc_DrivMotor*1.5;//mm/Ti
			reci_acc_DrivMotor = 0.01f / dec_DrivMotor;
			deadBand = 1.0f;
			break;

		//平台自旋电机速度控制
		case PlatformRotateMotor:
			if(targetValue > Pi || targetValue < -Pi)
			{
				*speed = 0;
				return 0;
			}
			distance_Remaining = -(targetValue - platform_status.platform_current_angle);	//单位:rad 旋转平台
			AngleRangePI_PI(distance_Remaining);
			acc_DrivMotor = 0.003f;
			dec_DrivMotor = 0.001f;
			V_MAX = 0.6f;  //对应电机最大2800rpm
			reci_acc_DrivMotor = 0.01f / acc_DrivMotor;
			deadBand = 0.02f;
			break;

		default:
			return 0;
	}
	if(distance_Remaining > 0)
		movingDireciton = 0;
	else
		movingDireciton = 1;

	distance_Remaining = fabs(distance_Remaining);
	if(distance_Remaining <= deadBand)
	{
		if(movingDireciton == 0)
		{
			*speed -= dec_DrivMotor*2;
			if(*speed <= 0)
			{
				*speed = 0;
				return true;
			}
		}
		else
		{
			*speed += dec_DrivMotor*2;
			if(*speed >= 0)
			{
				*speed = 0;
				return true;
			}
		}
	}
	else
	{
		distance_Braking = 0.5f * (*speed) * (*speed) * reci_acc_DrivMotor;
		distance_v_Brake = distance_Braking + fabs(*speed) * period;
		distance_acc_Brake = distance_v_Brake + 0.5f * acc_DrivMotor * period;

		if(distance_Remaining >= distance_acc_Brake)
		{
			if(movingDireciton == 0)
			{
				*speed += acc_DrivMotor;
				if(*speed > V_MAX)
					*speed = V_MAX;
			}
			else
			{
				*speed -= acc_DrivMotor;
				if(*speed < -V_MAX)
					*speed = -V_MAX;
			}
		}
		else if(distance_Remaining < distance_v_Brake)
		{
			acc_Adjust = acc_DrivMotor * distance_Braking / distance_Remaining;
			if(movingDireciton == 0)
			{
				*speed -= acc_Adjust;
				if(*speed < 0)
					*speed = 0;
			}
			else
			{
				*speed += acc_Adjust;
				if(*speed > 0)
					*speed = 0;
			}
		}
	}
	return 0;
}

/*******************************************************************************
* 函数名 : void ActionStop(float *PresentSpeed,int16_t Dec)
* 描  述 : 停止动作
* 输  入 : *PresentSpeed:当前速度
*					 Dec:减速度
* 输  出 : *PresentSpeed:减速后的速度
* 返回值 : 无
*******************************************************************************/
void ActionStop_f(float *PresentSpeed,float Dec)
{
	if(fabs(*PresentSpeed) <= Dec)
	{
		*PresentSpeed = 0.0f ;
	}
	else if(*PresentSpeed > 0)
	{
		*PresentSpeed -= Dec;
	}
	else if(*PresentSpeed < 0)
	{
		*PresentSpeed += Dec;
	}
}
/*******************************************************************************
* 函数名  :void Axis_Motor_Feedback(void)
* 描述     :获取轴位置及速度反馈信息
* 输入     : 无
* 输出     : 无
* 返回值  : 无
* 说明      : 无
*******************************************************************************/
void Axis_Motor_Feedback(void){
	int32_t current_pose = 0;
	float cur_speed = 0.0f;

	lift_CurrentDistance = encoder1_length ;  //拉线编码器实时获取的高度mm

	Agv_MotorPose_Get(PlatformUpDownMotor,&current_pose);
	lift_motor_curdis = Calculate_ScrewCurrentDistance(current_pose,robot_param.lift_motor);
	lift_motor_curdis *= 15.426f;	          //实际高度对应增量式电机的换算系数(实际测量获取系数)
	Agv_MotorSpeed_Get(PlatformUpDownMotor,&cur_speed);
//	wholelift_speed_feed = MotorSpeed2ScrewSpeed(cur_speed,robot_param.lift_motor);
}

具体速度下发

/**
 *@brief	电机速度设置
 *@param	无
 *@return	无
 */
void Agv_MotorSpeed_Set(Motor_Index motor_index,float speed){
	switch(motor_index){
	case WalkLeftMotor:
		Motor_Speed_Set(_motor_type,SERVO_1_RPDO1, speed);
		break;
	case WalkRightMotor:
		Motor_Speed_Set(_motor_type,SERVO_2_RPDO1, speed);
		break;
	case PlatformUpDownMotor:
		Motor_Speed_Set(_motor_type,SERVO_3_RPDO1, speed);
		break;
	case PlatformRotateMotor:
//		Motor_Speed_Set(_motor_type,SERVO_4_RPDO1, speed / RPM_INNER_CONVERT_KincoINC * 17895.67f);
		break;
	default:
		Sys_PeripheralErrorSet(EP_MotorType,true);
	}
}
/**
 *@brief	电机速度下发
 *@param	无
 *@return	无
 */
void Motor_Speed_Set(uint8_t _motor_type,uint32_t pdo_id,float speed)
{
	uint8_t _send_data[8];
	int32_t speed_value;
	if(speed > 3000)
		speed = 3000;
	else if(speed < -3000)
		speed = -3000;

	switch(_motor_type){
	case Kinco:
		speed_value = speed * RPM_INNER_CONVERT_KincoINC;  //增量式电机
		break;

	case Tongyi:
		if(speed > 2500)
			speed = 2500;
		else if(speed < -2500)
			speed = -2500;
		speed_value = (int32_t)speed * 10.0f;
		break;
	default:
		Sys_PeripheralErrorSet(EP_MotorType,true);
	}
	memcpy(_send_data,&speed_value,8);
	MOTOR_SEND_MSG(pdo_id,8,CAN_RTR_DATA,_send_data);
}

CAN底层发送数据

/* USER CODE BEGIN 1 */
uint8_t can1_send_msg(uint32_t StdId, uint32_t DLC, uint32_t RTR, uint8_t *Data)
{
	static uint8_t led_cnt=0;
	CAN_TxPacketTypeDef packet;
	CAN_TxHeaderTypeDef  CAN_RxHeaderVal;
	uint64_t timout_cnt=0;
	CAN_RxHeaderVal.StdId = StdId;
	CAN_RxHeaderVal.IDE = 0;
	CAN_RxHeaderVal.RTR = RTR;
	CAN_RxHeaderVal.DLC = DLC;
	CAN_RxHeaderVal.TransmitGlobalTime = DISABLE;
	for(uint8_t i=0;i<DLC;i++)
		packet.payload[i] = Data[i];
	while( HAL_CAN_GetTxMailboxesFreeLevel( &hcan1 ) == 0 )
	{
		timout_cnt++;
		if(timout_cnt>MAX_DELAY)return 0;
	}
	if(led_cnt++>100){
		CAN1_TX_LIGHT_TOGGLE;
		led_cnt=0;
	}
//	vTaskDelay(3);
	if(HAL_CAN_AddTxMessage(&hcan1, &CAN_RxHeaderVal, packet.payload, &packet.mailbox) != HAL_OK){
		return 1;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值