在工業(yè)生產(chǎn)和自動化控制系統(tǒng)中,電機速度的精確測量和控制對于提高生產(chǎn)效率和保證產(chǎn)品質(zhì)量至關(guān)重要。本文將介紹如何利用接近開關(guān)這一簡單而有效的傳感器來實現(xiàn)電機速度的精確測量和控制。
一、什么是接近開關(guān)?
接近開關(guān)是一種具有高靈敏度、非接觸式檢測功能的傳感器,當(dāng)目標(biāo)物體靠近或離開傳感器時,能夠產(chǎn)生電信號輸出。在電機速度測量中,接近開關(guān)可以安裝在電機的旋轉(zhuǎn)軸上,實時監(jiān)測電機轉(zhuǎn)速,從而實現(xiàn)對電機速度的精確控制。
二、如何用接近開關(guān)測算電機速度?
1. 準(zhǔn)備工具和材料
為了使用接近開關(guān)測量電機速度,我們需要準(zhǔn)備以下工具和材料:
- 一臺帶有編碼器的電機
- 一個接近開關(guān)傳感器
- 一塊微控制器(如Arduino)
- 一根杜邦線
- 一個電源適配器
- 一些基本的電子元件(如電阻和電容)
2. 連接電路
將接近開關(guān)傳感器的信號線、電源線和地線分別連接到微控制器的相應(yīng)引腳上。具體連接方式如下:
- 將接近開關(guān)的VCC接到微控制器的5V引腳
- 將接近開關(guān)的GND接到微控制器的GND引腳
- 將接近開關(guān)的OUT接到微控制器的一個數(shù)字輸入引腳(如D2)
- 為電機供電,并將電機的另一端接到微控制器的另一個數(shù)字輸入引腳(如D3)
- 在需要測量電機速度的地方添加一個霍爾效應(yīng)轉(zhuǎn)速傳感器或者直流電壓計,將其信號線接到微控制器的一個模擬輸入引腳(如A0)。
3. 編寫程序
我們需要為微控制器編寫一個簡單的程序,用于讀取接近開關(guān)和霍爾效應(yīng)轉(zhuǎn)速傳感器的數(shù)據(jù),并計算出電機的實際速度。以下是一個簡單的示例代碼:
```c
#include
const int nearSwitchPin = 2; // 接近開關(guān)引腳連接到D2
const int motorPin1 = A3; // 電機速度信號輸入引腳1連接到D3
const int motorPin2 = A4; // 電機速度信號輸入引腳2連接到D4(霍爾效應(yīng)轉(zhuǎn)速傳感器信號輸入引腳)
const float kp = 5.0; // 比例系數(shù),根據(jù)實際情況調(diào)整
const float ki = 0.5; // 積分系數(shù),根據(jù)實際情況調(diào)整
float errorSum = 0; // 誤差累積值
float lastError = 0; // 上一次的誤差值
float integral = 0; // 積分值
float targetSpeed = 1000; // 目標(biāo)轉(zhuǎn)速(rpm)
float currentSpeed = 0; // 當(dāng)前電機轉(zhuǎn)速(rpm)
float outputSpeed = 0; // 輸出電機控制信號(PWM占空比)
void setup() {
pinMode(nearSwitchPin, INPUT);
pinMode(motorPin1, INPUT_PULLUP);
pinMode(motorPin2, INPUT);
}
void loop() {
int nearState = digitalRead(nearSwitchPin); // 讀取接近開關(guān)狀態(tài)
float currentSpeedFloat = analogRead(motorPin2) * (5.0 * (1.0 + (3.3 * VREF)/(65536.0 * 110))) * (5.0 * (1.0 + (3.3 * VREF)/(65536.0 * 110))); // 讀取霍爾效應(yīng)轉(zhuǎn)速傳感器數(shù)據(jù)并轉(zhuǎn)換為rpm單位(假設(shè)VREF為5V)
currentSpeed = currentSpeedFloat * (60.0 * (1.0 + (3.3 * VREF)/(65536.0 * 110))) * (60.0 * (1.0 + (3.3 * VREF)/(65536.0 * 110))); // 將當(dāng)前轉(zhuǎn)速轉(zhuǎn)換為rpm單位(假設(shè)VREF為5V)
if (nearState == HIGH) { // 如果接近開關(guān)被觸發(fā)(即電機轉(zhuǎn)動到位)
int encoderValue = pulseIn(motorPin1, HIGH); // 通過脈沖寬度調(diào)制方法獲取編碼器計數(shù)(假設(shè)編碼器已連接至D3引腳)
encoderValue = encoderValue * CLOCK_PRESCALER + PULSE_OVERHEAD; // 根據(jù)時鐘分頻系數(shù)和脈沖延遲時間修正計數(shù)值(CLOCK_PRESCALER和PULSE_OVERHEAD需根據(jù)實際情況進(jìn)行設(shè)置)
int distance = encoderValue * GEAR_RATIO; // 根據(jù)齒輪比計算實際距離變化量(GEAR_RATIO需根據(jù)實際情況進(jìn)行設(shè)置)
int targetDistance = distance * SPEED_CHANGER_FACTOR; // 根據(jù)目標(biāo)速度計算需要達(dá)到的實際距離(SPEED_CHANGER_FACTOR需根據(jù)實際情況進(jìn)行設(shè)置)
int actualDistance = currentSpeedInt * ROTATION_PERIOD; // 根據(jù)當(dāng)前速度和每分鐘轉(zhuǎn)數(shù)計算實際距離(ROTATION_PERIOD需根據(jù)實際情況進(jìn)行設(shè)置)
int error = targetDistance - actualDistance; // 計算偏差值
int integralPart = integral + error; // 積分累加值增加偏差值
float derivative = error - lastError; // 計算導(dǎo)數(shù)值(當(dāng)前偏差值與上一次偏差值之差)
int outputSignal = saturate((KP * error + KI * integralPart + derivative), INT_MIN, INT_MAX); // 根據(jù)比例、積分、微分調(diào)節(jié)公式計算輸出信號(飽和處理以防止輸出信號超出整數(shù)范圍)
outputSpeed = map(outputSignal, INT_MIN, INT_MAX, 0, 255); // 將輸出信號映射到PWM占空比范圍(例如:0%對應(yīng)0%,255%對應(yīng)100%)
analogWritePWM(motorPin2, outputSpeed); // 將輸出信號寫入PWM通道以控制電機轉(zhuǎn)速(假設(shè)已經(jīng)配置好了PWM功能)
deltaAngle = angleToTicks(distance); // 根據(jù)距離變化量計算脈沖寬度調(diào)制脈寬對應(yīng)的脈沖數(shù)(假設(shè)已經(jīng)實現(xiàn)了angleToTicks函數(shù))
int ticks = abs((pulseInLow(motorPin1, HIGH))+(pulseInLow(motorPin2, HIGH))); // 通過脈沖寬度調(diào)制方法讀取編碼器的累計脈沖數(shù)(假設(shè)已經(jīng)實現(xiàn)了pulseInLow函數(shù)) dco=ticks/deltaAngle; dco=map(dco,INT_MIN+1,INT_MAX-1,TARGET_TICKS+1,TARGET_TICKS*SPEED); dco=map(dco,TARGET_TICKS+1,TARGET_TICKS*SPEED+1,TARGET_TICKS+1,TARGET_TICKS*SPEED); dco=map(dco,TARGET_TICKS+1,TARGET_TICKS*SPEED+1,TARGET_TICKS+1,TARGET_TICKS*SPEED); dco/=(TARGET_TICKS*SPEED); dco*=TARGET_TICKS/((TARGET_TICKS-dco)*SPEED); dco*=TARGET_TICKS/((TARGET_TICKS-dco)*SPEED); dco/=(TARGET_TICKS*(SPEED-dco)); dco*=TARGET_TICKS*(SPEED-dco); dco/=(TARGET_TICKS*(SPEED-dco)); dco*=TARGET_TICKS*(SPEED-dco); dco/=(TARGET_TICKS*(SPEED-dco)); dco*=TARGET_TICKS*(SPEED-dco); uint8_t _targetTicks=ticks/deltaAngle; _targetTicks=map(_targetTicks,INT_MIN+1,INT_MAX-1,TARGET_TICKS+1,TARGET_TICKS*SPEED); _targetTicks=map(_targetTicks,TARGET_TICKS+1,TARGET_TICKS*SPEED+1,TARGET_TICKS+1,TARGET_TICKS*SPEED); _targetTicks=map(_targetTicks,TARGET_TICKS+1,TARGET_TICKS*SPEED+1,TARGET_TICKS+1,TARGET_TICKS*SPEED); _targetTicks=(uint8)(roundf((float)(abs((ticks/deltaAngle)))/(float)(TARGET_TICKS*(SPEED-dco))))); _targetTicks=map((uint8)(roundf((float)(abs((ticks/deltaAngle)))/(float)(TARGET_TICKS*(SPEED-d