This commit is contained in:
Irony 2018-05-02 22:26:30 +08:00
parent a045a04d9d
commit 258f459507
7 changed files with 144 additions and 135 deletions

View file

@ -74,7 +74,6 @@ encoding//\u7A0B\u5E8F\u91CD\u542F/AutoRestart.py=utf-8
encoding//\u7A97\u53E3\u91CD\u542F/RestartMainWindow.py=utf-8
encoding//\u7B80\u5355\u7684\u7A97\u53E3\u8D34\u8FB9\u9690\u85CF/WeltHideWindow.py=utf-8
encoding//\u7F51\u7EDC\u64CD\u4F5C/TcpSocket/\u63A7\u5236\u5C0F\u8F66/ControlCar.py=utf-8
encoding//\u7F51\u7EDC\u64CD\u4F5C/TcpSocket/\u63A7\u5236\u5C0F\u8F66/imageserver.py=utf-8
encoding//\u7F51\u7EDC\u64CD\u4F5C/TcpSocket/\u63A7\u5236\u5C0F\u8F66/server.py=utf-8
encoding//\u817E\u8BAF\u89C6\u9891\u70ED\u64AD\u5217\u8868/TencentMovieHotPlay.py=utf-8
encoding//\u817E\u8BAF\u89C6\u9891\u70ED\u64AD\u5217\u8868/TencentMovieHotPlay_Flow.py=utf-8

View file

@ -22,14 +22,12 @@ __Version__ = 1.0
class ControlCar(QWidget):
HOST = "127.0.0.1"
PORT_CAR = 8888 # 控制小车的端口
PORT_IMAGE = 8899 # 获取图片的端口
HOST = '127.0.0.1'
PORT = 8888
def __init__(self, *args, **kwargs):
super(ControlCar, self).__init__(*args, **kwargs)
self._connCar = None # 控制小车的连接
self._connImage = None # 获取图片的连接
self._connCar = None
# 加载UI文件
uic.loadUi('carui.ui', self)
self.resize(800, 600)
@ -56,11 +54,6 @@ class ControlCar(QWidget):
self._connCar.deleteLater()
del self._connCar
self._connCar = None
if self._connImage:
self._connImage.close()
self._connImage.deleteLater()
del self._connImage
self._connImage = None
def closeEvent(self, event):
"""窗口关闭事件"""
@ -71,6 +64,7 @@ class ControlCar(QWidget):
def doConnect(self):
"""连接服务器"""
self.buttonConnect.setEnabled(False)
self._timer.stop()
self._clearConn()
self.browserResult.append('正在连接服务器')
# 连接控制小车的服务器
@ -79,18 +73,7 @@ class ControlCar(QWidget):
self._connCar.disconnected.connect(self.onDisconnected) # 绑定连接丢失信号
self._connCar.readyRead.connect(self.onReadyRead) # 准备读取信号
self._connCar.error.connect(self.onError) # 连接错误信号
self._connCar.connectToHost(self.HOST, self.PORT_CAR)
# 连接获取图片的服务器
self._connImage = QTcpSocket(self)
# 200毫秒,无闪烁
self._connImage.connected.connect(
lambda: self._timer.start(200) and self.browserResult.append('图片服务器连接成功'))
self._connImage.disconnected.connect(
lambda: self._timer.stop() and self.browserResult.append('图片服务器连丢失连接'))
self._connImage.error.connect(lambda _: self._timer.stop() and self.browserResult.append(
'连接图片服务器错误: ' + self._connImage.errorString()))
self._connImage.readyRead.connect(self.onImageReadyRead)
self._connImage.connectToHost(self.HOST, self.PORT_IMAGE)
self._connCar.connectToHost(self.HOST, self.PORT)
def onConnected(self):
"""连接成功"""
@ -101,9 +84,12 @@ class ControlCar(QWidget):
self.sliderLeft.setEnabled(True)
self.sliderRight.setEnabled(True)
self.browserResult.append('连接成功') # 记录日志
# 开启获取摄像头图片定时器
self._timer.start(200)
def onDisconnected(self):
"""丢失连接"""
self._timer.stop()
self.buttonConnect.setEnabled(True) # 按钮可用
# 设置初始拉动条不可用
self.sliderForward.setEnabled(False)
@ -122,23 +108,17 @@ class ControlCar(QWidget):
while self._connCar.bytesAvailable() > 0:
try:
data = self._connCar.readAll().data()
self.browserResult.append('接收到数据: ' + data.decode())
if data and data.find(b'JFIF') > -1:
self.qlabel.setPixmap( # 图片
QPixmap.fromImage(QImage.fromData(data)))
else:
self.browserResult.append('接收到数据: ' + data.decode())
except Exception as e:
self.browserResult.append('解析数据错误: ' + str(e))
def onImageReadyRead(self):
"""返回的图片数据"""
while self._connImage.bytesAvailable() > 0:
try:
data = self._connImage.readAll().data()
if data and data.find(b'JFIF') > -1:
self.qlabel.setPixmap(
QPixmap.fromImage(QImage.fromData(data)))
except Exception as e:
self.browserResult.append('解析图片数据错误: ' + str(e))
def onError(self, _):
"""连接报错"""
self._timer.stop()
self.buttonConnect.setEnabled(True) # 按钮可用
self.browserResult.append('连接服务器错误: ' + self._connCar.errorString())
@ -164,18 +144,12 @@ class ControlCar(QWidget):
def doGetImage(self):
# 请求图片
if not self._connImage or not self._connImage.isWritable():
return self.browserResult.append('图片服务器未连接或不可写入数据')
self._connImage.write(b'getimage\n')
self.sendData('getimage', '')
def sendData(self, ver, data):
"""发送数据"""
if not self._connCar or not self._connCar.isWritable():
return self.browserResult.append('服务器未连接或不可写入数据')
# self._connCar.write(ver.encode() + str(data).encode())
# time.sleep(0.05)
# 我的服务器需要接收以\n结尾的数据
self._connCar.write(ver.encode() + str(data).encode() + b'\n')

View file

@ -13,6 +13,7 @@
- 这里只用了UI文件做界面并没有转换为python代码
- server.py只是做个本地echo服务器用来测试命令是否正常依赖tornado库可以通过pip install tornado来安装
- 另外需要做粘包处理,以(\n作为粘包符
- 由于wifi能力不行,发送图片要尽量小
说明:
@ -22,4 +23,4 @@
- QTcpSocket.error 连接报错触发该信号(连接超时、服务器断开等等)
## 截图
![截图](ScreenShot/car.gif)
![截图](ScreenShot/1.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 916 KiB

View file

@ -1,74 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import logging
import cv2
from tornado import gen
from tornado.ioloop import IOLoop
from tornado.iostream import StreamClosedError
from tornado.options import options, define
from tornado.tcpserver import TCPServer
# Created on 2018年4月18日
# author: Irony
# site: https://github.com/892768447
# email: 892768447@qq.com
# file: 控制小车.server
# description:
__Author__ = """By: Irony
QQ: 892768447
Email: 892768447@qq.com"""
__Copyright__ = 'Copyright (c) 2018 Irony'
__Version__ = 1.0
define("port", default=8899, help="TCP port to listen on")
logger = logging.getLogger(__name__)
SIZE = (640, 480) # 分辨率
FPS = 24
PARAM = [int(cv2.IMWRITE_JPEG_QUALITY), FPS]
class EchoServer(TCPServer):
IMAGE = None
def __init__(self, *args, **kwargs):
super(EchoServer, self).__init__(*args, **kwargs)
try:
self.cap = cv2.VideoCapture(0)
except Exception as e:
print(e)
@gen.coroutine
def handle_stream(self, stream, address):
while True:
try:
data = yield stream.read_until(b"\n")
# logger.info("Received bytes: %s", data)
if not data.endswith(b"\n"):
data = data + b"\n"
if data == b'getimage\n' and self.cap and self.cap.isOpened():
_, frame = self.cap.read() # 读取一帧图片
if str(type(frame)).find('ndarray') > -1:
frame = cv2.resize(frame, SIZE)
ret, data = cv2.imencode('.jpg', frame, PARAM)
if ret:
yield stream.write(data.tostring()) # 发送图片
else:
yield stream.write(b'\n')
except StreamClosedError:
logger.warning("Lost client at host %s", address[0])
break
except Exception as e:
print(e)
if __name__ == "__main__":
options.parse_command_line()
server = EchoServer()
server.listen(options.port)
logger.info("Listening on TCP port %d", options.port)
IOLoop.current().start()

View file

@ -1,21 +1,9 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Created on 2018年4月18日
# author: Irony
# site: https://github.com/892768447
# email: 892768447@qq.com
# file: 控制小车.server
# description:
__Author__ = """By: Irony
QQ: 892768447
Email: 892768447@qq.com"""
__Copyright__ = 'Copyright (c) 2018 Irony'
__Version__ = 1.0
import atexit
import logging
import cv2
from tornado import gen
from tornado.ioloop import IOLoop
from tornado.iostream import StreamClosedError
@ -23,20 +11,123 @@ from tornado.options import options, define
from tornado.tcpserver import TCPServer
try:
import RPi.GPIO as GPIO # @UnusedImport @UnresolvedImport
except:
pass
# Created on 2018年4月18日
# author: Irony
# site: https://github.com/892768447
# email: 892768447@qq.com
# file: server
# description:
__Author__ = """By: Irony
QQ: 892768447
Email: 892768447@qq.com"""
__Copyright__ = 'Copyright (c) 2018 Irony'
__Version__ = 1.0
define("port", default=8888, help="TCP port to listen on")
logger = logging.getLogger(__name__)
# SIZE = (640, 480) # 分辨率
# FPS = 24
SIZE = (100, 80) # 分辨率
FPS = 5
PARAM = [int(cv2.IMWRITE_JPEG_QUALITY), FPS]
class EchoServer(TCPServer):
IMAGE = None
def __init__(self, cap, *args, **kwargs):
super(EchoServer, self).__init__(*args, **kwargs)
self.cap = cap
self.init()
def init(self):
"""初始化管脚"""
try:
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.OUT)
GPIO.setup(27, GPIO.OUT)
GPIO.setup(22, GPIO.OUT)
GPIO.setup(18, GPIO.OUT, initial=False)
self.duo = GPIO.PWM(18, 300)
self.p1 = GPIO.PWM(17, 10000)
self.p2 = GPIO.PWM(27, 10000)
en = GPIO.output(22, False) # @UnusedVariable
self.p1.start(0)
self.p2.start(0)
self.duo.start(0)
except Exception as e:
print(e)
def forward(self, a):
try:
k = a / 100
print("k=%lf" % k)
self.p1.ChangeDutyCycle(k)
self.p2.ChangeDutyCycle(0)
except:
pass
def back(self, a):
try:
k = a / 100
print("k1=%lf" % k)
self.p1.ChangeDutyCycle(0)
self.p2.ChangeDutyCycle(k)
except:
pass
def lr(self, a):
try:
self.duo.ChangeDutyCycle(a) # 左满舵a=32右满舵a=52中值a=42则a值取32至52
except:
pass
def stop(self):
try:
self.p1.ChangeDutyCycle(0)
self.p2.ChangeDutyCycle(0)
self.duo.ChangeDutyCycle(42)
except:
pass
@gen.coroutine
def handle_stream(self, stream, address):
while True:
try:
data = yield stream.read_until(b"\n")
logger.info("Received bytes: %s", data)
# logger.info("Received bytes: %s", data)
if not data.endswith(b"\n"):
data = data + b"\n"
yield stream.write(data)
if data == b'getimage\n' and self.cap and self.cap.isOpened():
_, frame = self.cap.read() # 读取一帧图片
if str(type(frame)).find('ndarray') > -1:
frame = cv2.resize(frame, SIZE)
ret, data = cv2.imencode('.jpg', frame, PARAM)
if ret:
yield stream.write(data.tostring()) # 发送图片
else:
try:
ver, value = data.decode().split(':')
if ver == 'L':
self.lr(int(value))
elif ver == 'R':
self.lr(int(value))
elif ver == 'F':
self.forward(int(value))
elif ver == 'B':
self.back(int(value))
yield stream.write(data)
except:
yield stream.write(b'\n')
except StreamClosedError:
logger.warning("Lost client at host %s", address[0])
break
@ -44,9 +135,27 @@ class EchoServer(TCPServer):
print(e)
if __name__ == "__main__":
def start(cap):
"""启动服务器"""
options.parse_command_line()
server = EchoServer()
server = EchoServer(cap)
server.listen(options.port)
logger.info("Listening on TCP port %d", options.port)
IOLoop.current().start()
if __name__ == "__main__":
cap = None
try:
cap = cv2.VideoCapture(0) # 开启摄像头
atexit.register(lambda: cap.release())
atexit.register(lambda: GPIO.cleanup())
start(cap)
except Exception as e:
print(e)
if cap:
cap.release()
try:
GPIO.cleanup()
except:
pass