中国网站建设网页设计,小工程承包,管家婆免费资料网站,厦门网站建设企业本节介绍的是一个举升电机#xff0c;顾名思义#xff0c;通过转轴控制物体升降#xff0c;为双通道磁性译码器#xff0c;利用电调进行操控#xff0c;具体驱动类似于大学期间最大众的SG180舵机#xff0c;在一定的频率下#xff0c;通过调制脉宽进行控制。
设备介绍…本节介绍的是一个举升电机顾名思义通过转轴控制物体升降为双通道磁性译码器利用电调进行操控具体驱动类似于大学期间最大众的SG180°舵机在一定的频率下通过调制脉宽进行控制。
设备介绍 具体实控 例如在50Hz情况下即周期为20ms ①驱动信号区间 区间一(0.5ms-1.5ms )和区间二(1.5ms-2.5ms ) 注意都是开区间且存在死区 ②其中区间一和区间二分别表示不同的方向运动例区间一表示正方向则区间二表示反方向。 ③旋转速度呈现为“ V ” 字形即0.5ms和2.5ms分别表示为正反方向的最快速度1.5ms左右分别表示正反方向的最慢速度。其中小于等于0.5ms时、1.5ms时和大于等于2.5ms时电机都保持停转状态。 电调引线 再看电调引线可注意 分别有7根线如上图其中粗线有四根红黑两根线为电源线这里接24V还有两根黄蓝接电机控制电机不同转向细线有三根分别是红黑白其中红黑为电源线输出5V可选择是否需要给MCU供电黑线接地白色线为PWM信号输入线接收MCU发过来的信号进而控制电机转动。 电机引线 如上图电机有6根线跟大众使用的编码器电机无差别两根电机引线两根编码器电源线AB相 PID 由于前几节中已介绍pwm的基本使用这里就不再介绍下面我直接介绍我的PID设计 ①首先在主函数中对PID进行初始化即设置目标数、比例积分微分常数、输出限幅、积分限幅。 ②在定时器中断中对旋转产生的脉冲进行采样然后进行PID运算将输出信号传入电调。 ③在P、I、D参数调节中我习惯先调I将P和D置0从小–大调观察电机变化这里我使用的是一个上位机软件VOFA串口协议通过上传指定数据可以很好的观察波形变化可发现 它呈现出一个缓慢上升的波形这时可以对I进行放大加快上升速度我的调节是调至I能很好的达到目标点且在第一次达到目标点时可以让它超出适量值再对比左右部分数值发现这个点的I值达到目标点的速度更快则这个点就是我要的I值。然后再对P进行调节也可以选择从小–大调P可以很好的反馈出控制器对电机的控制速度即加大对目标值的反应具体调节方法同I。最后在对D进行调节对于一般的控制PI两个参数足以满足需求如果最后完美可再选择DD表现为误差变化率的变化可以抑制电机的超调等对于D你可以用某物体人为的阻挡电机转动观察电机变化例如你提供足够大的阻力电机肯定会直接拉满这时观察电机再次回到目标点的时间。
软件设计
1. 设备初始化
/************************** Uart ************************************/
void Uart_Init(void)
{char str[] hello RT-Thread!\r\n;/* step1查找串口设备 */serial rt_device_find(SAMPLE_UART_NAME);/* step2修改串口配置参数 */config.baud_rate BAUD_RATE_115200; //修改波特率为 115200config.data_bits DATA_BITS_8; //数据位 8config.stop_bits STOP_BITS_1; //停止位 1config.bufsz 128; //修改缓冲区 buff size 为 128config.parity PARITY_NONE; //无奇偶校验位/* step3控制串口设备。通过控制接口传入命令控制字与控制参数 */rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, config);/* step4打开串口设备。以中断接收及轮询发送模式打开串口设备 */rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
}/************************** Timer ************************************/
void Timer_Init(void)
{rt_hwtimer_mode_t mode; /* 定时器模式 */rt_hwtimerval_t timeout_s; /* 定时器超时值 */rt_uint32_t freq 1000000; /* 计数频率 */// 使用前必须先手动打开时钟__HAL_RCC_TIM3_CLK_ENABLE();/* 查找定时器设备 */hw_dev rt_device_find(HWTIMER_DEV_NAME);if (hw_dev RT_NULL){rt_kprintf(hwtimer sample run failed! cant find %s device!\n, HWTIMER_DEV_NAME);}/* 以读写方式打开设备 */rt_err_t ret rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);if (ret ! RT_EOK){rt_kprintf(open %s device failed!\n, HWTIMER_DEV_NAME);}/* 设置超时回调函数 */rt_device_set_rx_indicate(hw_dev, Timer3_Out);/* 设置计数频率(若未设置该项默认为1Mhz 或 支持的最小计数频率) */rt_device_control(hw_dev, HWTIMER_CTRL_FREQ_SET, freq);/* 设置模式为周期性定时器若未设置默认是HWTIMER_MODE_ONESHOT*/mode HWTIMER_MODE_PERIOD;ret rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, mode);if (ret ! RT_EOK){rt_kprintf(set mode failed! ret is :%d\n, ret);}/* 设置定时器超时值为2s并启动定时器 */timeout_s.sec 0; /* 秒 */timeout_s.usec 40000; /* 微秒 */if (rt_device_write(hw_dev, 0, timeout_s, sizeof(timeout_s)) ! sizeof(timeout_s)){rt_kprintf(set timeout value failed\n);}
}/************************** PWM ************************************/
void PWM_Init(void)
{/* 查找设备 */pwm_dev (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME);if (pwm_dev RT_NULL){rt_kprintf(pwm sample run failed! cant find %s device!\n, PWM_DEV_NAME);}/* 使能设备 */rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL1);/* 设置PWM周期和脉冲宽度 */rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL1, period, pulse);
}/************************** Encoder ************************************/
void Encoder_Init(void)
{/* 查找脉冲编码器设备 */pulse_encoder_dev rt_device_find(PULSE_ENCODER_DEV_NAME);if (pulse_encoder_dev RT_NULL){rt_kprintf(pulse encoder sample run failed! cant find %s device!\n, PULSE_ENCODER_DEV_NAME);}/* 以只读方式打开设备 */rt_err_t ret rt_device_open(pulse_encoder_dev, RT_DEVICE_OFLAG_RDONLY);if (ret ! RT_EOK){rt_kprintf(open %s device failed!\n, PULSE_ENCODER_DEV_NAME);}
}2. 以下为位置式PID计算可供参考
PID_VAR_TYPE Position_PID_Cal(PID * s_PID,PID_VAR_TYPE now_point)
{s_PID-LastResult s_PID-Result; // 简单赋值运算//误差计算s_PID-Error s_PID-SetPoint - now_point;s_PID-SumError s_PID-Error; //积分误差累加//积分限幅PID_VAR_TYPE IOutValue s_PID-SumError * s_PID-Integral;if(IOutValue s_PID-IntegralMax)IOutValue s_PID-IntegralMax;else if(IOutValue s_PID-IntegralMin)IOutValue s_PID-IntegralMin;//PID计算s_PID-Result s_PID-Proportion * s_PID-Error // 比例项 IOutValue // 积分项 s_PID-Derivative * (s_PID-Error - s_PID-LastError); // 微分项s_PID-PrevError s_PID-LastError; // 简单赋值运算s_PID-LastError s_PID-Error; // 简单赋值运算//输出限幅if(s_PID-Result s_PID-OutMax)s_PID-Result s_PID-OutMax;else if(s_PID-Result s_PID-OutMin)s_PID-Result s_PID-OutMin;return s_PID-Result;
}3. VOFA 正如上面所介绍的一个上位机软件可观察PID波形变化协助开发具体协议如下所示
void SendDatatoVoFA(rt_uint8_t byte[],float v_real)
{rt_uint8_t t_test0;//四位发送rt_uint8_t send_date[4]{0};//发送数据Float_to_Byte(v_real,byte); //类型转换for(t_test0;t_test4;t_test){rt_device_write(serial, 0, byte[t_test], 1);}send_date[0]0X00;send_date[1]0X00;send_date[2]0X80;send_date[3]0X7f;for(t_test0;t_test4;t_test){rt_device_write(serial, 0, send_date[t_test], 1);}
}4. 在定时器中断不断进行PID计算并输出PWM信号
static rt_err_t Timer3_Out(rt_device_t dev, rt_size_t size)
{ rt_device_read(pulse_encoder_dev, 0, count, 1); /* 读取脉冲编码器计数值 */rt_int32_t outPosition_PID_Cal(pid1,count);rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL1, period, out);rt_kprintf(%d - %d\n,count,out);SendDatatoVoFA(byte,count); //发送到vofa上位机查看波形rt_device_control(pulse_encoder_dev, PULSE_ENCODER_CMD_CLEAR_COUNT, RT_NULL);/* 清空脉冲编码器计数值 */return 0;
}