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