|
作者:付千山
链接:https://zhuanlan.zhihu.com/p/24594614
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
一、功能介绍
最近完成一个Raspberry局域网视频小车项目,特此拿出来分享!
首先来介绍小车的情况,Raspberry首先担任一个服务器兼控制中心的角色,用户通过局域网查看监控视频以及发指令给Raspberry,然后Raspberry通过串口通信发指令给Arduino控制小车电机和舵机移动。
根据上述描述,我们可以把项目分为以下几部分:
1.Raspberry搭建服务器
2.搭建VNC远程桌面
3.视频流的传输
4.Raspberry-Arduino的串口通信
5.Arduino的电机与舵机控制
接下来,我会根据以上部分详细介绍每一步!至于安装系统,连接互联网等一些基本步骤就不在这介绍了。
二、搭建vnc远程桌面
因为我们这个项目需要在python编程,为了方便,所以搭建一个vnc服务器,在pc端远程连接树莓,以远程操控树莓。
首先,在树莓上安装vnctight:
sudo apt-get update
sudo apt-get install tightvncserver
安装完后,运行命令开启vnc服务器:
vncserver :1
或者设定特定屏幕分辨率:
vncserver :1 -geometry 1440x900
首次使用会提示你设置密码,那个是远程登录时要用到。
在树莓端开启vnc后,在pc端下载TightVnc Viewer远程登录,效果如图:
相关资料可以参考:VNC简明指南
三、Raspberry搭建服务器
首先,为什么要搭建服务器呢?因为我需要在局域网上控制小车的移动,所以就需要向Raspberry发送网络请求,Raspberry需要实时监控并接收网络请求,然后执行相对应的动作。
下面资料一切都是为了讲明白如何在局域网中向Raspberry发送指令,不要乱了思路!
我这次搭建服务器用了Python的Flask模板,这个模板简单且易入手,不用深入理解TCP/IP等一大堆令人头痛的协议也可操作。下面,介绍一下,怎么使用:
3.1在使用该模板前,需要在树莓上下载Python的Flask模板
sudo apt-get install python3-flask
3.2Flask搭建服务器
#flask_hello.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'Hello world'
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0',port=5000)
在以上例程中:
host='0.0.0.0':代表服务器接收局域网一切对象的访问 port=5000则代表端口值
试着在Python上运行这一段代码,你会看到输出有:
* Running on http://0.0.0.0:5000/
* Restarting with reloader
此时,你的电脑只要在局域网中访问
http://树莓ip:5000/
就可以看到收到相对应的数据:
3.2.1路径设置:
当你回顾刚才那段代码时,你会发现有这么一段程序:
@app.route('/')
def index():
return 'Hello world'
上面代码是路径设置,如果你想通过打开不同的路径显示不同的内容,你可以尝试在该代码下面加:
@app.route('/cakes')
def cakes():
return 'Yummy cakes!'
访问下面的网址:
所以我们可以知道@app.route('/XXX')里面XXX是路径名,当你访问不同的路径时,你可以通知Raspberyy执行不同的动作!
学到这里,来拓展一下路径参数,这个很重要,看下例程:
@app.route('/<name>')
def cakes(name):
return name;
以上例程把路径名作为输入参数,当路径为XXX时,Raspberry就会返回对应的值,看结果:
3.2.2建立网页
首先在程序模板的目录下建立templates文件夹
mkdir templates
接着在该目录下新建一个index.html格式的空文件,并用Text Editor编辑,在该文件下植入以下代码:
<html>
<body>
<h1>Hello from a template!</h1>
</body>
</html>
将主页路径触发事件改为:
@app.route('/')
def index():
return render_template('index.html')
同时,也要记得引入render_template模板:
from flask import Flask,render_template
当你打开主页时,你会看到:
说到这里,之前我们学了flask模板的路径设置以及网页制作,我是在局域网中通过点击网页指令来控制小车移动的,下面来说明一下如何做到这一点?
First,构建指令链接:
在你的网页.html文件中,尝试加以下语句:
<!DOCTYPE html>
<head>
<title>Rotbot_Car</title>
</head>
<body>
<br><a href="/forward">前进</a></br>
<br><a href="/back">后退</a></br>
<br><a href="/left">左转</a></br>
<br><a href="/right">右转</a></br>
</body>
</html>
对于上面的代码只说一点关于href的,href用于指定超链接目标的URL,比如说
<br><a href="/forward">前进</a></br>
上面指定超链接目标的URL为:
http://主域名/forward
具体运行结果为:
当你点击不同的选项时,便会跳转到对应的URL中!
Second,获取路径名参数来指挥Raspberry工作:
在上面网页程序的基础上继续操作,当点击不同指令时,Raspberry会收到不同路径名的跳转请求,所以我们就用路径设置的方法,根据路径名的类别来判断用户指令是什么,从而执行相对应的操作!
下面是程序的一个雏形!
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template(index.html)
@app.route('/<name>')
def index(name):
if(name == 'forward'):
%发送前进指令给Arduino
if(name == 'back'):
%发送后退指令给Arduino
if(name == 'left'):
%发送左转指令给Arduino
if(name == 'right'):
%发送右转指令给Arduino
return render_template(index.html)
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')
到这里,想必大家已经知道如何构建服务器实时获取用户控制小车的指令了吧!
相关资料可以参考:python-web-server-with-flask
Raspberry-Pi-Flask
四、视频流的传输
说下我用到的摄像头,Raspberry官方的摄像头,是一鱼眼摄像头,额外买红外灯的话,还会有夜视的功能,在京东淘宝都可以买到,在这我就不自行打广告了。
为了能使用户从局域网观看小车摄像头拍到的视频,raspberry需要把视频流传输到局域网上去,在这里,我们采用mjpg-streamer的方案,它是github上一个开源项目,有关介绍,可以参考:mjpg-streamer介绍
首先,把开源代码下载到树莓上:
pi@raspberrypi:~ $ wget https://github.com/jacksonliam/mjpg-streamer/archive/master.zip
接着,在树莓上编译工具安装好:
pi@raspberrypi:~ $ sudo apt-get install cmake libjpeg8-dev
解压下载好的压缩文件:
pi@raspberrypi:~ $ unzip master.zip
修改视频传输参数:
设置视频传输参数的input_raspicam.c文件在以下目录中,:
mjpg-streamer-master/mjpg-streamer-experimental/plugins/input_raspicam
具体代码如下:
为了保障视频传输流畅,建议把fps调到30左右较好!
编译程序:
pi@raspberrypi:~ $ cd mjpg-streamer-master/mjpg-streamer-experimental
pi@raspberrypi:~ $ make clean all
制作mjpg的启动脚本
新建一个.sh格式文件xx.sh,并进行编辑。
pi@raspberrypi:~ $ nano xx.sh
将以下内容复制到xx.sh文件中:
cd mjpg-streamer-master/mjpg-streamer-experimental
./mjpg_streamer -i "./input_raspicam.so" -o "./output_http.so -w ./www"
生成启动脚本
chmod 744 xx.sh
以后只要执行上面生成的启动脚本,就可以启动mjpg很方便,启动指令为:
sh xx.sh
观看视频:
启动了mjpg后,在pc端访问以下网址即可观看视频:
http://the ip of raspberry:8080
总的来说很简单,就是把源文件下载到树莓上,解压,修改视频传输参数,然后编译程序,最后弄一个启动脚本方便以后运行。执行启动脚本后,在pc端输入指定网址即可观看视频!
相关教程可以参考:用树莓派官方摄像头做丝滑般流畅的监控!
五、Raspberry-Arduino串口通信
我采用的方案是Raspberry通过USB转TTL与Arduino的RX,TX管脚连接,USB转TTL器件可以在淘宝选购,具体图片为:
因为Arduino与Raspberry的电源值不同,为了安全起见,不要接USB-TTL的VCC,USB-TTL的RX端接Arduino的TX端,TX端接Arduino的RX端,当然GND肯定是要接的!
做好电路连接后,首先先查看哪个USB0亦或USB1端口被占用了:
ls /dev/tty*
'*' 为USB0或USB1,两个都试一下,当某一个端口被占用,是会有对应的文件生成!
Raspberry串口发送数据的简单例程为:
import serial
import time
def Serial_open():
return serial.Serial("/dev/ttyUSB0", 115200)
#"/dev/ttyUSB0"表示该端口被占用
if __name__ == "__main__":
Ser = Serial_open()
while True:
pl2303.write(‘a’)
time.sleep(1)
上面例程作用就是Raspberry隔一秒就发送一个数据‘a’!
接下来到了Arduino的串口操作,这么都非常简单:
void setup() {
// put your setup code here, to run once:
Serial.begin(115200); #串口通信波特率为115200
}
void loop() {
// put your main code here, to run repeatedly:
if (Serial.available() > 0) {
if(Serial.read() == 'a'){
#执行相对应的动作
}
}
}
上面例程就是首先对串口初始化,然后实时对Serial进行检查,当串口收到数据时,Serial.available()会返回一个非0值,接着通过Serial.read()把串口收到的数据读出来,再进行进一步的操作。
相关资料参考:使用串口连接Arduino与树莓派开发板
RaspberryPi2树莓派USB转串口连接Arduino
六、Arduino的电机与舵机控制
到最后一章,如果前面都看懂的话,再加上这一节,几乎就可以做基于Raspberry与Arduino的局域网视频小车。
Fisrt,首先说下电机控制,电机控制需要购买电机驱动模块,如果直接GPIO驱动可能对板子来说很吃力,电机驱动模块,我首推荐的是Arduino配套的L298P驱动模块,如图:
说下它的使用方法,该扩展板是可以直接插到Ardunio MEGA2560开发板上面使用,右上角的VIN是电源输入端,一般电机需要高于5V的电压驱动才会比较好玩,速度才会快些,建议上网买几块大电池,8~12V左右供电,而且它会自动输出5V给Arduino供电,非常方便,同时它有光耦隔离电路,根本不用担心电源电压过高把开发板烧掉,所以还是建议多花点钱买这个拓展版比较好。
接着,右边有A,B各两个输入口,每两个连在一起的输入口接电机两根的线,板子上PWMA,PWMB的PWM占空比输出是控制对应输入端电机的速度,而DIRA,DIRB的高低电平是控制对应输入端电机转动的方向,具体方向取值因接线不同而不同,所以自己要亲自去调试一遍才能知道。
下面给一段自己的小车电机控制子函数给大家做个参考,这部分都比较简单就不做详细解释:
int Right_motor = 3;
int Left_motor = 11;
int Right_Dir = 12;
int Left_Dir = 13;
char flag;
void setup() { //初始化
// put your setup code here, to run once:
Serial.begin(115200);
pinMode(Right_motor,OUTPUT);
pinMode(Left_motor,OUTPUT);
pinMode(Right_Dir,OUTPUT);
pinMode(Left_Dir,OUTPUT);
}
void Car_Control(int r_speed, int l_speed, int flag){
analogWrite(Right_motor,r_speed); //PWM输出控制电机速度
analogWrite(Left_motor,l_speed);
if(flag == 1){ //小车行动方向控制
digitalWrite(Right_Dir,HIGH);//FORWARD
digitalWrite(Left_Dir,LOW);//FORWARD
}
else if(flag == 0){
digitalWrite(Right_Dir,LOW);//FORWARD
digitalWrite(Left_Dir,HIGH);//FORWARD
}
}
Second,说一下舵机的控制,舵机一般选购sg50舵机较适宜吧,价格不贵,占用空间也不是很大,模块如图:
把摄像头装到舵机上也是个很烦恼的问题,建议上网买些合适的舵机云台,然后用502或者热熔胶这类的工具把摄像头装上去也可以,总之,自己衡量吧。
控制舵机可以用到Arduino的Servo库,这个库控制电机的程序很简单,不过缺点在于该库只能利用9、10接口,只能控制两路舵机,不过在这已经够用了,所以,下面展示下例程:
#include <Servo.h>
Servo myservo;
int pos;
void setup() {
// put your setup code here, to run once:
myservo.attach(10); //初始化
}
void loop() {
// put your main code here, to run repeatedly:
myservo.write(pos); //控制舵机转动角度
}
具体资料可参考:Arduino 入门到精通 例程18-舵机控制
七、总结
整篇文章把视频小车所需要实现功能的方法都介绍了一遍,可能文章较长,比较难把握结构,我在这总结一下文章的分支结构:
*********************************************分割线***************************************************
1.VNC服务器搭建实现远程桌面操控
2.发送网络请求给Raspberr: 2.1Flask模板
2.2Flask路径设置
2.3Flask网页模板创建与传送
2.4发送网络请求给Raspberry
3.视频流的传输
4.Raspberry与Arduino的串口通信
5.Arduino的电机与舵机控制
*********************************************分割线***************************************************
整篇文章结构已经归纳完毕,由于水平有限,文章深度自然不够,如有错漏之处,希望可以提出建议,望海涵,谢谢! |
阿莫论坛20周年了!感谢大家的支持与爱护!!
一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。
|