1. 程式人生 > >Android手機控制樹莓派製作的四驅小車

Android手機控制樹莓派製作的四驅小車

-------更新

完整的程式碼放在Github上了:

-------全文

年初的時候看到使用樹莓派製作的遠端開門器》後,覺得硬體程式設計似乎沒有想象的難。 之前認為硬體程式設計可能需要學習新的程式語言,需要特別的程式設計環境。然而樹莓派使用Linux作業系統環境,只要Linux支援的程式語言 ,都可以成為你的選擇。當語言環境不是問題的時候,對於我來說,我最感興趣的部分是如何用樹莓派來控制一些低速的外部裝置,例如 :繼電器、小馬達。 一般的PC並不提供這些通用介面,PC只提供一些高速裝置的介面如USB。 而樹莓派不止提供了USB介面,還提供了GPIO介面,有了這個介面使得控制通用的外部裝置得以實現。

  1. import RPi.GPIO as GPIO  
  2. GPIO.setup(7, GPIO.OUT)  
  3. GPIO.output(7True)  
  4. GPIO.output(7,False)  

程式碼中樹莓派通過指定GPIO介面向外部發送訊號,如果從外部向樹莓派輸入訊號,則指定GPIO.input。整個小車需要的部件就是四個輪子,可以單獨控制,所以下面我們只說說如何來控制其中的一個電機。 

接通VCC,GND 模組電源指示燈亮  

IA1輸入高電平,IA1輸入低電平,【OA1 OB1】電機正轉;

IA1輸入低電平,IA1輸入高電平,【OA1 OB1】電機反轉;

IA2

輸入高電平,IA2輸入低電平,【OA2 OB2】電機正轉;

IA2輸入低電平,IA2輸入高電平,【OA2 OB2】電機反轉;

為了簡化電路設計,考慮用驅動模組控制。這是我在淘寶購買的兩路電機驅動 H橋 L9110 電機驅動模組 ,接上它,你只需要下面簡單的連線,就可以讓樹莓派來控制電機了。驅動模組有電源、訊號輸入介面以及電源輸出介面:

  • 電源輸入,VCC,GND分別是輸入電源的正負極,可以用電池組來供電。 注意不能接反,否則驅動模組可能短時間內發燙,甚至燒壞。
  •  訊號輸入,IA1 IB1, IA2 IB2分別是兩對訊號輸入介面,接受來自樹莓派訊號的控制驅動模組的電源輸出,達到電機正轉反正的目的。
  • 電源輸出,電源輸出介面OA1 OB1,OA2 OB2 (綠色部分)分別是兩對輸出電流到電機的介面,通過他們為電機供電。
  • 當你連線好這些介面後,模組上的連線也就全部完成了,接下來就要把模組上的IA1 IB1, IA2 IB2連線到樹莓派程式指定的GPIO。


BOARD模式下的介面定義

第二部分:連線GPIO

要使用樹莓派為GPIO提供連個設定模式,BOARD和BCM, 模式的不同GPIO的每一個介面的定義也不同(上圖是BOARD模式下的定義),使用時必須在程式碼中必須明確指定他的模式:

  1. import RPi.GPIO as GPIO  #GPIO package
  2. GPIO.setmode(GPIO.BOARD) #設定模式
  3. GPIO.setup(13, GPIO.OUT) #指定介面是輸出還是輸入
  4. GPIO.setup(15, GPIO.OUT) #指定介面是輸出還是輸入
  5. GPIO.output(13, GPIO.HIGH) #輸出高電平
  6. GPIO.output(15, GPIO.LOW) #輸出低電平
這六行就是要讓一個電機轉起來的全部程式碼。程式碼中的指定了13 和15兩個輸出介面為驅動模組提供控制訊號。我們要做的是在上圖中找到這兩個GPIO,把它們連線到IA1和IB1, 這個時候執行程式,電機轉動。

當然,為程式碼更好讀,可以專門寫一個Wheel類來控制輪子。單個輪子只有三個操作, 前進、後退、停止,現在來封裝這些操作:

第三部分:封裝輪子

  1. class Wheel:  
  2.     pins ={'a':[13,15],'b':[16,18],'c':[19,21],'d':[22,24]}# 這裡指定了四個輪子所使用的8個GPIO介面
  3.     def __init__(self,name):  
  4.         self.name = name  
  5.         self.pin = Wheel.pins[self.name]  
  6.         GPIO.setmode(GPIO.BOARD)  
  7.         GPIO.setup(self.pin[0],GPIO.OUT)  
  8.         GPIO.setup(self.pin[1],GPIO.OUT)  
  9.         self.stop()  
  10.     def forward(self):  
  11.         GPIO.output(self.pin[0],GPIO.HIGH)  
  12.         GPIO.output(self.pin[1],GPIO.LOW)  
  13.     def stop(self):  
  14.         GPIO.output(self.pin[0],False)  
  15.         GPIO.output(self.pin[1],False)  
  16.     def back(self):  
  17.         GPIO.output(self.pin[0],False)  
  18.         GPIO.output(self.pin[1],True)  
於是你就可以簡單的使用一下一行程式碼達到之前六行程式碼的功能:
  1. Wheel('a').forward() #a,b,c,d是四個輪子的名字

通過呼叫每個Wheel例項,可以對他們自由操作。由於整個車是由四個輪子協同來工作的,我們需要同時來讓四個輪子一起工作,對此對這種協同工作進行封裝,讓我們不必在關心怎樣驅動4個輪子就可以前進了:

第四部分: 封裝車子

我們希望車子能夠前進、後退、左轉、右轉,於是可以這樣來封裝一下程式碼:

  1. class Car:   
  2.     wheels=[Wheel('a'),Wheel('b'),Wheel('c'),Wheel('d')]   
  3.     @staticmethod
  4.     def init():  
  5.         GPIO.setmode(GPIO.BOARD)  
  6.     @staticmethod
  7.     def forward():  
  8.         for wheel in Car.wheels:  
  9.             wheel.forward()  
  10.        @staticmethod
  11.     def back():  
  12.         for wheel in Car.wheels:  
  13.             wheel.back()  
  14.     @staticmethod
  15.     def left():  
  16.         Car.wheels[0].forward()   
  17.         Car.wheels[1].forward()  
  18.         Car.wheels[3].back()  
  19.         Car.wheels[2].back()  
  20.     @staticmethod
  21.     def right():  
  22.         Car.wheels[2].forward()   
  23.         Car.wheels[3].forward()  
  24.         Car.wheels[0].back()  
  25.         Car.wheels[1].back()  
  26.     @staticmethod
  27.     def stop():  
  28.         Car.wheel[0].stop()   
  29.         Car.wheel[1].stop()   
  30.         Car.wheel[3].stop()  
  31.         Car.wheel[2].stop()  


Car是一個靜態類,它提供的五個方式分別對應到小車的前、後、左、右、停。現在我們考慮遠端遙控小車,因此小車必須提供和外部遙控裝置的通訊介面:

第五部分:通訊程式

小車和外界的通訊方式其實很多,紅外、藍芽、Wifi等等。根據我的裝置清單我就選擇了Wifi的方式,所以使用socket作為介面最直接不過了:

  1. rom socket import *  
  2. import sys  
  3. import time  
  4. import car  
  5. commands ={'forward':Car.forward,  
  6.   'back':Car.back,   
  7.   'stop':Car.stop,  
  8.   'left':Car.left,  
  9.   'right':Car.right  
  10. }  
  11. def execute(command):     
  12.     print command  
  13.     commands[command]()  
  14. HOST ='192.168.2.101'#the ip of rapberry pi
  15. PORT = 8888
  16. s= socket(AF_INET, SOCK_STREAM)  
  17. s.bind((HOST, PORT))  
  18. s.listen(1)  
  19. print ('listening on 8888')  
  20. while1:  
  21.     conn, addr = s.accept()  
  22.     print ('Connected by:', addr)  
  23.     while1:  
  24.             command= conn.recv(1024).replace('\n','')  
  25.             ifnot command:break
  26.             execute(command)  
  27.     conn.close()  

> sudo python server.py 之後,樹莓派會監聽8888埠一旦有訊息傳遞過來,根據命令引數呼叫相應的方法。小車的服務端介面就相當一個執行者,接受到命令就立刻執行,此次只要可以建立和小車的socket連線,便可以輕鬆控制,我們打算用Android手機來發送這個訊息:

第六部分: Android手機操作小車

通過手機來操作,實際上就通過socket和樹莓派進行通訊,當樹莓派處於listening狀態,對於手機來說,它要做的最重要的事情就是傳送訊息到樹莓派,一個小車的指揮者:

  1. package com.simplexk;  
  2. import java.io.PrintWriter;  
  3. import java.net.Socket;  
  4. publicclass Commander {  
  5.     publicstatic String HOST ="192.168.2.101"//the ip of raspberry pi 
  6.     publicstaticint PORT =8888;  
  7.     publicstaticvoid send(Command forward) throws Exception {  
  8.             Socket socket = new Socket(HOST, PORT);  
  9.             PrintWriter writer = new PrintWriter(socket.getOutputStream());  
  10.             writer.println(forward.toString());  
  11.             writer.flush();  
  12.             socket.close();  
  13.     }  
  14. }  

 當然這僅僅是手機向樹莓派發送訊息的部分,手機發送什麼的命令,你還需要程式設計額外的使用者介面程式來完成。最簡單的,你可以放上四個按鈕來操作小車的四個運動方向。


---------------結束---------------