如何免费做网站推广,网站备案名称重复,jsp开发网站开发源码,网站上全景云台怎么做的上节有这样一句话#xff1a; 步进电机旋转角度和编码器输出数据之间的关系通常是非线性的。在校准过程中#xff0c;可以通过采集一系列已知角度位置的数据点#xff0c;并拟合出角度与编码器数据之间的关系。这个拟合可以使用曲线拟合算法或其他数学方法来实现。通过拟合 步进电机旋转角度和编码器输出数据之间的关系通常是非线性的。在校准过程中可以通过采集一系列已知角度位置的数据点并拟合出角度与编码器数据之间的关系。这个拟合可以使用曲线拟合算法或其他数学方法来实现。通过拟合可以建立编码器输出数据与实际相位角之间的非线性转换公式从而实现更准确的角度测量。 代码是这样实现的在步进电机旋转的每一步都计算下一步和这一步的传感器读取数值的差如果这个差值和预期不一致则认为发生了阶跃同时把阶跃差值确定。 uint32_t step_num 0; //阶跃次数if(encode_cali.dir){ //电机正转for(count0; count200; count){sub_data (int32_t)encode_cali.coder_data_f[CycleRem(count1, 200)] - (int32_t)encode_cali.coder_data_f[CycleRem(count, 200)];if(sub_data 0){ //这个差值是应该大于0的如果小于0则代表发生了阶跃即转了超过1圈step_num; //阶跃次数加1encode_cali.rcd_x count;//使用区间前标encode_cali.rcd_y (2^14-1) - encode_cali.coder_data_f[CycleRem(encode_cali.rcd_x, 200)]; //阶跃差值}}if(step_num ! 1){encode_cali.error_code CALI_Error_PhaseStep; //如果阶跃次数不为1则报错return;}}else{ //反转也是类似的差值应该小于0如果大于0则代表发生了阶跃for(count0; count200; count){sub_data (int32_t)encode_cali.coder_data_f[CycleRem(count1, 200)] - (int32_t)encode_cali.coder_data_f[CycleRem(count, 200)];if(sub_data 0){step_num;encode_cali.rcd_x count;//使用区间前标encode_cali.rcd_y (2^14-1) - encode_cali.coder_data_f[CycleRem(encode_cali.rcd_x1, 200)]; //这里要注意反转需要把步数1即下一步的差值}}if(step_num ! 1){encode_cali.error_code CALI_Error_PhaseStep;return;}}到这里为止整个编码器的校准过程就完成了。
接下去就是正常使用的过程。
首先要定义一个编码器状态的枚举类型
typedef enum{CALI_Disable 0x00, //不校准CALI_Forward_Encoder_AutoCali, //编码器正转自动校准CALI_Forward_Measure, //正向测量CALI_Reverse_Ret, //反向回退CALI_Reverse_Gap, //反向消差CALI_Reverse_Measure, //反向测量CALI_Operation, //解算
}CALI_State;会把它分为中断过程的回调使用和正常回调两个函数来执行。
首先是中断回调一般是用户在正常工作时想要进行校准时的操作。来看下代码
switch(encode_cali.state) //看现时的编码器状态{case CALI_Disable:if(encode_cali.trigger) //如果用户开启了校准请求初始化也会使trigger置1{REIN_HW_Elec_SetDivideElec(encode_cali.out_location, Current_Cali_Current); //这一句是和FOC算法相关的后面再学习encode_cali.out_location Move_Pulse_NUM; //步进电机转一圈这个宏定义的值是单圈脉冲数200*256256是单步细分数encode_cali.gather_count 0; //采集清零encode_cali.state CALI_Forward_Encoder_AutoCali; //---编码器正转自动校准encode_cali.error_code CALI_No_Error; //初始化encode_cali.error_data 0;}break;//编码器正转自动校准case CALI_Forward_Encoder_AutoCali:encode_cali.out_location 2; //每次走2个脉冲一直走到第二圈REIN_HW_Elec_SetDivideElec(encode_cali.out_location, Current_Cali_Current);if(encode_cali.out_location 2 * Move_Pulse_NUM){encode_cali.out_location Move_Pulse_NUM; //重置到一圈encode_cali.state CALI_Forward_Measure; //走到第二圈后到下一个状态正向测量}break;//正向测量case CALI_Forward_Measure:if((encode_cali.out_location % Move_Divide_NUM) 0)//每到达采集细分量点采集一次数据{//开始采集传感器的角度数据encode_cali.coder_data_gather[encode_cali.gather_count] mt6816.angle_data;if(encode_cali.gather_count Gather_Quantity){//记录数据encode_cali.coder_data_f[(encode_cali.out_location - Move_Pulse_NUM) / Move_Divide_NUM] CycleDataAverage(encode_cali.coder_data_gather, Gather_Quantity, CALI_Encode_Res);//采集计数清零encode_cali.gather_count 0;//移动位置encode_cali.out_location 1; //每次移动1个脉冲}}else{//移动位置encode_cali.out_location 1;} REIN_HW_Elec_SetDivideElec(encode_cali.out_location, Current_Cali_Current);if(encode_cali.out_location (2 * Move_Pulse_NUM)) //如果走的脉冲数超过2圈了进入下一个状态{encode_cali.state CALI_Reverse_Ret;//---反向回退}break;//反向回退case CALI_Reverse_Ret: encode_cali.out_location 1;REIN_HW_Elec_SetDivideElec(encode_cali.out_location, Current_Cali_Current);if(encode_cali.out_location (2 * Move_Pulse_NUM Move_Divide_NUM * 20)) //从第二圈再走20步到下一个状态{encode_cali.state CALI_Reverse_Gap;//---反向消差}break;//反向消差case CALI_Reverse_Gap:encode_cali.out_location - 1; //每次往回退一个脉冲REIN_HW_Elec_SetDivideElec(encode_cali.out_location, Current_Cali_Current);if(encode_cali.out_location (2 * Move_Pulse_NUM)) //退回到第二圈{encode_cali.state CALI_Reverse_Measure;//---反向测量}break;//反向测量和正向测量类似case CALI_Reverse_Measure:if((encode_cali.out_location % Move_Divide_NUM) 0)//每到达采集细分量点采集一次数据{//采集encode_cali.coder_data_gather[encode_cali.gather_count] mt6816.angle_data;if(encode_cali.gather_count Gather_Quantity){//记录数据encode_cali.coder_data_r[(encode_cali.out_location - Move_Pulse_NUM) / Move_Divide_NUM] CycleDataAverage(encode_cali.coder_data_gather, Gather_Quantity, CALI_Encode_Res);//采集计数清零encode_cali.gather_count 0;//移动位置encode_cali.out_location - 1; 回退一个脉冲}}else{//移动位置encode_cali.out_location - 1;} REIN_HW_Elec_SetDivideElec(encode_cali.out_location, Current_Cali_Current);if(encode_cali.out_location Move_Pulse_NUM){encode_cali.state CALI_Operation;//如果退回1圈以内则进入下一个状态}break;//计算case CALI_Operation://进行校准计算中REIN_HW_Elec_SetDivideElec(0, 0);break;default:break;}
}可以看到进中断时的操作是走一个流程把每个状态都走一遍并把采集的数据记录到coder_data_f和coder_data_r两个数组中。 下面看看主循环中的调用函数下面代码中Move_Step_NUM是步进电机总步数200Move_Divide_NUM是每步的细分数256Move_Pulse_NUM是总的脉冲数即256*200
void Calibration_Loop_Callback(void)
{int32_t data_i32; //32位有符号uint16_t data_u16; //16位无符号数//必须要是校准计算状态才进入主循环否则退出if(encode_cali.state ! CALI_Operation)return;//给电机的4线低电平REIN_HW_Elec_SetSleep();//传感器数据检查Calibration_Data_Check();if(encode_cali.error_code CALI_No_Error){int32_t step_x, step_y;encode_cali.result_num 0;Stockpile_Flash_Data_Empty(stockpile_quick_cali); //Flash擦除数据区Stockpile_Flash_Data_Begin(stockpile_quick_cali); //开始写数据区if(encode_cali.dir){ //正转的情况for(step_x encode_cali.rcd_x; step_x encode_cali.rcd_x Move_Step_NUM 1; step_x) //从rcd_x的位置整一圈{ //可以认为rcd_x是步数rcd_y是该步数对应的传感器读数 data_i32 CycleSub( encode_cali.coder_data_f[CycleRem(step_x1, Move_Step_NUM)], encode_cali.coder_data_f[CycleRem(step_x, Move_Step_NUM)], CALI_Encode_Res); //data_i32的值存的是两步之间的传感器的读取数值差值if(step_x encode_cali.rcd_x){//开始边缘for(step_y encode_cali.rcd_y; step_y data_i32; step_y){ data_u16 CycleRem( Move_Divide_NUM * step_x Move_Divide_NUM * step_y / data_i32,Move_Pulse_NUM); //data_u16存值step_x这一步各个脉冲的传感器读取值Stockpile_Flash_Data_Write_Data16(stockpile_quick_cali, data_u16, 1); //分为开始、中间、结尾3个区间获取并存入flashencode_cali.result_num;}}else if(step_x encode_cali.rcd_x Move_Step_NUM){//结束边缘for(step_y 0; step_y encode_cali.rcd_y; step_y){data_u16 CycleRem( Move_Divide_NUM * step_x Move_Divide_NUM * step_y / data_i32,Move_Pulse_NUM);Stockpile_Flash_Data_Write_Data16(stockpile_quick_cali, data_u16, 1);encode_cali.result_num;}}else{//中间for(step_y 0; step_y data_i32; step_y){data_u16 CycleRem( Move_Divide_NUM * step_x Move_Divide_NUM * step_y / data_i32,Move_Pulse_NUM);Stockpile_Flash_Data_Write_Data16(stockpile_quick_cali, data_u16, 1);encode_cali.result_num;}}}}else //以下是反转的情况同样也是把每一步的每个脉冲的传感器数值存入flash{for(step_x encode_cali.rcd_x Move_Step_NUM; step_x encode_cali.rcd_x - 1; step_x--) {data_i32 CycleSub( encode_cali.coder_data_f[CycleRem(step_x, Move_Step_NUM)],encode_cali.coder_data_f[CycleRem(step_x1, Move_Step_NUM)],CALI_Encode_Res);if(step_x encode_cali.rcd_xMove_Step_NUM){//开始边缘for(step_y encode_cali.rcd_y; step_y data_i32; step_y){data_u16 CycleRem( Move_Divide_NUM * (step_x1) - Move_Divide_NUM * step_y / data_i32,Move_Pulse_NUM);Stockpile_Flash_Data_Write_Data16(stockpile_quick_cali, data_u16, 1);encode_cali.result_num;}}else if(step_x encode_cali.rcd_x){//结束边缘for(step_y 0; step_y encode_cali.rcd_y; step_y){data_u16 CycleRem( Move_Divide_NUM * (step_x1) - Move_Divide_NUM * step_y / data_i32,Move_Pulse_NUM);Stockpile_Flash_Data_Write_Data16(stockpile_quick_cali, data_u16, 1);encode_cali.result_num;}}else{//中间for(step_y 0; step_y data_i32; step_y){data_u16 CycleRem( Move_Divide_NUM * (step_x1) - Move_Divide_NUM * step_y / data_i32,Move_Pulse_NUM);Stockpile_Flash_Data_Write_Data16(stockpile_quick_cali, data_u16, 1);encode_cali.result_num;}}}}Stockpile_Flash_Data_End(stockpile_quick_cali); //结束写数据区if(encode_cali.result_num ! CALI_Encode_Res) //result_num应该等于2^14encode_cali.error_code CALI_Error_Analysis_Quantity; //报解析数据错误}//确认校准结果if(encode_cali.error_code CALI_No_Error){mt6816.rectify_valid true; //磁编码器数据确认}else{mt6816.rectify_valid false; //不进行数据的存储Stockpile_Flash_Data_Empty(stockpile_quick_cali); //清除校准区数据}//运动配置覆盖motor_control.stall_flag true; //这是电机相关的可以先不看意思是堵转保护,即校准后禁用运动控制//清理校准信号encode_cali.state CALI_Disable;encode_cali.trigger false; //清除校准触发
}在实际使用时当有外部事件要求例如实体按键或者用户界面按钮会进入中断回调函数。 主loop程序会调用Calibration_Loop_Callback()。
至此为止磁编码器和电机驱动芯片的驱动基本完成了接下去就是最核心的FOC算法实现对步进电机的控制。
未完待续