小程序網(wǎng)站建設(shè)長沙百度百科
本節(jié)介紹的是一個(gè)舉升電機(jī),顧名思義,通過轉(zhuǎn)軸控制物體升降,為雙通道磁性譯碼器,利用電調(diào)進(jìn)行操控,具體驅(qū)動類似于大學(xué)期間最大眾的SG180°舵機(jī),在一定的頻率下,通過調(diào)制脈寬進(jìn)行控制。
設(shè)備介紹
-
具體實(shí)控
例如在50Hz情況下,即周期為20ms
①驅(qū)動信號區(qū)間: 區(qū)間一(0.5ms-1.5ms )和區(qū)間二(1.5ms-2.5ms ) (注意都是開區(qū)間且存在死區(qū))
②其中區(qū)間一和區(qū)間二分別表示不同的方向運(yùn)動,例區(qū)間一表示正方向,則區(qū)間二表示反方向。
③旋轉(zhuǎn)速度呈現(xiàn)為“ V ” 字形,即0.5ms和2.5ms分別表示為正反方向的最快速度,1.5ms左右分別表示正反方向的最慢速度。其中小于等于0.5ms時(shí)、1.5ms時(shí)和大于等于2.5ms時(shí)電機(jī)都保持停轉(zhuǎn)狀態(tài)。 -
電調(diào)引線
再看電調(diào)引線,可注意 分別有7根線,如上圖,其中粗線有四根,紅黑兩根線為電源線,這里接24V,還有兩根黃藍(lán)接電機(jī),控制電機(jī)不同轉(zhuǎn)向;細(xì)線有三根,分別是紅黑白,其中紅黑為電源線,輸出5V,可選擇是否需要給MCU供電,黑線接地,白色線為PWM信號輸入線,接收MCU發(fā)過來的信號進(jìn)而控制電機(jī)轉(zhuǎn)動。 -
電機(jī)引線
如上圖,電機(jī)有6根線,跟大眾使用的編碼器電機(jī)無差別,兩根電機(jī)引線+兩根編碼器電源線+AB相 -
PID
由于前幾節(jié)中已介紹pwm的基本使用,這里就不再介紹,下面我直接介紹我的PID設(shè)計(jì)
①首先在主函數(shù)中對PID進(jìn)行初始化,即設(shè)置目標(biāo)數(shù)、比例積分微分常數(shù)、輸出限幅、積分限幅。
②在定時(shí)器中斷中對旋轉(zhuǎn)產(chǎn)生的脈沖進(jìn)行采樣,然后進(jìn)行PID運(yùn)算,將輸出信號傳入電調(diào)。
③在P、I、D參數(shù)調(diào)節(jié)中,我習(xí)慣先調(diào)I,將P和D置0,從小–>大調(diào),觀察電機(jī)變化,這里我使用的是一個(gè)上位機(jī)軟件VOFA,串口協(xié)議,通過上傳指定數(shù)據(jù),可以很好的觀察波形變化,可發(fā)現(xiàn) 它呈現(xiàn)出一個(gè)緩慢上升的波形,這時(shí)可以對I進(jìn)行放大,加快上升速度,我的調(diào)節(jié)是:調(diào)至I能很好的達(dá)到目標(biāo)點(diǎn),且在第一次達(dá)到目標(biāo)點(diǎn)時(shí),可以讓它超出適量值,再對比左右部分?jǐn)?shù)值,發(fā)現(xiàn)這個(gè)點(diǎn)的I值達(dá)到目標(biāo)點(diǎn)的速度更快,則這個(gè)點(diǎn)就是我要的I值。然后再對P進(jìn)行調(diào)節(jié),也可以選擇從小–>大調(diào),P可以很好的反饋出控制器對電機(jī)的控制速度,即加大對目標(biāo)值的反應(yīng),具體調(diào)節(jié)方法同I。最后在對D進(jìn)行調(diào)節(jié)(對于一般的控制,PI兩個(gè)參數(shù)足以滿足需求,如果最后完美,可再選擇D),D表現(xiàn)為誤差變化率的變化,可以抑制電機(jī)的超調(diào)等,對于D,你可以用某物體人為的阻擋電機(jī)轉(zhuǎn)動,觀察電機(jī)變化,例如你提供足夠大的阻力,電機(jī)肯定會直接拉滿,這時(shí)觀察電機(jī)再次回到目標(biāo)點(diǎn)的時(shí)間。
軟件設(shè)計(jì)
- 1. 設(shè)備初始化
/************************** Uart ************************************/
void Uart_Init(void)
{char str[] = "hello RT-Thread!\r\n";/* step1:查找串口設(shè)備 */serial = rt_device_find(SAMPLE_UART_NAME);/* step2:修改串口配置參數(shù) */config.baud_rate = BAUD_RATE_115200; //修改波特率為 115200config.data_bits = DATA_BITS_8; //數(shù)據(jù)位 8config.stop_bits = STOP_BITS_1; //停止位 1config.bufsz = 128; //修改緩沖區(qū) buff size 為 128config.parity = PARITY_NONE; //無奇偶校驗(yàn)位/* step3:控制串口設(shè)備。通過控制接口傳入命令控制字,與控制參數(shù) */rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &config);/* step4:打開串口設(shè)備。以中斷接收及輪詢發(fā)送模式打開串口設(shè)備 */rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
}/************************** Timer ************************************/
void Timer_Init(void)
{rt_hwtimer_mode_t mode; /* 定時(shí)器模式 */rt_hwtimerval_t timeout_s; /* 定時(shí)器超時(shí)值 */rt_uint32_t freq = 1000000; /* 計(jì)數(shù)頻率 */// 使用前必須先手動打開時(shí)鐘__HAL_RCC_TIM3_CLK_ENABLE();/* 查找定時(shí)器設(shè)備 */hw_dev = rt_device_find(HWTIMER_DEV_NAME);if (hw_dev == RT_NULL){rt_kprintf("hwtimer sample run failed! can't find %s device!\n", HWTIMER_DEV_NAME);}/* 以讀寫方式打開設(shè)備 */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);}/* 設(shè)置超時(shí)回調(diào)函數(shù) */rt_device_set_rx_indicate(hw_dev, Timer3_Out);/* 設(shè)置計(jì)數(shù)頻率(若未設(shè)置該項(xiàng),默認(rèn)為1Mhz 或 支持的最小計(jì)數(shù)頻率) */rt_device_control(hw_dev, HWTIMER_CTRL_FREQ_SET, &freq);/* 設(shè)置模式為周期性定時(shí)器(若未設(shè)置,默認(rèn)是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);}/* 設(shè)置定時(shí)器超時(shí)值為2s并啟動定時(shí)器 */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)
{/* 查找設(shè)備 */pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME);if (pwm_dev == RT_NULL){rt_kprintf("pwm sample run failed! can't find %s device!\n", PWM_DEV_NAME);}/* 使能設(shè)備 */rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL1);/* 設(shè)置PWM周期和脈沖寬度 */rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL1, period, pulse);
}/************************** Encoder ************************************/
void Encoder_Init(void)
{/* 查找脈沖編碼器設(shè)備 */pulse_encoder_dev = rt_device_find(PULSE_ENCODER_DEV_NAME);if (pulse_encoder_dev == RT_NULL){rt_kprintf("pulse encoder sample run failed! can't find %s device!\n", PULSE_ENCODER_DEV_NAME);}/* 以只讀方式打開設(shè)備 */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計(jì)算,可供參考
PID_VAR_TYPE Position_PID_Cal(PID * s_PID,PID_VAR_TYPE now_point)
{s_PID->LastResult = s_PID->Result; // 簡單賦值運(yùn)算//誤差計(jì)算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計(jì)算s_PID->Result = s_PID->Proportion * s_PID->Error // 比例項(xiàng)+ IOutValue // 積分項(xiàng)+ s_PID->Derivative * (s_PID->Error - s_PID->LastError); // 微分項(xiàng)s_PID->PrevError = s_PID->LastError; // 簡單賦值運(yùn)算s_PID->LastError = s_PID->Error; // 簡單賦值運(yùn)算//輸出限幅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
正如上面所介紹的一個(gè)上位機(jī)軟件,可觀察PID波形變化,協(xié)助開發(fā),具體協(xié)議如下所示:
void SendDatatoVoFA(rt_uint8_t byte[],float v_real)
{rt_uint8_t t_test=0;//四位發(fā)送rt_uint8_t send_date[4]={0};//發(fā)送數(shù)據(jù)Float_to_Byte(v_real,byte); //類型轉(zhuǎn)換for(t_test=0;t_test<4;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_test=0;t_test<4;t_test++){rt_device_write(serial, 0, &send_date[t_test], 1);}
}
- 4. 在定時(shí)器中斷不斷進(jìn)行PID計(jì)算,并輸出PWM信號
static rt_err_t Timer3_Out(rt_device_t dev, rt_size_t size)
{ rt_device_read(pulse_encoder_dev, 0, &count, 1); /* 讀取脈沖編碼器計(jì)數(shù)值 */rt_int32_t out=Position_PID_Cal(&pid1,count);rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL1, period, out);rt_kprintf("%d - %d\n",count,out);SendDatatoVoFA(byte,count); //發(fā)送到vofa上位機(jī),查看波形rt_device_control(pulse_encoder_dev, PULSE_ENCODER_CMD_CLEAR_COUNT, RT_NULL);/* 清空脈沖編碼器計(jì)數(shù)值 */return 0;
}