在树莓派上做一个远程控制的小车(基于Python)
自制基于树莓派3B的WIFI控制小车
- 所需材料
- 开发环境搭建
- 实现的功能
- 系统架构
- 效果
- 客户端实现代码
- 标题服务端实现代码
- 总结
所需材料
1.履带式底盘及电机:能适应大多数地形
2.L298N步进电机驱动板:驱动电机
3.AR9271无线网卡:虽然树莓派3B内置了wifi模块,但是此网卡信号更好。
4.树莓派500万摄像头:提供实时的视频信号
5.移动电源:树莓派的功耗低,移动电源为10000mA,给小车提供较长时间的续航。
6.超声波测距模块:使用距离探测避免碰撞
开发环境搭建
1.下载树莓派系统:在https://www.raspberrypi.org/downloads/下载Raspbian系统
2.下载win32软件
3.使用win32将下载好的系统文件烧录至内存卡
4.将内存卡插入树莓派并上电启动
5.使用sudo apt-get install python3 安装python3
6.使用python3 –m pip install upgrade pip 升级pip
7.使用pip install pyqt5 安装qt包
8.使用pip install pyqt-tools安装qt依赖包
9.使用sudo apt-get install mjpg-streamer安装视频服务
10.使用pip install socket 安装socket服务
实现的功能
- 远程控制小车行为
- 接收小车的视频信号
- 使用超声波模块避免碰撞
系统架构
效果
客户端实现代码
1.导入必要的包
from PyQt5 import QtCore, QtWidgets from PyQt5.QtCore import * from PyQt5.QtWidgets import * from PyQt5.QtGui import * import cv2 import sys import socket 2.定义 socket 方法:
def sent_msg(msg): # 创建 socket 对象 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) host = '192.168.43.223' # 获取本地主机名port = 9999 # 设置端口号s.connect((host, port)) # 连接服务,指定主机和端口s.sendall(msg.encode('utf-8')) #编码方式s.close() 3.定义用户界面及行为 (利用QtDesigner和UIC对界面进行设计并转成Python文件)
class Ui_Controller(object): def setupUi(self, Controller): Controller.setObjectName("Controller") Controller.resize(680, 535) self.widget = QtWidgets.QWidget(Controller) self.widget.setGeometry(QtCore.QRect(50, 30, 571, 271)) self.widget.setObjectName("widget") self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.widget)self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0) self.horizontalLayout_4.setObjectName("horizontalLayout_4") spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_4.addItem(spacerItem) self.label = QtWidgets.QLabel(self.widget) self.label.setText("") self.label.setObjectName("label") self.horizontalLayout_4.addWidget(self.label) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_4.addItem(spacerItem1) self.widget1 = QtWidgets.QWidget(Controller) self.widget1.setGeometry(QtCore.QRect(0, 330, 671, 193)) self.widget1.setObjectName("widget1") self.horizontalLayout_5 = QtWidgets.QHBoxLayout(self.widget1)self.horizontalLayout_5.setContentsMargins(0, 0, 0, 0) self.horizontalLayout_5.setObjectName("horizontalLayout_5") spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_5.addItem(spacerItem2) spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_5.addItem(spacerItem3) self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.setObjectName("verticalLayout") self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem4) spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding,
QtWidgets.QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem5) self.pushButton = QtWidgets.QPushButton(self.widget1) self.pushButton.setObjectName("pushButton") self.horizontalLayout.addWidget(self.pushButton) spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem6) spacerItem7 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem7) self.verticalLayout.addLayout(self.horizontalLayout) spacerItem8 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.verticalLayout.addItem(spacerItem8) self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") spacerItem9 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_2.addItem(spacerItem9) self.pushButton_3 = QtWidgets.QPushButton(self.widget1) self.pushButton_3.setObjectName("pushButton_3") self.horizontalLayout_2.addWidget(self.pushButton_3) spacerItem10 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_2.addItem(spacerItem10) self.pushButton_5 = QtWidgets.QPushButton(self.widget1) self.pushButton_5.setObjectName("pushButton_5") self.horizontalLayout_2.addWidget(self.pushButton_5) spacerItem11 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_2.addItem(spacerItem11) self.pushButton_4 = QtWidgets.QPushButton(self.widget1) self.pushButton_4.setObjectName("pushButton_4") self.horizontalLayout_2.addWidget(self.pushButton_4) spacerItem12 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_2.addItem(spacerItem12) self.verticalLayout.addLayout(self.horizontalLayout_2) spacerItem13 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.verticalLayout.addItem(spacerItem13) self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") spacerItem14 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_3.addItem(spacerItem14) spacerItem15 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_3.addItem(spacerItem15) self.pushButton_2 = QtWidgets.QPushButton(self.widget1) self.pushButton_2.setObjectName("pushButton_2") self.horizontalLayout_3.addWidget(self.pushButton_2) spacerItem16 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_3.addItem(spacerItem16) spacerItem17 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_3.addItem(spacerItem17) self.verticalLayout.addLayout(self.horizontalLayout_3) self.horizontalLayout_5.addLayout(self.verticalLayout) self.checkBox = QtWidgets.QCheckBox(self.widget1) self.checkBox.setObjectName("checkBox") self.horizontalLayout_5.addWidget(self.checkBox) spacerItem18 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_5.addItem(spacerItem18) self.retranslateUi(Controller) QtCore.QMetaObject.connectSlotsByName(Controller) 4.用户行为方法调用
def retranslateUi(self, Controller): _translate = QtCore.QCoreApplication.translate Controller.setWindowTitle(_translate("Controller", "Form")) self.pushButton.setText(_translate("Controller", "前进")) self.pushButton.clicked.connect(self.on_Forward) self.pushButton_3.setText(_translate("Controller", "左转")) self.pushButton_3.clicked.connect(self.on_Turn_Left) self.pushButton_4.setText(_translate("Controller", "右转")) self.pushButton_4.clicked.connect(self.on_Turn_Right) self.pushButton_2.setText(_translate("Controller", "后退")) self.pushButton_2.clicked.connect(self.on_Back) self.pushButton_5.setText(_translate("Controller", "停止")) self.pushButton_5.clicked.connect(self.on_Stop) self.checkBox.setText(_translate("Controller", "防撞")) self.checkBox.stateChanged.connect(self.on_distance_module) @staticmethod def on_Forward(self): sent_msg("Forward") @staticmethod def on_Turn_Left(self): sent_msg("Left") @staticmethod def on_Turn_Right(self): sent_msg("Right") @staticmethod def on_Back(self): sent_msg("Back") @staticmethod def on_Stop(self): sent_msg("Stop") def on_distance_module(self,state): if state == QtCore.Qt.Checked: sent_msg("on") else: sent_msg("off") 5.使用 cv2 处理视频信号
class MainWindow(QMainWindow, Ui_Controller): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) self.timer_camera = QTimer(self) self.cap = cv2.VideoCapture("http://192.168.43.223:8085/?action=stream") self.timer_camera.timeout.connect(self.show_pic) self.timer_camera.start(10) def show_pic(self): success, frame = self.cap.read() frame = cv2.flip(frame, -1) if success: show = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) showImage = QImage(show.data, show.shape[1], show.shape[0], QImage.Format_RGB888) self.label.setPixmap(QPixmap.fromImage(showImage)) self.timer_camera.start(10) 6.主函数调用
if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec_())
标题服务端实现代码
1.导入必要的包
import socket,sys,os
import wiringpi,time,multiprocessing 2.初始化使能引脚
wiringpi.wiringPiSetup()
wiringpi.pinMode(0, 1)
wiringpi.pinMode(1, 1)
wiringpi.pinMode(2, 1)
wiringpi.pinMode(3, 1)
wiringpi.pinMode(24,0)
wiringpi.pinMode(25,1)
wiringpi.pinMode(28,0)wiringpi.pinMode(29,1) 3.定义小车类及方法
class Car(object): def __init__(self): self.Stop() def right_stop(self): wiringpi.digitalWrite(2, 0) wiringpi.digitalWrite(3, 0) def left_back(self): wiringpi.digitalWrite(0, 0) wiringpi.digitalWrite(1, 1) def right_back(self): wiringpi.digitalWrite(2, 0) wiringpi.digitalWrite(3, 1) def left_stop(self): wiringpi.digitalWrite(0, 0) wiringpi.digitalWrite(1, 0) def left_roll(self): wiringpi.digitalWrite(0, 1) wiringpi.digitalWrite(1 ,0) def right_roll(self): wiringpi.digitalWrite(2, 1) wiringpi.digitalWrite(3, 0) def Stop(self): self.right_stop() self.left_stop() def Run(self): self.right_roll() self.left_roll() def Left(self): self.left_back() self.right_roll() def Right(self): self.left_roll() self.right_back() def Back(self): self.left_back() self.right_back() 4.使用 socket 进行连接
def rec_msg(car,num): serversocket = socket.socket( socket.AF_INET, socket.SOCK_STREAM) host = '192.168.43.223' print(host) port = 9999 serversocket.bind((host, port)) serversocket.listen(5) while True: clientsocket, addr = serversocket.accept() rec_msg = clientsocket.recv(1024).decode('utf-8') if rec_msg == "Forward": car.Stop() car.Run() elif rec_msg == "Back": car.Stop() car.Back() elif rec_msg == "Left": car.Stop() car.Left() elif rec_msg == "Right": car.Stop() car.Right() elif rec_msg == "on": with num.get_lock(): num.value = 1 elif rec_msg == "off": with num.get_lock(): num.value = 0 else : car.Stop() clientsocket.close() 5.距离探测进行防撞
#模块中的引脚操作较多是因为这是一个相对独立的模块,同时测试也比较方便
def detect_distance(): time.sleep(0.01) wiringpi.digitalWrite(29, 1) time.sleep(0.00001) wiringpi.digitalWrite(29, 0) while wiringpi.digitalRead(28) == 0: pass time_start_F = time.time() while wiringpi.digitalRead(28) ==1: pass time_end_F = time.time() distance_F = ((time_end_F - time_start_F) * 34000) / 2 wiringpi.digitalWrite(25, 1) time.sleep(0.00001) wiringpi.digitalWrite(25, 0) while wiringpi.digitalRead(24) == 0: pass time_start_B = time.time() while wiringpi.digitalRead(24) ==1: pass time_end_B = time.time() distance_B = ((time_end_B - time_start_B) * 34000) / 2 if distance_F < 10 and distance_B > 15: wiringpi.digitalWrite(0, 0) wiringpi.digitalWrite(1 ,1) wiringpi.digitalWrite(2, 0) wiringpi.digitalWrite(3, 1) time.sleep(0.5) wiringpi.digitalWrite(0, 0) wiringpi.digitalWrite(1 ,0) wiringpi.digitalWrite(2, 0) wiringpi.digitalWrite(3, 0) if distance_F > 15 and distance_B < 10: wiringpi.digitalWrite(0, 1) wiringpi.digitalWrite(1 ,0) wiringpi.digitalWrite(2, 1) wiringpi.digitalWrite(3, 0) time.sleep(0.5) wiringpi.digitalWrite(0, 0) wiringpi.digitalWrite(1 ,0) wiringpi.digitalWrite(2, 0) wiringpi.digitalWrite(3, 0) if distance_F < 10 and distance_B < 10: wiringpi.digitalWrite(0, 0) wiringpi.digitalWrite(1 ,0) wiringpi.digitalWrite(2, 0) wiringpi.digitalWrite(3, 0) time.sleep(0.1) return distance_F, distance_B def safe_distance(num): while True: if num.value == 0: time.sleep(1) continue elif num.value == 1 : F,B = detect_distance() #print("f:",F,"b:",B) time.sleep(0.2) continue 6.主函数开启多进程
if __name__ == "__main__": car = Car() num = multiprocessing.Value('B',0) pid = os.fork() if pid == 0: rec_msg(car,num) else: safe_distance(num)
总结
这个项目花了三周时间才调试完成,其中主要是对于Python库的学习花的时间比较长,但是也让我充分认识到了Python的强大,另外,毕竟是第一次用Python写的一个完整的项目,总还是有不足的地方,希望网友们指针批评。
参考内容:
[1] 简单WiFi控制小车系统(树莓派+python+web控制界面) https://blog.csdn.net/qq_41923622/article/details/85850780
[2]wiringPi使用手册
https://pypi.org/project/wiringpi/
[3] python +cv2实现视频流播放
https://www.baidu.com/link?url=VTy7HETvmQ6C73iq3Qz8xqFobfCZTMK52zyJZBXsQNPCPbmrihezYkhLdoKbK876IJzDtNWenbz8QkFcooalnciPbcrvv13pTPp0k2z6B93&wd=&eqid=f0fbfd88001672f5000000065cfbaddf
[4] PyQt5中的事件和信号
https://www.cnblogs.com/archisama/p/5454200.html
在树莓派上做一个远程控制的小车(基于Python)相关推荐
- 新手学习实记(十、在树莓派上做图形化界面)
[前言] 校内实习制作--基于树莓派的云台人脸追踪系统.本文主要是记录我的操作和执行过程. 由于要同时准备考研,所以只能学习做一个简易的系统啦,希望能有收获叭. [个人情况(供看文章的同学参考): ① ...
- 用树莓派 + aria2 做一个下载机
用树莓派 + aria2 做一个下载机 用树莓派做下载机很久了,在此记录下来,免得忘记. 0x00 配置aria2 安装aria2c sudo apt-get install aria2 新建aria ...
- 目前市场上做一个网站大约需要多少钱?
建站市场制作网站有两种类型可以选择:定制设计网站建设和模板网站建设,这两种建站类型价格相差很大,目前市场上做一个网站大约需要多少钱?我给大家说下大概的价格定制一个网站价格在8000元左右,直接通过上海 ...
- 在微信平台上做一个公众号,业务序列图
Simplicity(191**17) 2018-06-10 10:03:49 Simplicity(191**17) 2018-06-10 10:05:49 请教:这个图表示 经销商向厂家下达采购订 ...
- 用树莓派PICO做一个桌面时钟超详细教程!
用树莓派PICO做一个可显示时间和温湿度的桌面时钟 一.概述 二.材料准备 1.树莓派PICO 2.DHT11温湿度传感器 3.DS1302时钟模块(选用) 4.SSD1306屏幕 5.其他材料 三. ...
- 使用树莓派摄像头做一个监控小车
最近在网络上看到一句话,让我感触颇深: "你看那些,牵着手说着笑,通往厕所的身影,看那一堆人抱怨着,畅想着.看几个人大笑着吃着泡面的场景,你看,那是我们回不去的青春." 游戏手柄, ...
- 【树莓派】做一个备份镜像
在做树莓派镜像时候,遇到了一点问题,参考这篇文章,再重试一下. Adafruit的树莓派教程第一课福利:做一个备份镜像 04/08/2014 Boyd Wang Adafruit树莓派教程 , 树莓派 ...
- 2021-09-21如何在PCB上做一个城市地铁图?
这是一个电子技术不怎么行(三极管的原理都是刚弄明白),但却创意满满的创客做的作品,他是一位华人小哥(Chai Jia Xun),住在旧金山湾区.他先前曾做过一款生命倒计时(Lifeclocc)的作品, ...
- 同r做一个窗口_怎样在触摸屏上做一个自定义的弹出窗口?
在触摸屏的应用中,一些故障.警告等提示信息通常是使用系统的报警窗口来实现.系统的报警窗口通常只有故障/警告的编号.日期时间及报警信息等内容,并且可以被折叠.这种千篇一律的报警窗口有时候并不能满足项目的 ...
最新文章
- MySQL---Subquery returns more than 1 row
- sql server schema下拉不到存储过程_mysql数据库字符编码总结--数据存储编码
- 优优加速cdn带宽_为什么使用CDN你的网速还是那么慢?
- oracle查询本身字符集,Oracle字符集问题总结
- js将中文转换成编码 java解析_JS实现的汉字与Unicode码相互转化功能分析
- java 栈 大小_java – JVM堆栈大小规范
- 数学之美:45幅耀眼夺目的分形艺术作品欣赏
- [leetcode] Single Number 查找数组中的单数
- 好的安排小明(南阳19)(DFS)
- ABBYY FineReader PDF for Mac(PDF转换工具)
- mysql sha1prng_为啥POST过来的
- [C++ primer]优化内存分配
- php网站源码怎么在本地电脑调式,Windows 平台下配置ZendStudio调式PHP
- 2本学计算机好就业吗,今年高三了,感觉考不上2本了,想读个好点的大专将来好就业。学什么技术好呢,汽修,数控,计算机还是别的什么,求支招,毕业5年后打算自己开店的。...
- 股票数据下载-如何下载股票历史行情数据?
- Linux内核中获取虚拟机KVM结构体信息以及vCPU个数
- [LetCode-1438] 绝对差不超过限制的最长连续子数组
- mysql 5.7 查询分类并返回json格式的数据
- 不要与最好的朋友合伙开公司?对吗
- 使用jquery validate结合zui作表单验证