实现的功能有:
1.实现小车的前进,后退,左转,右转。
2.实时视频的传回,查看小车周围的情况。
3.摄像头的上下左右转动,使用舵机云台来实现。
需要的材料:
1.树莓派一个(带有python环境,现在的好像都有自带python环境)。
2.安卓手机一部,用于安装写的APP。
3.杜邦线若干。
4.L298N电机驱动模块(某宝9块钱一个)。
5.舵机云台一个(某宝有卖散件,买来自己装,20几块钱)。
6.车架一个(同样某宝…).
7.充电宝一个,用于树莓派供电,和L298N电机驱动模块供电,虽然L298N标的是12V的电源,但是5V也能使用。
8.电脑一台。
首先要实现手机app与树莓派的通信,这样才能实现对树莓派小车的控制。首先想到的就是socket通信,简单易懂,但是写的时候还是遇见了很多的问题,下面会说到。
这篇文章只介绍实现app控制小车的前进后退左转右转。
整体的思路就是:手机app向树莓派发送不同的指令,树莓派根据不同的指令进行指定的相应,来控制车体的运动。
一、车体的组装以及连线这里就不仔细介绍了,这种东西还是比较简单的。要注意的是将从树莓派引出的GPIO引脚要记好,编程的时候还要用。其中L298N驱动的作用就是来为带动小车运动的电机提供足够的电源。
二、下面就是app进行编程了,这里使用的是Android studio,如何安装,与配置环境百度一下都有,这里就不介绍了。下面拿控制小车前进作为一个例子进行解释一下:
@Override
public void onClick(View v)
{
if (v.getId() == R.id.forward)
{
forward.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent)
{
//抬起操作
if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
sendRequestWithHttpURLConnection1();
}
//按下操作
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
sendRequestWithHttpURLConnection();
}
//移动操作
if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
}
return false;
}
});
}
}
上面的代码是来监控你在app中按下了那个按键,如果是前进键,按下时调用sendRequestWithHttpURLConnection()函数向树莓派发送指令,抬起按键时向树莓派在此发送指令。
其中sendRequestWithHttpURLConnection()这个函数很重要,在写时遇到了很多的问题,主要就是在UI线程和通信socket线程的处理上,UI线程中不能使用socket通信必须要重新创建一个线程来进行通信。
重点内容
private void sendRequestWithHttpURLConnection()
{
new Thread(new Runnable()
{
@Override
public void run() {
int PORT = 1;
InetAddress addr = null;
try
{
addr = InetAddress.getByName("192.168.31.6");//此处是树莓派的IP地址。
}
catch (UnknownHostException e)
{
e.printStackTrace();
}
Socket socket = new Socket();
try
{
socket.connect(new InetSocketAddress(addr, PORT), 30000);
socket.setSendBufferSize(100);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
out.write("forward");
out.flush();
}
catch (SocketException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
StringBuilder response = new StringBuilder();
String line="Iot";
response.append(line);
showResponse(response.toString());
}
finally
{
try
{
socket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}).start();
}
上面的代码就是socket编程的关键所在,这只是前进指令的发送代码,还有其他的指令的发送代码,几乎都是相同的,只是把write()括号中的内容改一下就行了。每次按下一个按键,就发送一个指令,使得树莓派的GPIO改变状态。每次抬起按键都发送停止的指令,使得小车停下来。
三、树莓派部分的代码
树莓派的代码使用python写的,它的作用是来对手机发送来的指令进行处理。
分为两部分,一部分是用来封装小车的控制代码,一部分是用来识别接收到的指令,调用第一部分的代码。
第一部分代码:
重点内容
import threading
import RPi.GPIO as GPIO
import time
class Info:
@staticmethod
def p(message):
print 'Info: '+message
class Wheel:
pins ={'a':[13,15],'b':[16,18]}
def __init__(self,name):
self.name = name
self.pin = Wheel.pins[self.name]
GPIO.setmode(GPIO.BOARD)
GPIO.setup(self.pin[0],GPIO.OUT)
GPIO.setup(self.pin[1],GPIO.OUT)
self.stop()
def st(self):
print 'ss'
def forward(self):
Info.p('wheel ' + self.name + ' is forwarding')
GPIO.output(self.pin[0],GPIO.HIGH)
GPIO.output(self.pin[1],GPIO.LOW)
def stop(self):
GPIO.output(self.pin[0],False)
GPIO.output(self.pin[1],False)
def back(self):
Info.p('wheel ' +self.name + ' is backing')
GPIO.output(self.pin[0],False)
GPIO.output(self.pin[1],True)
class Car:
wheel=[Wheel('a'),Wheel('b'),Wheel('c'),Wheel('d')]
@staticmethod
def init():
GPIO.setmode(GPIO.BOARD)
Info.p('initialize the smart car ....')
Info.p('Smart car is ready to fly!')
@staticmethod
def forward():
Info.p('go straight forward')
for wheel in Car.wheel:
wheel.forward()
@staticmethod
def left():
Info.p('turn left ')
Car.wheel[0].forward()
Car.wheel[1].back()
@staticmethod
def right():
Info.p('turn left ')
Car.wheel[0].back()
Car.wheel[1].forward()
@staticmethod
def bleft():
Info.p('turn left ')
Car.wheel[2].back()
@staticmethod
def stop():
Info.p('turn left ')
Car.wheel[0].stop()
Car.wheel[1].stop()
@staticmethod
def back():
Info.p('go straight back')
for wheel in Car.wheel:
wheel.back()
@staticmethod
def lforward():
Info.p('go forward and turn left')
@staticmethod
def rforward():
Info.p('go forward and turn right')
@staticmethod
def lback():
Info.p('go back and turn left')
@staticmethod
def rback():
Info.p('go back and turn right')
@staticmethod
def stop():
Info.p('try to stop the car ...')
for wheel in Car.wheel:
wheel.stop()
@staticmethod
def bark():
Info.p('try to slow down the car ...')
@staticmethod
def speedup():
Info.p('try to speed up the car ...')
if __name__ =='__main__':
print '....'
第二部分代码:
```python
from socket import *
import sys
import time
from car import *
def run_raspberry():
commands ={'forward':Car.forward,'back': Car.back, 'stop': Car.stop,'left': Car.left,'right': Car.right}
PORT = 1
s= socket(AF_INET, SOCK_STREAM)
s.bind(("", PORT)) #对所有的ip都能接收。
s.listen(1)
print ('raspberry pi is listening on port 8888')
while 1:
conn, addr = s.accept()
print ('Connected by:', addr)
while 1:
command= conn.recv(1024).replace('\n','')
if not command or command not in commands:break
commands[command]()
conn.close()
if __name__ == '__main__':
run_raspberry()
```
只需运行run_raspberry.py这个代码就可以了。
后续功能的实现,将在后面的博客中更新。
参考了一下这个博客:
http://blog.csdn.net/AMDS123/article/details/70595127?locationNum=2&fps=1