Arduino通過(guò)太陽(yáng)能操作機(jī)器人割草機(jī)動(dòng)力
這個(gè)機(jī)器人會(huì)修剪你花園里的草,呆在指定的區(qū)域內(nèi),避開(kāi)所有障礙,完全自主工作,用太陽(yáng)能電池板自動(dòng)充電。
本文引用地址:http://cafeforensic.com/article/202308/450104.htm在這篇文章中,我們介紹了一種機(jī)器人割草機(jī),它由太陽(yáng)能供電,能夠僅利用來(lái)自太陽(yáng)的清潔能源進(jìn)行操作;這與商業(yè)項(xiàng)目有很大的不同,商業(yè)項(xiàng)目需要一個(gè)連接到電網(wǎng)的充電站。在設(shè)計(jì)太陽(yáng)能驅(qū)動(dòng)的割草機(jī)時(shí),至關(guān)重要的是,大部分能量來(lái)自太陽(yáng),當(dāng)然,如果太陽(yáng)能足以為機(jī)器人完全供電,最終結(jié)果就會(huì)得到:然而,鑒于現(xiàn)有太陽(yáng)能電池板的低效率,這一目標(biāo)將很難實(shí)現(xiàn)。在我們的項(xiàng)目中,機(jī)器人的整個(gè)表面都是太陽(yáng)能電池板,同時(shí)也是一個(gè)蓋子:只有側(cè)面是自由的,無(wú)論如何,它們?cè)诠?yīng)能源方面都不會(huì)發(fā)揮決定性作用。顯然,這種選擇對(duì)項(xiàng)目的其余部分構(gòu)成了嚴(yán)重的限制,因?yàn)橥ㄟ^(guò)這種方式,我們已經(jīng)定義了可用的最大功率。
我們必須考慮到,太陽(yáng)能并不總是可用的,因?yàn)樵S多花園區(qū)域經(jīng)常處于陰涼處,或者無(wú)論如何都沒(méi)有被太陽(yáng)直接照射,所以我們必須考慮相當(dāng)大的電力損失。只有當(dāng)機(jī)器人有一個(gè)蓄能器,能夠在缺乏陽(yáng)光的情況下提供能量時(shí),才能彌補(bǔ)這些損失。在這種情況下,電池起到緩沖作用,在電量充足時(shí)積累能量,相反,在機(jī)器人處于陰影下時(shí)提供能量。從這個(gè)角度來(lái)看,鉛電池是最合適的電池,但沒(méi)有什么能阻止我們使用在重量和容量方面表現(xiàn)更好的電池,比如鋰電池。在陽(yáng)光充足的情況下,太陽(yáng)能電池板能夠用約0.6A的電流為內(nèi)部電池充電,總功率約為8W,遠(yuǎn)低于最高效的電動(dòng)割草機(jī)所使用的功率,功率為220Vac。這讓我們已經(jīng)明白,像我們?cè)谶@些頁(yè)面中描述的產(chǎn)品不能完全取代手動(dòng)割草機(jī),因?yàn)楫?dāng)草太高時(shí),應(yīng)該不時(shí)使用最后一款。相反,機(jī)器人割草機(jī)可以用于連續(xù)穩(wěn)定地修剪草坪。
這種解決方案還提供了另一個(gè)優(yōu)勢(shì),因?yàn)檫B續(xù)割草可以確保草始終年輕柔軟,而且當(dāng)它被切成很小的碎片時(shí),它會(huì)在短時(shí)間內(nèi)自行分解,從而為草坪施肥。你不應(yīng)該指望被割下的草會(huì)被收集起來(lái):相反,它會(huì)沉積在剛剛割下的草葉中。
對(duì)于這種用途,所需的電力更少,并且可以使用電池供電系統(tǒng)輕松管理。游戲中的弱動(dòng)力說(shuō)服我們選擇一個(gè)牽引力和功率降低的切割發(fā)動(dòng)機(jī)。也許,它們可能不完全符合我們讀者的需求,他們可能會(huì)根據(jù)預(yù)算和個(gè)人需求選擇他們喜歡的引擎和結(jié)構(gòu)。為了確定草坪上的切割區(qū)域,地下布線系統(tǒng)被證明是簡(jiǎn)單、準(zhǔn)確和可靠的。它也是定義機(jī)器人工作區(qū)域的最佳系統(tǒng)。
一切都是基于一根簡(jiǎn)單電線的使用,電線鋪設(shè)在地上或其下,并連接到一個(gè)控制單元,用大約10V和34KHz頻率的交流電信號(hào)為電線本身供電。在機(jī)器人底盤(pán)的下部安裝了兩個(gè)小卷軸,一個(gè)在右側(cè),另一個(gè)在左側(cè),這兩個(gè)卷軸都是指由并聯(lián)的電容器形成的電路。由并聯(lián)電感和電容器形成的電路被稱為并聯(lián)諧振電路,并且被計(jì)算為使得當(dāng)磁場(chǎng)以34KHz的頻率變化時(shí),由外部磁場(chǎng)感應(yīng)的其端部的張力處于最大值。
現(xiàn)在讓我們來(lái)更詳細(xì)地描述這個(gè)項(xiàng)目所采用的電氣部分。最重要的創(chuàng)新是采用了Arduino作為控制板,使你能夠獲得一個(gè)更用戶友好、更易于破解的項(xiàng)目,即使是經(jīng)驗(yàn)不足的人。為了實(shí)現(xiàn)最大的使用靈活性,我們認(rèn)為要實(shí)現(xiàn)特定的屏蔽,而不是實(shí)現(xiàn)特定的電子板。
這種選擇也決定了一個(gè)缺點(diǎn),即當(dāng)板處于待機(jī)模式時(shí),電流的吸收,這種情況可能發(fā)生在夜間,機(jī)器人仍然沒(méi)有電源。在這種情況下,內(nèi)部電池將不得不面對(duì)Arduino板和屏蔽的長(zhǎng)時(shí)間供電。
關(guān)于發(fā)動(dòng)機(jī)的管理,就牽引力而言,我們計(jì)算了商用護(hù)罩的使用情況,這是唯一一種可用于修改控制銷分配的商用護(hù)罩;為此,請(qǐng)使用表1正確分配引腳。發(fā)動(dòng)機(jī)護(hù)罩可管理兩臺(tái)發(fā)動(dòng)機(jī),每臺(tái)發(fā)動(dòng)機(jī)的總最大吸收功率為2A,確保有足夠的動(dòng)力用于牽引。顯然,沒(méi)有什么可以禁止我們使用其他類型的驅(qū)動(dòng)器來(lái)驅(qū)動(dòng)發(fā)動(dòng)機(jī),從而增加功率;唯一重要的是,駕駛員為每臺(tái)發(fā)動(dòng)機(jī)提供兩個(gè)可用的控制信號(hào),一個(gè)用于定義方向,另一個(gè)用于控制速度所需的PWM信號(hào)。
該屏蔽是使用具有特定功能的最新組件設(shè)計(jì)的,因此需要使用高度集成的SMD組件,從而將所有東西都安裝到與Arduino UNO兼容的屏蔽中。用于讀取地下線路的部分基于包含六個(gè)CD4069型NOT門(mén)的集成電路。使用這種集成電路,我們只需放大并平方并聯(lián)諧振電路頭部的弱信號(hào)。即使在這個(gè)項(xiàng)目中,我們也計(jì)算了激活或停用太陽(yáng)能電池板的可能性;為此,我們依靠集成電路ASSR1611,這是一種由光隔離器控制的固態(tài)開(kāi)關(guān)。如果使用的緩沖電池是鉛電池,則無(wú)需拆下面板,因?yàn)檫@種電池可以很好地支持過(guò)充電,但如果您使用更現(xiàn)代的鋰電池,則必須在達(dá)到極限電壓后暫停充電,否則您可能會(huì)導(dǎo)致電池?fù)p壞,或在最壞的情況下發(fā)生爆炸。
兩個(gè)名為ACS712的集成電路可以測(cè)量太陽(yáng)能電池板提供的電流和切割引擎吸收的電流:5A范圍的版本對(duì)我們來(lái)說(shuō)似乎綽綽有余。
這些集成電路使用霍爾效應(yīng)技術(shù)來(lái)提供(作為輸出)與電源電路上的循環(huán)電流成比例的張力,從而與輸出級(jí)保持電流分離。測(cè)量太陽(yáng)能電池板電流的可能性將是檢測(cè)最適合給電池充電的區(qū)域的基礎(chǔ)。運(yùn)行時(shí),實(shí)際上會(huì)存儲(chǔ)面板提供的電流水平,當(dāng)割草機(jī)必須找到充電區(qū)時(shí),在電池電量接近低的情況下,會(huì)再次使用數(shù)據(jù)。機(jī)器人不知道真實(shí)的大氣情況(晴天或陰天),也不知道是否有陰影區(qū)域,甚至不知道它是否在變暗:它只會(huì)在上一次工作中檢測(cè)到的最大發(fā)光強(qiáng)度方面尋找一個(gè)足夠亮的區(qū)域。測(cè)量切割引擎吸收的電流將是了解切割過(guò)程中的作用力的基礎(chǔ),也是計(jì)算在異常情況下何時(shí)停止切割的基礎(chǔ)。
為了完成關(guān)于屏蔽的討論,我們必須注意二極管D1,它是在電池電量不足的情況下避免電池在光伏面板上的張力所必需的;以及使I2C總線可用所需的兩個(gè)連接器。
還設(shè)計(jì)了三個(gè)通用按鈕,它們通過(guò)電阻網(wǎng)絡(luò)連接到模擬輸入A0;事實(shí)上,所有的數(shù)字引腳都已被占用。一個(gè)入口由一個(gè)簧片傳感器使用,該傳感器放置在非??拷髽休S輪的位置,并由一個(gè)小磁鐵操作,該磁鐵在每次旋轉(zhuǎn)時(shí)插入同一個(gè)輪中。有了這個(gè)傳感器,就可以確定機(jī)器人是否有規(guī)律地移動(dòng),或者一個(gè)或多個(gè)輪子是否被鎖住或徒勞地移動(dòng)。
我們?cè)黾恿藘蓚€(gè)數(shù)字輸入,您可以將前面的障礙物識(shí)別機(jī)械開(kāi)關(guān)連接到它們;除此之外,經(jīng)驗(yàn)證的超聲波傳感器連接到I2C總線并檢測(cè)前方物體。
超聲波傳感器雖然性能非常好,但可能會(huì)被表面特別小的物體(如金屬網(wǎng))或一些非常不規(guī)則的表面(如灌木)所欺騙。
至于草坪修剪,我們依賴于航空建模領(lǐng)域使用的無(wú)刷電機(jī),該電機(jī)與通過(guò)組合兩個(gè)刀片獲得的刀片相連。
我們談?wù)摰氖且慌_(tái)200W的發(fā)動(dòng)機(jī),但它的使用率不超過(guò)20%。發(fā)動(dòng)機(jī)控制分配給模型構(gòu)建中使用的ESC(電子速度控制),并使用簡(jiǎn)單的PWM信號(hào)進(jìn)行操作,易于使用Arduino進(jìn)行管理,因?yàn)樗呀?jīng)在系統(tǒng)庫(kù)中具有相關(guān)功能。
為了測(cè)量電池頭部的張力,我們將使用電機(jī)護(hù)罩中已有的分壓器。然而,需要修改軌道,將分配器輸出的張力從引腳A5帶到引腳A3,以便引腳A4和A5可用于I2C總線。兩條數(shù)字線路D0和D1用于與PC通信,但一旦對(duì)Arduino進(jìn)行了編程,它們就可以用于與GPS或藍(lán)牙等其他外圍設(shè)備通信。
Tab. 1 Mower Shield pin connect
Pin Arduino | name | Description |
A0 | Button_pin | Push button |
A1 | ICut_pin | Motor cut current |
A2 | IPanel_pin | Solar panel current |
A3 | VBat_pin | Battery voltage (from motorshield_FE) |
A4 | SDA_pin | I2C BUS |
A5 | SCL_pin | I2C BUS |
D0 | RXD_pin | GPS or bluetooth |
D1 | TXD_pin | GPS or bluetooth |
D2 | Encoder_pin | Encoder pivoting wheel |
D3 | PWMA_pin | PWM motor A motorshield_FE |
D4 | DIRA_pin | Direction motor A motorshield_FE |
D5 | BWFR_pin | Buried Wire Fence Right |
D6 | BWFL_pin | Buried Wire Fence Left |
D7 | Panel_pin | ON/OFF pannel |
D8 | ESC_pin | ESC cut motor signal |
D9 | SWOL_pin | Obstacle switch Right |
D10 | SWOR_pin | Obstacle switch Left |
D11 | PWMB_pin | PWM motor B motorshield_FE |
D12 | DIRB_pin | Direction motor B motorshield_FE |
D13 | LCD_pin | Serial LCD |
硬件現(xiàn)在已經(jīng)相當(dāng)完整,防護(hù)罩做得非常好,盡管還可以添加一些更多的功能,比如雨水傳感器,或者更好的是,草濕度傳感器,這將使機(jī)器人能夠停下來(lái)等待更好的切割條件。作為一種安全措施,我們?cè)谛D(zhuǎn)輪上安裝了一個(gè)編碼器,作為一種支撐,甚至可以在牽引輪上添加一個(gè)編碼器甚至可以添加一個(gè)傳感器來(lái)測(cè)量吸收的電流。
電氣部分還計(jì)算了用于調(diào)試功能且絕對(duì)不需要的綠色背景黑色文本串行顯示器的使用情況。
使用一個(gè)簡(jiǎn)單的Arduino板應(yīng)該可以讓許多用戶嘗試實(shí)現(xiàn)電動(dòng)割草機(jī),當(dāng)然也不會(huì)缺少社區(qū)的貢獻(xiàn),以及進(jìn)一步改進(jìn)的建議。
關(guān)于屏蔽的電氣連接,請(qǐng)參考下表:
表2–屏蔽連接器的鏈接
connector function
J1 Ignition switch
J2 Battery Power
J3 Photovoltaic panel
J4 Electronic speed control (ESC) for the cutting engine
J5 Obstacle detection Switch left
J6 Obstacle detection Switch right
J7 Cotrol signal for the speed control of the cutting engine
J8 LCD Display
J9 Reed contact for the rear pivoting wheel
J10 1mH Reel for underground wiring detection left
J11 1mH Reel for underground wiring detection right
J12 Ultrasonic Sensor SRF-02 right
J13 Ultrasonic Sensor SRF-02 left
J14 Buttons
我們將在下面列出本項(xiàng)目中使用的所有硬件組件:
N°2微電機(jī)齒輪箱RH-158-12-200
N°2輪轂
2號(hào)超聲波傳感器SRF02。
N°1鉛蓄電池2,1Ah NP21-12
N°1太陽(yáng)能電池板STP10M 10W 0,59A
用于診斷的N°1 LCD串行顯示器1446-LCDSER16X2NV
用于航空建模BMA20-22L的N°1無(wú)刷電機(jī)
ESC-18A無(wú)刷電機(jī)的N°1速度控制
1個(gè)用于報(bào)警系統(tǒng)的磁性傳感器(用作編碼器)
能量平衡使我們能夠了解有用的能量循環(huán)以及一天可以做多少工作:
切割發(fā)動(dòng)機(jī)吸收的電流,約1.4A
電子設(shè)備吸收的電流0,07A
發(fā)動(dòng)機(jī)吸收的電流0,4A
光伏板吸收的電流,約0.6A
根據(jù)測(cè)量數(shù)據(jù)(使用所述設(shè)置),我們可以推斷運(yùn)行機(jī)器所需的電流是光伏板提供的電流的三倍,也就是說(shuō),一個(gè)小時(shí)的工作需要三個(gè)小時(shí)的充電,有用的使用百分比為30%。考慮到在夏天,在最佳條件下,大約有九個(gè)晴天,我們可能一天有大約三個(gè)小時(shí)的時(shí)間進(jìn)行修剪,這通常足以維持500平方米的花園秩序。
BOM
R1: 10 Mohm (0805)
R2: 100 kohm (0805)
R3: 10 Mohm (0805)
R4: 100 kohm (0805)
R5: 390 ohm (0805)
R6: 4,7 kohm (0805)
R7: 2,2 kohm (0805)
R8: 6,8 kohm (0805)
C1: 100 μF 25 VL (D)
C2: 100 nF (0805)
C3: 470 nF (0805)
C4: 470 nF (0805)
C5: 100 nF (0805)
C6: 100 nF (0805)
C7: 22 nF (0805)
C8: 1 nF (0805)
C9: 1 nF (0805)
C10: 22 nF (0805)
C11: 1 nF (0805)
C12: 1 nF (0805)
U1: ACS712ELCTR-05B-T
U2: ACS712ELCTR-05B-T
U3: CD4069UBM
U4: ASSR-1611-301E
F1: RUEF300
D1: GF1M
固件
/* SolarMower V1.0 SolarMower use mowershield_FE 2014 Mirco Segatello For hardware see www.elettronicain.it Press PEN during power-on for ESC test Press PUP during power-on for test motor Press PDW during power-on for test sensor */ #include <EEPROM.h> #include <SoftwareSerial.h> #include <Servo.h> #include "Wire.h" #include "SRF02.h" #include "Configuration.h" Servo ESC; //variables float VBat; // Battery voltage [V] int VBatPC; // Battery voltage percentage float VBatScale=0.054; // Battery scale for Volt converter float IPanel; // Panel current [A] float IPanelOffset; // Panel current offset float IPanelScale=0.185; // Panel current scale V/A float ICut; // Motor cut current [A] float ICutOffset; // Motor cut current offset float ICutScale=0.185; // Motor cut current scale V/A int i; int cutPower=0; // Cut Power from 0%=ESC_MIN_SIGNAL to 100%=ESC_MAX_SIGNAL int cutPower_uSec=ESC_MIN_SIGNAL; // Cut Power from ESC_MIN_SIGNAL to ESC_MAX_SIGNAL int oldSpeed=0; // Speed of mower (0-255) float IPanelMax=0; // IPanel max current unsigned long BWFL_count; unsigned long BWFR_count; unsigned long previousMillis = 0; unsigned long currentMillis; volatile int mowerStatus=0; // 0=oncharge (press pen for run) // 1=run // 2=stuck // 3=search // 4=batlow // 5=charge and restart when full // 6=cuterror volatile unsigned long wheelTime=0; // LCD does not send data back to the Arduino, only define the txPin SoftwareSerial LCD = SoftwareSerial(0, LCD_pin); int LCD_Page = 0; // Page to display SRF02 US_SX(US_SX_address, SRF02_CENTIMETERS); SRF02 US_DX(US_DX_address, SRF02_CENTIMETERS); void setup() { Serial.begin(9600); Wire.begin(); pinMode(Encoder_Pin, INPUT_PULLUP); pinMode(PWMA_pin, OUTPUT); pinMode(DIRA_pin, OUTPUT); pinMode(BWFR_pin, INPUT); pinMode(BWFL_pin, INPUT); pinMode(Panel_pin, OUTPUT); pinMode(ESC_pin, OUTPUT); pinMode(SWOR_pin, INPUT_PULLUP); pinMode(SWOL_pin, INPUT_PULLUP); pinMode(PWMB_pin, OUTPUT); pinMode(DIRB_pin, OUTPUT); pinMode(LCD_pin, OUTPUT); digitalWrite(DIRA_pin, LOW); digitalWrite(DIRB_pin, LOW); analogWrite(PWMA_pin, 0); analogWrite(PWMB_pin, 0); digitalWrite(Panel_pin, LOW); // For SerialMonitor diagnostic Serial.println("Solar Mower V1.0n"); Serial.println("Init ESC..."); ESC.attach(ESC_pin); cutOFF(); Serial.println("Init SerLCD..."); serLCDInit(); clearLCD(); lcdPosition(0,0); LCD.print("Solar Mower v1.0"); lcdPosition(1,0); LCD.print("Init..."); Serial.println("Init Sensor"); sensorInit(); Serial.print("IPanelOffset= "); Serial.println(IPanelOffset); Serial.print("ICutOffset= "); Serial.println(ICutOffset); Serial.println(); // TEST MOTOR if (Button(Button_pin)==PUP) { while(1) { clearLCD(); lcdPosition(0,0); LCD.print("Test motor"); lcdPosition(1,0); LCD.print("PEN begin test "); Serial.println("Press PEN for begin motor test"); while (Button(Button_pin)!=3) { } testMotor(); } } //TEST SENSOR if (Button(Button_pin)==PDW) { clearLCD(); lcdPosition(0,0); LCD.print("Test sensor"); Serial.println("Test sensor"); delay(1000); while(1) { sensorReading(); clearLCD(); lcdPosition(0,0); LCD.print("VB="); LCD.print(VBat); lcdPosition(0,9); if ((US_DX.read()>0) && (US_DX.read()<USdistance)) { LCD.print("UsDX "); Serial.println("UsDX"); } if ((US_SX.read()>0) && (US_SX.read()<USdistance)) { LCD.print("UsSX "); Serial.println("UsSX"); } if ( (BWFL_count>3000) && (BWFL_count<4000) ) { LCD.print("BWFL"); Serial.println("BWFL"); } if ( (BWFR_count>2000) && (BWFR_count<4000) ) { LCD.print("BWFR"); Serial.println("BWFR"); } if (digitalRead(Encoder_Pin)==0) { LCD.print("Encoder"); Serial.println("Encoder"); } if (digitalRead(SWOR_pin)==0) { LCD.print("SWOR"); Serial.println("SWOR"); } if (digitalRead(SWOL_pin)==0) { LCD.print("SWOL"); Serial.println("SWOL"); } if (Button(Button_pin)==1) { LCD.print("PUP"); Serial.println("PUP"); } if (Button(Button_pin)==2) { LCD.print("PDW"); Serial.println("PDW"); } if (Button(Button_pin)==3) { LCD.print("PEN"); Serial.println("PEN"); } lcdPosition(1,0); LCD.print("IC="); LCD.print(ICut); Serial.print("IC="); Serial.println(ICut); lcdPosition(1,9); LCD.print("IP="); LCD.print(IPanel); Serial.print("IP="); Serial.println(IPanel); delay(250); } } //TEST ESC if (Button(Button_pin)==PEN) { Serial.println("Test ESC..."); clearLCD(); lcdPosition(0,0); LCD.print("Test ESC"); while(1) { sensorReading(); cutPower = map(cutPower_uSec, ESC_MIN_SIGNAL, ESC_MAX_SIGNAL, 0, 100); lcdPosition(0,9); LCD.print("IC="); LCD.print(ICut); lcdPosition(1,0); LCD.print("cutPower="); LCD.print(cutPower); LCD.print("% "); Serial.print("cutPower="); Serial.print(cutPower); Serial.print("% usec="); Serial.println(cutPower_uSec); if (Button(Button_pin)==2) if (cutPower_uSec<ESC_MAX_SIGNAL) cutPower_uSec += 20; if (Button(Button_pin)==1) if (cutPower_uSec>ESC_MIN_SIGNAL) cutPower_uSec -= 20; ESC.writeMicroseconds(cutPower_uSec); delay(200); } } attachInterrupt(0, rotate, FALLING); } void loop() { //main program digitalWrite(Panel_pin, HIGH); main: //wait for PEN press while(Button(Button_pin)!=3) { currentMillis = millis(); if(currentMillis - previousMillis > timeClock) { sensorReading(); LCDdebug(); } } Serial.println("GO!"); mowerStatus=1; IPanelMax=0; LCDdebug(); cutON(); setMowerSpeed(255); //main loop while(1) { //ferma tutto if (Button(Button_pin)==PUP || Button(Button_pin)==PDW) { cutOFF(); setMowerSpeed(0); mowerStatus=0; goto main; } //if not an interrupt wheels occurs within 10 seconds, the robot is blocked if (millis()>wheelTime+10000) { cutOFF(); setMowerSpeed(0); mowerStatus=2; goto main; } // gestione sensori ostacolo if (digitalRead(SWOL_pin)==LOW) obstacleAvoidSX(); if (digitalRead(SWOR_pin)==LOW) obstacleAvoidDX(); // reads the sensors every timeClock currentMillis = millis(); if(currentMillis - previousMillis > timeClock) { previousMillis = currentMillis; sensorReading(); if ((US_DX.read()>0) && (US_DX.read()<USdistance)) { obstacleAvoidSX(); resetEncoder(); } if ((US_SX.read()>0) && (US_SX.read()<USdistance)) { obstacleAvoidDX(); resetEncoder(); } if ((BWFL_count>3000) && (BWFL_count<4000)) { obstacleAvoidSX(); resetEncoder(); } if ((BWFR_count>2000) && (BWFR_count<4000)) { obstacleAvoidDX(); resetEncoder(); } //********************************************************************** if (IPanel>IPanelMax) IPanelMax=IPanel; //memory to max current on panel //battery lower then 10% then searching the point to charge if (VBatPC<10) { mowerStatus=3; cutOFF(); //stop cut } //continues to advance until it finds a light source at least 80% of the previous maximum. if (mowerStatus==3) { if (IPanel>IPanelMax*0.8) { setMowerSpeed(0); mowerStatus=5; //charge with restart } } //********************************************************************** if (mowerStatus==5) { resetEncoder(); // full charge then restart if (VBatPC>=100) { mowerStatus=1; IPanelMax=0; cutON(); setMowerSpeed(255); } } if (VBat > VBat_Level_Max) { //lead battery never stop charge //disable charge only for lipo battery //digitalWrite(Panel_pin, LOW); } //battery is completely discharged if (VBat < VBat_Level_Min) { cutOFF(); setMowerSpeed(0); digitalWrite(Panel_pin, HIGH); mowerStatus=4; goto main; } // ICut too high if (ICut > ICut_Max) { cutOFF(); setMowerSpeed(0); digitalWrite(Panel_pin, HIGH); mowerStatus=6; goto main; } serialDebug(); LCDdebug(); } } } void rotate() { wheelTime=millis(); } void resetEncoder() //reset value for block wheels { wheelTime=millis(); } void obstacleAvoidSX() { // obstacle avoid setMowerSpeed(-PWMSpeed); delay(timeReverse); setMowerRotate(-PWMSpeed); //gira a sinistra delay(timeRotate); setMowerSpeed(PWMSpeed); } void obstacleAvoidDX() { // obstacle avoid setMowerSpeed(-PWMSpeed); delay(timeReverse); setMowerRotate(PWMSpeed); delay(timeRotate); setMowerSpeed(PWMSpeed); } void setMowerRotate(int newSpeed) { //rotate mower (first set speed at zero) constrain(newSpeed, -255, 255); for (i=oldSpeed; i>=0; i--) { analogWrite(PWMA_pin, i); analogWrite(PWMB_pin, i); delay(accelerateTime); } oldSpeed=0; if (newSpeed<0) { digitalWrite(DIRA_pin, HIGH); digitalWrite(DIRB_pin, LOW); newSpeed=-newSpeed; } else { digitalWrite(DIRA_pin, LOW); digitalWrite(DIRB_pin, HIGH); } for (i=0; i<=newSpeed; i++) { analogWrite(PWMA_pin, i); analogWrite(PWMB_pin, i); delay(accelerateTime); } oldSpeed=newSpeed; } void setMowerSpeed(int newSpeed) { //set new speed for mower (first set speed at zero) constrain(newSpeed, -255, 255); for (i=oldSpeed; i>=0; i--) { analogWrite(PWMA_pin, i); analogWrite(PWMB_pin, i); delay(accelerateTime); } oldSpeed=0; if (newSpeed<0) { digitalWrite(DIRA_pin, HIGH); digitalWrite(DIRB_pin, HIGH); newSpeed=-newSpeed; } else { digitalWrite(DIRA_pin, LOW); digitalWrite(DIRB_pin, LOW); } if (newSpeed > oldSpeed) { for (i=oldSpeed; i<=newSpeed; i++) { analogWrite(PWMA_pin, i); analogWrite(PWMB_pin, i); delay(accelerateTime); } } else { for (i=oldSpeed; i>=newSpeed; i--) { analogWrite(PWMA_pin, i); analogWrite(PWMB_pin, i); delay(accelerateTime); } } oldSpeed=newSpeed; } void cutON() { //cutter ON for (cutPower_uSec=ESC_MIN_SIGNAL; cutPower_uSec<=ESC_MAX_SIGNAL; cutPower_uSec += 10) { ESC.writeMicroseconds(cutPower_uSec); delay(50); } wheelTime=millis(); } void cutOFF() { //cutter OFF ESC.writeMicroseconds(ESC_MIN_SIGNAL); }
草圖被分為不同的文件,每個(gè)文件都有特定的用途,可以對(duì)功能進(jìn)行排序,使閱讀更容易;我們將在下面看到構(gòu)成草圖的文件。
文件configuration.h包含用于設(shè)置Arduino的工作參數(shù)和所有引腳分配的所有定義指令。在所有參數(shù)中,最重要的是:
ESC_MAX_SIGNAL 2000:它定義了與ESC最大功率相關(guān)的信號(hào)的持續(xù)時(shí)間(以微秒為單位),與切割發(fā)動(dòng)機(jī)的控制有關(guān)。
#定義ESC_MIN_SIGNAL 1000:它定義與ESC停止有關(guān)的信號(hào)的持續(xù)時(shí)間(以微秒為單位),與切割發(fā)動(dòng)機(jī)的控制有關(guān)。
#define VBat_Level_Min 9.0:它定義電池的最小電壓:在此值下,除太陽(yáng)能電池板充電外,所有割草機(jī)功能都將停用。
#定義VBat_Level_Max:它定義電池的最大電壓:超過(guò)該值,太陽(yáng)能電池板的充電將中斷。最小值和最大值也用于確定蓄電池充電水平。
#define ICut_Min:它定義切割引擎吸收的最小電流:低于該值時(shí)會(huì)產(chǎn)生警報(bào)。
#define ICut_Max:它定義切割引擎吸收的最大電流:超過(guò)該值,前進(jìn)速度會(huì)降低。
#define accelerateTime:它定義了分配給運(yùn)動(dòng)的發(fā)動(dòng)機(jī)的加速持續(xù)時(shí)間;總加速時(shí)間等于accelerateTime*255[msec]。
#定義Usdistance:檢測(cè)到障礙物并且機(jī)器人改變方向的距離(以厘米為單位)。
#定義時(shí)間反向:檢測(cè)到障礙物后,機(jī)器人反向運(yùn)動(dòng)的持續(xù)時(shí)間(以毫秒為單位)。
#define timeRotate:檢測(cè)到障礙物后,在修改行進(jìn)方向的操作過(guò)程中,機(jī)器人旋轉(zhuǎn)的持續(xù)時(shí)間(以毫秒為單位)。
SerLCD.ino文件包含LCD顯示器的初始化和控制功能。debug.ino文件包含機(jī)器人運(yùn)行過(guò)程中測(cè)量值在LCD顯示器上的初始化和可視化功能,還包含用于將測(cè)量數(shù)據(jù)發(fā)送到PC的功能。
sensor.ino文件包含讀取傳感器時(shí)使用的功能;為了便于比較,所有測(cè)量值都以安培和伏特為單位進(jìn)行轉(zhuǎn)換。特別有趣的是FreqCounter(int引腳,無(wú)符號(hào)長(zhǎng)gateTime)功能,它允許測(cè)量來(lái)自用于檢測(cè)地下線路的輸入的脈沖數(shù)量。
從用于檢測(cè)地下布線的電路獲得的方波信號(hào)僅在正確檢測(cè)到布線的情況下才呈現(xiàn)特定頻率。
參數(shù)gateTime顯示信號(hào)檢測(cè)的持續(xù)時(shí)間,也表示函數(shù)計(jì)數(shù)所需的時(shí)間,其默認(rèn)值為100msec。文件TestMotor.ino包含牽引發(fā)動(dòng)機(jī)測(cè)試過(guò)程中使用的功能。
對(duì)于割草機(jī)的每一項(xiàng)功能,都會(huì)在LCD顯示屏上進(jìn)行確認(rèn),并向PC發(fā)送等效消息:LCD顯示屏為數(shù)據(jù)管理提供了更大的便利,無(wú)需PC連接。
主程序包含在文件SolarMower.ino中:它監(jiān)督所有操作,并按正確順序調(diào)用所有功能。
一旦電氣部分完成,就需要正確驗(yàn)證功能和接線:為此,預(yù)先設(shè)置了三個(gè)特定的公用設(shè)施。我們要記住,割草的刀片非常危險(xiǎn),因此我們建議在結(jié)束所有測(cè)試之前移除刀片。
當(dāng)點(diǎn)火時(shí),或按下Arduino的重置按鈕時(shí),或當(dāng)重新啟動(dòng)串行監(jiān)視器時(shí)(如果連接到Arduino),固件將開(kāi)始其細(xì)化;作為第一次操作,它將驗(yàn)證是否按下了其中一個(gè)按鈕,在這種情況下,它將啟動(dòng)特定的設(shè)置程序,如下所示:
按下PUP按鈕,進(jìn)入傳感器測(cè)試;
按下PDW按鈕,進(jìn)入發(fā)動(dòng)機(jī)測(cè)試;
按下PEN按鈕,進(jìn)入ESC測(cè)試。
ESC測(cè)試程序允許校準(zhǔn)最大值和最小值;這不是一個(gè)編程順序,相反,它需要參考正在使用的ESC的特定手冊(cè)。
1斷開(kāi)切割刀片和ESC電源連接器。
2為割草機(jī)和ESC測(cè)試條目供電。
3使用PUP 100%=2000usec按鈕將cutPower設(shè)置為最大值
4為ESC供電,等待最大點(diǎn)的配置(您將聽(tīng)到特定的聲學(xué)信號(hào))。
5使用PDW按鈕將cutPower設(shè)置為最小值(您將聽(tīng)到特定的聲學(xué)信號(hào))。
6現(xiàn)在將完成校準(zhǔn)。電子穩(wěn)定控制系統(tǒng)將自動(dòng)設(shè)置最小值在10-30%范圍內(nèi),最大值在70-100%范圍內(nèi)的限值。通過(guò)操作PUP和PDW按鈕,可以修改cutPower的值,并驗(yàn)證電機(jī)是否正確運(yùn)行。
要驗(yàn)證運(yùn)動(dòng)發(fā)動(dòng)機(jī),啟動(dòng)發(fā)動(dòng)機(jī)測(cè)試程序:它將通過(guò)逐漸加速和減速依次啟動(dòng)兩個(gè)電機(jī)。然后,您必須驗(yàn)證旋轉(zhuǎn)方式是否與Arduino串行監(jiān)視器或LDC顯示器上顯示的信息一致:如果旋轉(zhuǎn)方式不同,則足以反轉(zhuǎn)發(fā)動(dòng)機(jī)的導(dǎo)線。您還必須驗(yàn)證DX引擎是否與正確的引擎匹配,反之亦然。
在啟動(dòng)傳感器測(cè)試程序之前,我們必須討論超聲波傳感器:由于它們都連接到同一個(gè)I2C總線,因此需要用不同的地址對(duì)其中一個(gè)進(jìn)行編程。傳感器屬于SRF02類型,在銷售時(shí)分配了值地址HEX0x70。因此,如果連接到同一個(gè)總線,剛剛購(gòu)買的兩個(gè)傳感器將發(fā)生沖突。我們將保留左側(cè)傳感器的默認(rèn)地址0x70,并修改右側(cè)傳感器的地址。
要做到這一點(diǎn),請(qǐng)將屏蔽單獨(dú)連接到右側(cè)傳感器,并打開(kāi)SRF02_address.ino樣本,該樣本包含在SRF02庫(kù)中,與本文的文件一起提供,然后將其加載到Arduino上;地址將被自動(dòng)修改。您可以使用庫(kù)中包含的示例程序來(lái)驗(yàn)證地址的更改是否正確。
通過(guò)啟動(dòng)傳感器測(cè)試程序,您將有機(jī)會(huì)驗(yàn)證所有輸入外圍設(shè)備是否正確運(yùn)行;在LCS顯示器(如果可用)和串行監(jiān)視器(如果連接到Arduino)上,都可以看到從當(dāng)前傳感器獲取的數(shù)據(jù)、數(shù)字條目的值以及檢測(cè)到的障礙物的存在與否。
一旦確定一切正常,您可以進(jìn)行第一次現(xiàn)場(chǎng)測(cè)試:按下主屏幕上的PEN按鈕即可啟動(dòng)割草機(jī),同時(shí)按下PUP和PDW兩個(gè)按鈕之一即可立即停止。
無(wú)論如何,在提起或操作割草機(jī)之前,我們建議通過(guò)總開(kāi)關(guān)將其關(guān)閉:只有這樣,您才能保證任何機(jī)制都不會(huì)開(kāi)始工作。
在不輸入整個(gè)固件的詳細(xì)信息的情況下,現(xiàn)在讓我們看看在第一個(gè)versoin中實(shí)現(xiàn)的基本行;其思想是實(shí)現(xiàn)有限狀態(tài)自動(dòng)機(jī),其操作狀態(tài)存儲(chǔ)在割草機(jī)狀態(tài)變量中。
當(dāng)狀態(tài)變量取值為0時(shí),顯示屏上將顯示CHARGE(充電)字樣:這是點(diǎn)火后不久的初始狀態(tài),機(jī)器人仍在充電,等待按下PEN引導(dǎo)按鈕。
當(dāng)狀態(tài)變量的值為1時(shí),顯示屏上將顯示RUN(運(yùn)行)字樣:這是主要狀態(tài),機(jī)器人正在割草,同時(shí)驗(yàn)證是否存在障礙物。在這種情況下,將啟動(dòng)一個(gè)簡(jiǎn)單的程序,該程序?qū)⑿薷男旭偡较颉?/p>
當(dāng)狀態(tài)變量的值為2時(shí),顯示器上將顯示單詞STUCK:在這種狀態(tài)下,機(jī)器人被卡住了。由于后輪停止轉(zhuǎn)動(dòng)并且沒(méi)有向板發(fā)出任何信號(hào),因此檢測(cè)到了這種情況。
當(dāng)狀態(tài)變量取值3時(shí),顯示屏上將顯示單詞SEARCH:在這種狀態(tài)下,電池電量接近低,切割發(fā)動(dòng)機(jī)停止,機(jī)器人尋找發(fā)光的地方為自己充電。
當(dāng)狀態(tài)變量的值為4時(shí),顯示屏上將顯示單詞BATLOW:在這種狀態(tài)下,電池電量不足,無(wú)法找到令人滿意的充電位置。甚至牽引電機(jī)也被停止,機(jī)器人仍處于充電模式。
當(dāng)狀態(tài)變量取值5時(shí),顯示屏上將顯示CHARGE RS字樣:在這種狀態(tài)下,機(jī)器人處于充電位置,一旦電池完全充電,機(jī)器人將準(zhǔn)備再次啟動(dòng)。
當(dāng)狀態(tài)變量的值為6時(shí),顯示器上將顯示單詞CUTERROR:在這種狀態(tài)下,機(jī)器人靜止不動(dòng),因?yàn)樗鼨z測(cè)到切割發(fā)動(dòng)機(jī)電流吸收異常。
為地下線路供電的電路
如前所述,地下布線需要形成一個(gè)閉環(huán),并由頻率為34Khz的交流信號(hào)供電。要做到這一點(diǎn),需要一個(gè)非常簡(jiǎn)單的不穩(wěn)定電路。它是用一個(gè)NE555集成電路和幾個(gè)更多的組件創(chuàng)建的;該電路與以前的版本相同,并計(jì)算到具有9伏次級(jí)的變壓器的連接,該變壓器又以220Vac連接到電網(wǎng)。
然而,根據(jù)該項(xiàng)目背后的理念,建議使用小型太陽(yáng)能電池板和緩沖電池,從電網(wǎng)中獨(dú)立供電。太陽(yáng)能電池板將是電路的主要電源,而12V電池(與C1電容器并聯(lián))將是在陽(yáng)光照射不足的情況下的主要電源。橋式整流器的存在將防止電池張力在低陽(yáng)光暴露期間進(jìn)入太陽(yáng)能電池板。為了正確平衡系統(tǒng),需要確保在夜間電池能夠?yàn)殡娐饭╇姸粫?huì)電量過(guò)低,而太陽(yáng)能電池板必須能夠?yàn)殡娐烦潆?,同時(shí)在白天為電池充電。
該系統(tǒng)與花園中的太陽(yáng)能燈沒(méi)有什么不同,它們不需要連接到家庭網(wǎng)絡(luò)的電線。地下布線將形成一個(gè)封閉的環(huán),以標(biāo)記割草機(jī)工作區(qū)域的界限。由于車載傳感器,該區(qū)域內(nèi)的任何其他障礙物都將得以避免。
唯一要進(jìn)行的校準(zhǔn)涉及發(fā)送到地下線路的信號(hào)的頻率調(diào)節(jié):將電纜靠近BWF傳感器的卷軸并旋轉(zhuǎn)微調(diào)器就足夠了,直到獲得盡可能好的讀數(shù)(為此,使用傳感器測(cè)試程序)。
BOM
R1: 3,3 kohm
R2: 12 kohm
R3: 100 ohm
R4: 4,7 kohm MV
C1: 1.000 μF 35 VL
C2, C4: 100 nF
C3: 1,2 nF 63 VL
C5: 1 μF 63 VL
PT1: W06M
U1: NE555
機(jī)械設(shè)計(jì)
評(píng)論