some fix
This commit is contained in:
parent
a045a04d9d
commit
258f459507
7 changed files with 144 additions and 135 deletions
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
BIN
网络操作/TcpSocket/控制小车/ScreenShot/1.png
Normal file
BIN
网络操作/TcpSocket/控制小车/ScreenShot/1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
Binary file not shown.
Before Width: | Height: | Size: 916 KiB |
|
@ -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()
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue