自制基于树莓派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. 远程控制小车行为
  2. 接收小车的视频信号
  3. 使用超声波模块避免碰撞

系统架构

效果




客户端实现代码

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)相关推荐

  1. 新手学习实记(十、在树莓派上做图形化界面)

    [前言] 校内实习制作--基于树莓派的云台人脸追踪系统.本文主要是记录我的操作和执行过程. 由于要同时准备考研,所以只能学习做一个简易的系统啦,希望能有收获叭. [个人情况(供看文章的同学参考): ① ...

  2. 用树莓派 + aria2 做一个下载机

    用树莓派 + aria2 做一个下载机 用树莓派做下载机很久了,在此记录下来,免得忘记. 0x00 配置aria2 安装aria2c sudo apt-get install aria2 新建aria ...

  3. 目前市场上做一个网站大约需要多少钱?

    建站市场制作网站有两种类型可以选择:定制设计网站建设和模板网站建设,这两种建站类型价格相差很大,目前市场上做一个网站大约需要多少钱?我给大家说下大概的价格定制一个网站价格在8000元左右,直接通过上海 ...

  4. 在微信平台上做一个公众号,业务序列图

    Simplicity(191**17) 2018-06-10 10:03:49 Simplicity(191**17) 2018-06-10 10:05:49 请教:这个图表示 经销商向厂家下达采购订 ...

  5. 用树莓派PICO做一个桌面时钟超详细教程!

    用树莓派PICO做一个可显示时间和温湿度的桌面时钟 一.概述 二.材料准备 1.树莓派PICO 2.DHT11温湿度传感器 3.DS1302时钟模块(选用) 4.SSD1306屏幕 5.其他材料 三. ...

  6. 使用树莓派摄像头做一个监控小车

    最近在网络上看到一句话,让我感触颇深: "你看那些,牵着手说着笑,通往厕所的身影,看那一堆人抱怨着,畅想着.看几个人大笑着吃着泡面的场景,你看,那是我们回不去的青春." 游戏手柄, ...

  7. 【树莓派】做一个备份镜像

    在做树莓派镜像时候,遇到了一点问题,参考这篇文章,再重试一下. Adafruit的树莓派教程第一课福利:做一个备份镜像 04/08/2014 Boyd Wang Adafruit树莓派教程 , 树莓派 ...

  8. 2021-09-21如何在PCB上做一个城市地铁图?

    这是一个电子技术不怎么行(三极管的原理都是刚弄明白),但却创意满满的创客做的作品,他是一位华人小哥(Chai Jia Xun),住在旧金山湾区.他先前曾做过一款生命倒计时(Lifeclocc)的作品, ...

  9. 同r做一个窗口_怎样在触摸屏上做一个自定义的弹出窗口?

    在触摸屏的应用中,一些故障.警告等提示信息通常是使用系统的报警窗口来实现.系统的报警窗口通常只有故障/警告的编号.日期时间及报警信息等内容,并且可以被折叠.这种千篇一律的报警窗口有时候并不能满足项目的 ...

最新文章

  1. MySQL---Subquery returns more than 1 row
  2. sql server schema下拉不到存储过程_mysql数据库字符编码总结--数据存储编码
  3. 优优加速cdn带宽_为什么使用CDN你的网速还是那么慢?
  4. oracle查询本身字符集,Oracle字符集问题总结
  5. js将中文转换成编码 java解析_JS实现的汉字与Unicode码相互转化功能分析
  6. java 栈 大小_java – JVM堆栈大小规范
  7. 数学之美:45幅耀眼夺目的分形艺术作品欣赏
  8. [leetcode] Single Number 查找数组中的单数
  9. 好的安排小明(南阳19)(DFS)
  10. ABBYY FineReader PDF for Mac(PDF转换工具)
  11. mysql sha1prng_为啥POST过来的
  12. [C++ primer]优化内存分配
  13. php网站源码怎么在本地电脑调式,Windows 平台下配置ZendStudio调式PHP
  14. 2本学计算机好就业吗,今年高三了,感觉考不上2本了,想读个好点的大专将来好就业。学什么技术好呢,汽修,数控,计算机还是别的什么,求支招,毕业5年后打算自己开店的。...
  15. 股票数据下载-如何下载股票历史行情数据?
  16. Linux内核中获取虚拟机KVM结构体信息以及vCPU个数
  17. [LetCode-1438] 绝对差不超过限制的最长连续子数组
  18. mysql 5.7 查询分类并返回json格式的数据
  19. 不要与最好的朋友合伙开公司?对吗
  20. 使用jquery validate结合zui作表单验证

热门文章

  1. 随着人工智能发展的少儿编程教育
  2. 安德斯.埃里克森 的研究
  3. 机器学习从入门到创业手记-1.2 机器学习的概念
  4. 宫崎骏最新动画——哈尔的移动城堡
  5. 我的世界匠魂钢怎么做
  6. 女神青涩时纤毫毕现,腾讯 AI 模型 GFPGAN 火上 GitHub 热榜第一,Demo 在线可玩
  7. 万诤:同心同向同行,才算得上不负遇见
  8. vscode源代码管理不显示修改的文件夹
  9. Unity UI 动画 工具
  10. 碳素结构钢的实际拉伸性能可能与规定的最小值不同