Android手机控制树莓派制作的四驱小车

来源:互联网 发布:有机玻璃 亚克力 知乎 编辑:程序博客网 时间:2024/05/01 05:54

-------更新


完整的代码放在Github上了:

服务端:https://github.com/darlinglele/raspberry-server

手机客户端: https://github.com/darlinglele/raspberry-client


-------全文

年初的时候看到@段念-段文韬 的这篇文章《使用树莓派制作的远程开门器》后,觉得硬件编程似乎没有想象的难。 之前认为硬件编程可能需要学习新的编程语言,需要特别的编程环境。然而树莓派使用Linux操作系统环境,只要Linux支持的编程语言 ,都可以成为你的选择。当语言环境不是问题的时候,对于我来说,我最感兴趣的部分是如何用树莓派来控制一些低速的外部设备,例如 :继电器、小马达。 一般的PC并不提供这些通用接口,PC只提供一些高速设备的接口如USB。 而树莓派不止提供了USB接口,还提供了GPIO接口,有了这个接口使得控制通用的外部设备得以实现。

开始之前,请用最方便的方式连入树莓派。我自己没有额外的显示器,所以只好通过MBA的Terminal直接SSH上去。 树莓派预装了Python,但是你需要安装RPI GPIO python来驱动GPIO。安装包地址:http://log.liminastudio.com/writing/tutorials/tutorial-how-to-use-your-raspberry-pi-like-an-arduino 。安装之后,在程序中import就可以控制GPIO:

[python] view plain copy
 在CODE上查看代码片派生到我的代码片
  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模式下的定义),使用时必须在代码中必须明确指定他的模式:

[python] view plain copy
 在CODE上查看代码片派生到我的代码片
  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类来控制轮子。单个轮子只有三个操作, 前进、后退、停止,现在来封装这些操作:

第三部分:封装轮子

[python] view plain copy
 在CODE上查看代码片派生到我的代码片
  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)  
于是你就可以简单的使用一下一行代码达到之前六行代码的功能:

[python] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. Wheel('a').forward() #a,b,c,d是四个轮子的名字  

通过调用每个Wheel实例,可以对他们自由操作。由于整个车是由四个轮子协同来工作的,我们需要同时来让四个轮子一起工作,对此对这种协同工作进行封装,让我们不必在关心怎样驱动4个轮子就可以前进了:


第四部分: 封装车子

我们希望车子能够前进、后退、左转、右转,于是可以这样来封装一下代码:

[python] view plain copy
 在CODE上查看代码片派生到我的代码片
  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.  
  15.  
  16.     @staticmethod  
  17.     def left():  
  18.         Car.wheels[0].forward()   
  19.         Car.wheels[1].forward()  
  20.         Car.wheels[3].back()  
  21.         Car.wheels[2].back()  
  22.     @staticmethod  
  23.     def right():  
  24.         Car.wheels[2].forward()   
  25.         Car.wheels[3].forward()  
  26.         Car.wheels[0].back()  
  27.         Car.wheels[1].back()  
  28.     @staticmethod  
  29.     def stop():  
  30.         Car.wheel[0].stop()   
  31.         Car.wheel[1].stop()   
  32.         Car.wheel[3].stop()  
  33.         Car.wheel[2].stop()  


Car是一个静态类,它提供的五个方式分别对应到小车的前、后、左、右、停。现在我们考虑远程遥控小车,因此小车必须提供和外部遥控设备的通信接口:


第五部分:通信程序

小车和外界的通信方式其实很多,红外、蓝牙、Wifi等等。根据我的设备清单我就选择了Wifi的方式,所以使用socket作为接口最直接不过了:

[python] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. rom socket import *  
  2. import sys  
  3. import time  
  4. import car  
  5.   
  6. commands ={'forward':Car.forward,  
  7.   'back':Car.back,   
  8.   'stop':Car.stop,  
  9.   'left':Car.left,  
  10.   'right':Car.right  
  11. }  
  12.   
  13. def execute(command):     
  14.     print command  
  15.     commands[command]()  
  16.   
  17. HOST ='192.168.2.101' #the ip of rapberry pi  
  18. PORT = 8888  
  19. s= socket(AF_INET, SOCK_STREAM)  
  20. s.bind((HOST, PORT))  
  21. s.listen(1)  
  22. print ('listening on 8888')  
  23. while 1:  
  24.     conn, addr = s.accept()  
  25.     print ('Connected by:', addr)  
  26.     while 1:  
  27.             command= conn.recv(1024).replace('\n','')  
  28.             if not command:break  
  29.             execute(command)  
  30.     conn.close()  

> sudo python server.py 之后,树莓派会监听8888端口一旦有消息传递过来,根据命令参数调用相应的方法。小车的服务端接口就相当一个执行者,接受到命令就立刻执行,此次只要可以建立和小车的socket连接,便可以轻松控制,我们打算用Android手机来发送这个消息:

第六部分: Android手机操作小车

通过手机来操作,实际上就通过socket和树莓派进行通信,当树莓派处于listening状态,对于手机来说,它要做的最重要的事情就是发送消息到树莓派,一个小车的指挥者:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. package com.simplexk;  
  2. import java.io.PrintWriter;  
  3. import java.net.Socket;  
  4.   
  5. public class Commander {  
  6.     public static String HOST ="192.168.2.101"//the ip of raspberry pi   
  7.     public static int PORT =8888;  
  8.     public static void send(Command forward) throws Exception {  
  9.             Socket socket = new Socket(HOST, PORT);  
  10.             PrintWriter writer = new PrintWriter(socket.getOutputStream());  
  11.             writer.println(forward.toString());  
  12.             writer.flush();  
  13.             socket.close();  
  14.     }  
  15. }  

 当然这仅仅是手机向树莓派发送消息的部分,手机发送什么的命令,你还需要编程额外的用户接口程序来完成。最简单的,你可以放上四个按钮来操作小车的四个运动方向。


---------------结束---------------

0 0
原创粉丝点击