了解如何使用您的 Arduino 控制樂(lè)高電機(jī)和伺服系統(tǒng),并構(gòu)建您自己的 Android 應(yīng)用程序來(lái)遠(yuǎn)程控制您的模型。
背景
您是否擁有帶有電動(dòng)機(jī)和伺服電機(jī)的超棒Lego Power Functions 模型之一?在本文中,我將向您展示如何使用 Arduino 和最少的電子元件來(lái)控制樂(lè)高模型。我將詳細(xì)解釋電路和編程,以便于初學(xué)者理解。
我們還將學(xué)習(xí)如何使用MIT 應(yīng)用程序發(fā)明者來(lái)編寫(xiě)我們自己的遠(yuǎn)程控制 Android 應(yīng)用程序。很快,您將在您的后院擁有自己的樂(lè)高火星探測(cè)器!
這是我的第一個(gè) Arduino 項(xiàng)目,我兒子有一個(gè)漂亮的 Lego Technic 汽車模型(9398 4X4 Crawler ),帶有樂(lè)高動(dòng)力功能:一個(gè)用于轉(zhuǎn)向的樂(lè)高伺服電機(jī)和兩個(gè)用于駕駛的樂(lè)高 L 電機(jī)。同時(shí)他也允許我在這個(gè)項(xiàng)目中使用這輛車。
了解電源功能接線
首先,購(gòu)買一些樂(lè)高電源功能延長(zhǎng)線。接下來(lái),將它們切斷。我們將制作一些“分線”電纜,一端有樂(lè)高積木,另一端有別針。將引腳焊接在上面或類似的地方。以下是接線說(shuō)明:
GND 代表接地,它是電池組(陽(yáng)極)的負(fù)極端子 (-)。C1和C2可以切換極性,使電機(jī)和舵機(jī)切換方向。對(duì)于樂(lè)高伺服連接器,你需要將針腳焊接到所有四根電纜上。您可以使用淺灰色插頭。對(duì)于連接電池盒和面包板的電源線,我們只需要 +9 Volt 和 GND 但您必須使用深灰色插頭:
對(duì)于電機(jī)電纜,我們只需連接 C1 和 C2,您可以使用淺灰色插頭。
使用 L293D 芯片控制樂(lè)高電機(jī)
我們需要直流電機(jī)的變速控制和樂(lè)高伺服的位置控制。這是通過(guò)脈沖寬度調(diào)制 (PWM)實(shí)現(xiàn)的。Arduino的編程語(yǔ)言使PWM易于使用;只需調(diào)用analogWrite(pin, dutyCycle) ,其中 dutyCycle 是一個(gè)從 0 到 255 的值。PWM 引腳在您的 arduino 上標(biāo)有 ~。
Arduino 輸出引腳為 5 伏特和最大值。30 毫安,而樂(lè)高電機(jī)需要 9 伏且每個(gè)拉力超過(guò) 100 毫安。我們需要某種介于兩者之間的“開(kāi)關(guān)設(shè)備”。我們還希望能夠在兩個(gè)方向上運(yùn)行直流電機(jī)。這些功能由所謂的H 橋解決。我們將使用L293D ,它在一個(gè)集成芯片上包含兩個(gè) H 橋,這意味著我們可以將樂(lè)高電機(jī) (M) 并聯(lián)連接到芯片的一側(cè),將樂(lè)高伺服 (S) 連接到芯片的另一側(cè)。(如果您想獨(dú)立控制兩個(gè)電機(jī),則需要第二個(gè) L293D)。樂(lè)高伺服還需要連接到 GND 和樂(lè)高 +9 伏。
該芯片使 Lego +9 Volt 和 Arduino +5 Volt 完全分離。切勿將它們連接在一起,否則會(huì)損壞某些東西!但是您同時(shí)須將所有接地線連接在一起并與 L293D 接地引腳連接。
在我們的 Arduino 中,我們將使用引腳 9 來(lái)控制電機(jī)速度,使用引腳 2 和 5 來(lái)控制旋轉(zhuǎn)方向。樂(lè)高伺服像電機(jī)一樣被控制:我們連接引腳 3 用于位置,引腳 6 和 8 用于方向(左或右)。
在我們程序的頂部,我們將使用的 Arduino 引腳定義為常量。此外,我們定義了一些用于控制電機(jī)的變量:
// Motor control digital output pins defined as global constants
const int controlPin1A = 2; ? ? ? ? ? ? ? ?
const int controlPin2A = 5; ? ? ? ? ? ? ? ??
const int ENablePin = 9; ? ? ? ? ? ? ? ? ??
// Servo control digital output pins defined as global constants?
const int controlPin3A = 6; ? ? ? ? ? ? ?
const int controlPin4A = 8; ? ? ? ? ? ? ? ? ?
const int servoENablePin = 3; ?
? ? ? ??
// Motor control global variables:?
int motorSpeed = 0; ? ? ? ? ? ? ? ? ? ? ? ? ?// Motor speed 0..255
int motorDirection = 1; ? ? ? ? ? ? ? ? ? ? ?// Forward (1) or reverse (0)
// Servo control global variables:
int steering = 0; ? ? ? ? ? ? ? ? ? ? ? ? ? ?// Servo position 0..255
int steeringDirection = 0; ? ? ? ? ? ? ? ? ? // Left (0) and Right (1)
在設(shè)置中,我們使用pinmode()命令將這些引腳定義為輸出,然后使用digitalWrite ()將它們?cè)O(shè)置為 0 伏。?
void setup()?
{
? //other stuff....
?
? // Declare digital output pins:
? pinMode(controlPin1A, OUTPUT); ? ? ?// 1A
? pinMode(controlPin2A, OUTPUT); ? ? ?// 2A
? pinMode(ENablePin, OUTPUT); ? ? ? ? // EN1,2
? pinMode(controlPin3A, OUTPUT); ? ? ?// 3A
? pinMode(controlPin4A, OUTPUT); ? ? ?// 4A
? pinMode(servoENablePin, OUTPUT); ? ?// EN3,4
?
? digitalWrite(ENablePin, LOW); ? ? ? // motor off
? digitalWrite(servoENablePin, LOW); ?// steering centered
}
現(xiàn)在我們需要了解 L293D 芯片是如何控制電機(jī)的旋轉(zhuǎn)方向的。我們必須提供以下信號(hào)(高 == 5 伏;低 == 0 伏):
EN1,2 1A 2A
高 高 低 電機(jī)左轉(zhuǎn)(前進(jìn);motorDirection == 1)
高 低 高 電機(jī)右轉(zhuǎn)(反向;motorDirection == 0)
EN3,4 3A 4A
高 高 低 舵機(jī)左轉(zhuǎn)(steeringDirection == 0)
高 低 高 舵機(jī)右轉(zhuǎn)(steeringDirection == 1)
接下來(lái)我們準(zhǔn)備編寫(xiě)一個(gè)子程序來(lái)讀取方向和速度/位置的全局變量并控制電機(jī)和伺服:
void SetMotorControl()
{
?if (motorDirection == 1) ? ? ? ? ? ? ? //Forward
? ?{
? ? ? digitalWrite(controlPin1A, HIGH);
? ? ? digitalWrite(controlPin2A, LOW);
? ?}
?else ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //Reverse
? ?{
? ? ? digitalWrite(controlPin1A, LOW);
? ? ? digitalWrite(controlPin2A, HIGH);
? ?}?
?analogWrite(ENablePin, motorSpeed); ? ?//Speed
?
?if (steeringDirection == 0) ? ? ? ? ? ?//Left
? ?{
? ? ? digitalWrite(controlPin3A, HIGH);
? ? ? digitalWrite(controlPin4A, LOW);
? ?}
?else ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //Right
? ?{
? ? ? digitalWrite(controlPin3A, LOW);
? ? ? digitalWrite(controlPin4A, HIGH);
? ?}?
?analogWrite(servoENablePin, steering); //Servo position
}
帶有操縱桿的簡(jiǎn)單 RC Android 應(yīng)用程序
接下來(lái),讓我們構(gòu)建一個(gè)簡(jiǎn)單的 Android 應(yīng)用程序來(lái)控制模型。
我們將使用 MIT app inventor 2。MIT App Inventor 是一個(gè)創(chuàng)新的初學(xué)者對(duì)編程和應(yīng)用程序創(chuàng)建的介紹。Google 的 Mark Friedman 和麻省理工學(xué)院教授 Hal Abelson 共同領(lǐng)導(dǎo)了 App Inventor 的開(kāi)發(fā)。它作為一項(xiàng)網(wǎng)絡(luò)服務(wù)運(yùn)行,由麻省理工學(xué)院移動(dòng)學(xué)習(xí)中心的工作人員管理。
在您的 Android 手機(jī)上,前往 Google Play 并安裝MIT AI2 Companion 應(yīng)用程序。在您的計(jì)算機(jī)上,在 Firefox 或 Chrome 瀏覽器中打開(kāi)我的RC 應(yīng)用程序的鏈接。您必須使用您的 gmail 地址登錄并創(chuàng)建一個(gè)帳戶才能查看源代碼。如果您在手機(jī)上打開(kāi)配套應(yīng)用程序,您可以在瀏覽器中查看源代碼,對(duì)其進(jìn)行更改并立即在手機(jī)上進(jìn)行測(cè)試。
在瀏覽器中,您現(xiàn)在將看到應(yīng)用程序的設(shè)計(jì)器視圖:
在底部,我們看到帶有藍(lán)色操縱桿球的橙色墊。現(xiàn)在切換到 Blocks-view 來(lái)查看程序。該程序的核心是一個(gè) when 塊,它跟蹤您的手指觸摸和拖動(dòng)藍(lán)色操縱桿球的動(dòng)作:
您的手指位置將會(huì)在兩個(gè)變量currentX和currentY中進(jìn)行跟蹤,并用于計(jì)算兩個(gè)變量轉(zhuǎn)向和速度的值(范圍:-100..0..+100)。首先,程序會(huì)先檢查您的手指是否在墊外,并將值限制為 +/- 100。如果手指在墊內(nèi),程序會(huì)計(jì)算轉(zhuǎn)向和速度的值。接下來(lái),程序生成以下形式的命令字符串:
“遙控,轉(zhuǎn)向,速度,\n”
該命令以用于遠(yuǎn)程控制的“RC”開(kāi)頭,后跟逗號(hào)。然后我們發(fā)送轉(zhuǎn)向和速度的值。命令末尾的換行符 (‘\n’) 是向 Arduino 發(fā)出命令完成的信號(hào)。該命令字符串通過(guò)藍(lán)牙發(fā)送到 Arduino。供您參考,該字符串也顯示在屏幕上。
將藍(lán)牙命令讀入 Arduino
為了讀取藍(lán)牙命令字符串,我們需要連接一個(gè) HC-05 藍(lán)牙模塊:
我的這塊板子有 6 個(gè)引腳。但我們實(shí)際上只需要 4 個(gè)引腳。VCC 是(正)電源電壓,GND 是地。該模塊可承受 6 伏電源電壓,這意味著我們可以將其連接到 arduino 5 伏電源引腳。TXD 和 RXD 是串行信號(hào)。我們必須越線并將 TXD 連接到 arduino RXD(引腳 0),反之亦然。
注意: LEVEL:3.3V,這意味著 RXD不能直接連接到 5V arduino TXD(引腳 1)。我們必須構(gòu)建一個(gè)帶有三個(gè) 1 kOhm 電阻的分壓器,以產(chǎn)生 5V 的 2/3 的輸出電壓。另一方面,3.3V 的 TXD 信號(hào)可以直接連接到 Arduino RXD。Arduino 會(huì)將 3.3V識(shí)別為高。
由于引腳 0 和 1 與 Arduino 的 USB 端口共享,因此在通過(guò) USB 將程序上傳到開(kāi)發(fā)板時(shí),您必須斷開(kāi)引腳 0 和 1 的 RXD 和 TXD 信號(hào)。如果您不斷開(kāi)電纜,上傳將無(wú)法進(jìn)行。
接下來(lái),您必須將 HC-05 模塊與您的 Android 設(shè)備配對(duì)。打開(kāi)藍(lán)牙;啟動(dòng)應(yīng)用程序;按“藍(lán)牙連接”;讓您的手機(jī)可見(jiàn)并尋找名為 HC-05 或類似設(shè)備的設(shè)備。選擇設(shè)備。您將被要求輸入代碼。按“1234”。當(dāng)您返回操縱桿屏幕時(shí),它應(yīng)該以綠色顯示“已連接”。
現(xiàn)在,讓我們看一下代碼:
// Serial buffer size: calculate based on max input size expected for one command
#define INPUT_SIZE 30
?
?
void loop()?
{
? // Get next command from serial bluetooth (add 1 byte for final 0)
? char input[INPUT_SIZE + 1]; ? ? ? ? ? ? ? ? ?// array of type char (C-string)
? //read Serial until new line or buffer full or time out
? byte size = Serial.readBytesUntil('\n', input, INPUT_SIZE); ??
? // Add the final 0 to end the C-string
? input[size] = 0;
?
? // Split string which is of the form: ?"RC,steering,speed,\n\0"
? char* command = strtok(input, ","); ? ? ? ? ?// command (RC) ??
? // RCsteering in Range: -100 (left).. 0 .. 100 (right)
? char* RCsteering = strtok(NULL, ","); ? ? ? ?
? // RCspeed in Range: -100 (full speed reverse).. 0 .. 100 (full speed forward)
? char* RCspeed = strtok(NULL, ","); ? ? ? ? ??
? int iRCsteering = atoi(RCsteering); ? ? ? ? ?// convert string into integer
? int iRCspeed = atoi(RCspeed); ? ? ? ? ? ? ? ?// convert string into integer
?
? //rest of program
}
Android 應(yīng)用程序發(fā)送的字符串被讀入一個(gè)特殊的字符串結(jié)構(gòu):一個(gè)帶有 null-termination 的 C 字符串。(0 字符告訴程序它已經(jīng)到了字符串的末尾)。這是通過(guò)使用函數(shù) Serial.readBytesUntil(‘\n’, input, 。..)來(lái)完成的,該函數(shù)從串行接口(藍(lán)牙)讀取,直到獲得換行符(‘\n’)。這樣,我們會(huì)一直讀取字節(jié),直到在input中有完整的命令:
“遙控,轉(zhuǎn)向,速度,\n\0”。
處理輸入的一種非常有效的方法是字符串標(biāo)記函數(shù),它使用逗號(hào)作為分隔符將字符串分成幾部分。第一次調(diào)用 strtok() 返回“RC”。然后通過(guò)將 NULL 傳遞給 strtok() 來(lái)讀取命令的后續(xù)部分。返回值存儲(chǔ)在RCsteering和RCspeed中。這些變量實(shí)際上是指向input中位置的指針。atoi()函數(shù)最終將它們轉(zhuǎn)換為整數(shù)。現(xiàn)在,我們有:
iRC 轉(zhuǎn)向 == -100(左)。. 0 。. +100(右)
iRCspeed == -100(后退)。. 0 。. +100(前進(jìn))
現(xiàn)在差不多完成了。在將它們傳遞給我們的例程 SetMotorControl() 之前,我們必須將這些值乘以 2.55(請(qǐng)記住,電機(jī)速度在 0..255 范圍內(nèi))。你現(xiàn)在可以在 CODE 部分研究程序的其余部分,構(gòu)建電路并測(cè)試您的遙控樂(lè)高模型。
未來(lái)?
既然您有一個(gè) Arduino 控制您的樂(lè)高模型,您可能希望將該模型用作機(jī)器人平臺(tái):
添加一些超聲波 ping 傳感器,編寫(xiě)您自己的避障邏輯并制作您自己的自動(dòng)駕駛機(jī)器人火星探測(cè)器。
或者給遙控器增加更多指令,給模型增加更多功能。
評(píng)論
查看更多