一、需求描述
通过python实现对云台的控制,使用到的相关模块:
1、pyserial,串口模块,用于连接串口,并通过串口发送指令
2、bytes,内置模块,用于将16进制的指令转化成字节流
二、实现代码:版本v1
1、详细过程见代码备注,版本v2,请查阅“四”
2、关键一步是发送数据时的处理,使用到了bytes,请查阅“三”
3、环境搭建根据云台的说明书进行,这里采用的是串口连接设备
import serial
from common.config import serial_com
class SerialHandler(object):
def __init__(self, port=serial_com, baudrate=9600, parity="无", bytesize=8, stopbits=1):
"""
串口初始化,设置串口相关参数
:param port: str类型, 例:COM1
:param baudrate: int类型,取值范围:[4800, 9600, 19200, 18400, 57600, 115200]
:param parit: str类型,N:"无", O:"奇", E:"偶"
:param bytesize: int类型,取值范围:[7, 8]
:param stopbits: int类型,取值范围:[1, 2]
"""
# 根据上位机显示,转换成serial库识别的参数
if parity == "无":
parity = 'N'
elif parity == "奇":
parity = 'O'
elif parity == "偶":
parity = 'E'
else:
pass
self.serial_handler = serial.Serial()
self.serial_handler.port = port
self.serial_handler.baudrate = baudrate
self.serial_handler.bytesize = bytesize
self.serial_handler.parity = parity
self.serial_handler.stopbits = stopbits
# 连接若超时1秒,则结束连接
self.serial_handler.timeout = 15
def open_and_write(self):
'''
# PELCO-D协议:
一、数据格式:
8位数据位、1位停止位,无效验位。波特率:2400
二、命令格式:
字节1 字节2 字节3 字节4 字节5 字节6 字节7
同步字节 地址码 指令码1 指令码2 数据码1 数据码2 校验码
三、命令解释:
1.协议采用十六进制
2.同步字节始终为FF
3.地址码为云台地址号,地址范围请了解云台说明
4.指令码用于表示不同的行为
5.数据码1表示水平速度,2分别表示垂直速度
6.校验码 = MOD[(字节2~6的值相加)/100H]
四、命令例子:
# 右下角:FF 01 00 12 20 20 53
# 左上角:FF 01 00 0C 20 20 4D
# 左下角:FF 01 00 14 20 20 55
# 右上角:FF 01 00 0A 20 20 4B
# 左:FF 01 00 04 20 00 25
# 上:FF 01 00 08 00 20 29
# 右:FF 01 00 02 20 00 23
# 下:FF 01 00 10 00 20 31
# 停止指令:FF 01 00 00 00 00 01
:return:无
'''
self.serial_handler.timeout = 0.05 # 云台转动的时间,单位为秒
self.serial_handler.open()
# bytes().fromhex("FF 01 00 0A 20 20 4B")
self.serial_handler.write(bytes().fromhex("FF 01 00 0A 20 20 4B"))
res = self.serial_handler.readline()
print(res)
self.serial_handler.write(bytes().fromhex("FF 01 00 00 00 00 01")) # 停止转动指令,如果没有,则走到世界尽头
# b"ff01000c20204d"
# chr(0x06).encode("utf-8")
# self.serial_handler.in_waiting(0xff010008002029)
# self.serial_handler.write(b'FF010000000001')
print("串口设置:", self.serial_handler)
print("我请求了!!!")
res = self.serial_handler.readline()
print(res)
self.serial_handler.close()
if __name__ == '__main__':
# 控制云台
SerialHandler(port="COM5", baudrate=2400, parity="无", bytesize=8, stopbits=1).open_and_write()
三、bytes()的用法:官方文档
摘要(其实就是复制粘贴):
二进制序列类型 --- bytes, bytearray, memoryview
操作二进制数据的核心内置类型是 bytes 和 bytearray。 它们由 memoryview 提供支持,该对象使用 缓冲区协议 来访问其他二进制对象所在内存,不需要创建对象的副本。
array 模块支持高效地存储基本数据类型,例如 32 位整数和 IEEE754 双精度浮点值。
bytes 对象
bytes 对象是由单个字节构成的不可变序列。 由于许多主要二进制协议都基于 ASCII 文本编码,因此 bytes 对象提供了一些仅在处理 ASCII 兼容数据时可用,并且在许多特性上与字符串对象紧密相关的方法。
class bytes
([source[, encoding[, errors]]])
首先,表示 bytes 字面值的语法与字符串字面值的大致相同,只是添加了一个 b
前缀:
-
单引号:
b'同样允许嵌入 "双" 引号'
。 -
双引号:
b"同样允许嵌入 '单' 引号"
。 -
三重引号:
b'''三重单引号'''
,b"""三重双引号"""
bytes 字面值中只允许 ASCII 字符(无论源代码声明的编码为何)。 任何超出 127 的二进制值必须使用相应的转义序列形式加入 bytes 字面值。
像字符串字面值一样,bytes 字面值也可以使用 r
前缀来禁用转义序列处理。 请参阅 字符串和字节串字面值 了解有关各种 bytes 字面值形式的详情,包括所支持的转义序列。
虽然 bytes 字面值和表示法是基于 ASCII 文本的,但 bytes 对象的行为实际上更像是不可变的整数序列,序列中的每个值的大小被限制为 0 <= x < 256
(如果违反此限制将引发 ValueError)。 这种限制是有意设计用以强调以下事实,虽然许多二进制格式都包含基于 ASCII 的元素,可以通过某些面向文本的算法进行有用的操作,但情况对于任意二进制数据来说通常却并非如此(盲目地将文本处理算法应用于不兼容 ASCII 的二进制数据格式往往将导致数据损坏)。
除了字面值形式,bytes 对象还可以通过其他几种方式来创建:
-
指定长度的以零值填充的 bytes 对象:
bytes(10)
-
通过由整数组成的可迭代对象:
bytes(range(20))
-
通过缓冲区协议复制现有的二进制数据:
bytes(obj)
另请参阅 bytes 内置类型。
由于两个十六进制数码精确对应一个字节,因此十六进制数是描述二进制数据的常用格式。 相应地,bytes 类型具有从此种格式读取数据的附加类方法:
classmethod fromhex
(string)
此 bytes 类方法返回一个解码给定字符串的 bytes 对象。 字符串必须由表示每个字节的两个十六进制数码构成,其中的 ASCII 空白符会被忽略。
>>> bytes.fromhex('2Ef0 F1f2 ') b'.\xf0\xf1\xf2'
在 3.7 版更改: bytes.fromhex() 现在会忽略所有 ASCII 空白符而不只是空格符。
存在一个反向转换函数,可以将 bytes 对象转换为对应的十六进制表示。
hex
()
返回一个字符串对象,该对象包含实例中每个字节的两个十六进制数字。
>>> b'\xf0\xf1\xf2'.hex() 'f0f1f2'
3.5 新版功能.
由于 bytes 对象是由整数构成的序列(类似于元组),因此对于一个 bytes 对象 b,b[0]
将为一个整数,而 b[0:1]
将为一个长度为 1 的 bytes 对象。 (这与文本字符串不同,索引和切片所产生的将都是一个长度为 1 的字符串)。
bytes 对象的表示使用字面值格式 (b'...'
),因为它通常都要比像 bytes([46, 46, 46])
这样的格式更好用。 你总是可以使用 list(b)
将 bytes 对象转换为一个由整数构成的列表。
注解
针对 Python 2.x 用户的说明:在 Python 2.x 系列中,允许 8 位字符串( 2.x 所提供的最接近内置二进制数据类型的对象)与 Unicode 字符串进行各种隐式转换。 这是为了实现向下兼容的变通做法,以适应 Python 最初只支持 8 位文本而 Unicode 文本是后来才被加入这一事实。 在 Python 3.x 中,这些隐式转换已被取消 —— 8 位二进制数据与 Unicode 文本间的转换必须显式地进行,bytes 与字符串对象的比较结果将总是不相等。
四、实现代码:版本v2
1、新增功能:直接设置水平、俯仰角度
2、封装代码
import serial
from common.config import serial_com # serial_com = "COM6"
class SerialHandler(object):
def __init__(self, port=serial_com, baudrate=9600, parity="无", bytesize=8, stopbits=1):
"""
串口初始化,设置串口相关参数
:param port: str类型, 例:COM1
:param baudrate: int类型,取值范围:[4800, 9600, 19200, 18400, 57600, 115200]
:param parit: str类型,N:"无", O:"奇", E:"偶"
:param bytesize: int类型,取值范围:[7, 8]
:param stopbits: int类型,取值范围:[1, 2]
"""
# 根据上位机显示,转换成serial库识别的参数
if parity == "无":
parity = 'N'
elif parity == "奇":
parity = 'O'
elif parity == "偶":
parity = 'E'
else:
pass
self.serial_handler = serial.Serial()
self.serial_handler.port = port
self.serial_handler.baudrate = baudrate
self.serial_handler.bytesize = bytesize
self.serial_handler.parity = parity
self.serial_handler.stopbits = stopbits
# 连接若超时1秒,则结束连接
self.serial_handler.timeout = 15
def set_angle(self, devel_angle=None, elevation_angle=None):
self.serial_handler.timeout = 0.5 # 云台转动的时间,单位为秒
self.serial_handler.open()
if devel_angle != None:
# 右下角:FF 01 00 12 20 20 53
# 左上角:FF 01 00 0C 20 20 4D
# 40
# FF 01 00 4D 0F A0 FD
# FF01004D0FA0FD
# 20
# FF 01 00 4D 07 D0 25
# FF01004D07D025
devel_num = self.__devel(devel_angle)
# print(hex(devel_num)[2:])
d = hex(devel_num)[2:].upper()
self.serial_handler.write(bytes().fromhex(d))
self.serial_handler.readline()
# self.serial_handler.write(bytes().fromhex("FF010000000001"))
if elevation_angle != None:
elevation_num = self.__elevation(elevation_angle)
# print(hex(elevation_num)[2:])
e = hex(elevation_num)[2:].upper()
self.serial_handler.write(bytes().fromhex(e))
self.serial_handler.readline()
# self.serial_handler.write(bytes().fromhex("FF010000000001"))
self.serial_handler.close()
def open_and_write(self):
# 已弃用,做测试使用
'''
# PELCO-D协议:
一、数据格式:
1位起始位、8位数据、1位停止位,无效验位。波特率:2400B/S
二、命令格式:
字节1 字节2 字节3 字节4 字节5 字节6 字节7
同步字节 地址码 指令码1 指令码2 数据码1 数据码2 校验码
三、命令解释:
1.该协议中所有数值都为十六进制数
2.同步字节始终为FF
3.地址码为云台地址号,地址范围请了解云台说明
4.指令码表示不同的动作
5.数据码1、2分别表示水平、垂直方向速度(00-3FH),FFH表示“turbo”速度
6.校验码 = MOD[(字节2 + 字节3 + 字节4 + 字节5 + 字节6)% 0x100]
四、命令例子:
# 右下角:FF 01 00 12 20 20 53
# 左上角:FF 01 00 0C 20 20 4D
# 左下角:FF 01 00 14 20 20 55
# 右上角:FF 01 00 0A 20 20 4B
# 左:FF 01 00 04 20 00 25
# 上:FF 01 00 08 00 20 29
# 右:FF 01 00 02 20 00 23
# 下:FF 01 00 10 00 20 31
# 停止指令:FF 01 00 00 00 00 01
:return:
'''
self.serial_handler.timeout = 0.5 # 云台转动的时间,单位为秒
self.serial_handler.open()
# bytes().fromhex("FF 01 00 0A 20 20 4B")
# FF01004D1388E9
# FF01004D03E839
self.serial_handler.write(bytes().fromhex("FF 01 00 14 20 20 55")) # FF 01 00 4D 13 88 E9 : FF01004B13884C
res = self.serial_handler.readline()
print(res)
self.serial_handler.write(bytes().fromhex("FF010000000001")) # 停止转动指令,如果没有,则走到世界尽头
# b"ff01000c20204d"
# chr(0x06).encode("utf-8")
# self.serial_handler.in_waiting(0xff010008002029)
# self.serial_handler.write(b'FF010000000001')
print("串口设置:", self.serial_handler)
print("我请求了!!!")
res = self.serial_handler.readline()
print(res)
self.serial_handler.close()
def request(self, bytes_data=b'start'):
'''
通过串口发送字节数据,并返回字节类型的响应结果
:param bytes_data:
:return:
'''
print("串口设置:", self.serial_handler)
print("请求数据:", bytes_data)
self.serial_handler.open()
self.serial_handler.write(bytes_data)
res_list = []
res_str = b""
while 1:
res = self.serial_handler.readline()
print("res的值:",res)
break
# if res == b'':
# print("连接串口失败或没有响应数据!")
# break
# elif res == b' ' or res == b"\x90":
# for ele in res_list:
# res_str += ele
# print("返回结果:", res_str)
# break
# else:
# print("每一次返回结果:", res)
# res_list.append(res)
self.serial_handler.close()
# 返回二进制结果
return res
def __angle_per_num(self):
# 返回:度/1数值
d_min = 0x0000
d_max = 0x8CA0
differ = d_max - d_min # 36000
# print(differ)
average = 360/differ # 数值1则代表0.01度
return average
def __angle_to_num(self, angle):
# 返回:num角度对应的数值(十进制)
average = self.__angle_per_num()
num = angle/average
# print(int(num))
return int(num)
def __devel(self, angle):
# 返回水平数值(十进制)
# 将角度转换成数值
num = self.__angle_to_num(angle)
# 高位数值
h = 0XFF01004B000000
# print(h)
# 中间数值
middle = num*0x100
# print(middle)
# 末尾数值
num_h_m = h+middle # 获取除校验位的所有数值
check_num = self.__check_code(num_h_m)
return h+middle+check_num
def __elevation(self, angle):
# 返回仰角数值(十进制)
# 将角度转换成数值
num = self.__angle_to_num(angle)
# 高位数值
h = 0XFF01004D000000
# print(h)
# 中间数值
middle = num*0x100
# print(middle)
# 末尾数值
num_h_m = h+middle # 获取除校验位的所有数值
check_num = self.__check_code(num_h_m)
return h+middle+check_num
def __check_code(self, num):
# 返回:校验码(十进制),算法是:校验码 = MOD[(字节2 + 字节3 + 字节4 + 字节5 + 字节6)/100H])
num_hex = hex(num)
# print(num_hex) # 0xff01004b8ca078
num_hex_deal = num_hex[4:-2] # 掐头去尾01004b8ca0
# print(num_hex_deal)
num_sum = sum([int(num_hex_deal[i:i+2], 16) for i in range(len(num_hex_deal)) if i % 2 == 0])
check_num = num_sum % 0x100
# print(check_num)
return check_num
if __name__ == '__main__':
# 控制云台
SerialHandler(port="COM6", baudrate=2400, parity="无", bytesize=8, stopbits=1).set_angle(66, 19.88)
五、实现代码:版本v3
1、实现角度获取功能
2、变更了部分方法
3、关键方法:将返回字节数值进行转换(对小白很蓝的啦,特地拿出来)
binascii.b2a_hex(res).decode()
# -*- coding: UTF-8 -*-
# coding=gb18030
'''控制串口,也控制串口依赖的设备,如云台'''
import struct
import threading
import time
import serial
from common.config import serial_com
import binascii
class SerialHandler(object):
def __init__(self, port=serial_com, baudrate=9600, parity="无", bytesize=8, stopbits=1):
"""
串口初始化,设置串口相关参数
:param port: str类型, 例:COM1
:param baudrate: int类型,取值范围:[4800, 9600, 19200, 18400, 57600, 115200]
:param parit: str类型,N:"无", O:"奇", E:"偶"
:param bytesize: int类型,取值范围:[7, 8]
:param stopbits: int类型,取值范围:[1, 2]
"""
# 根据上位机显示,转换成serial库识别的参数
if parity == "无":
parity = 'N'
elif parity == "奇":
parity = 'O'
elif parity == "偶":
parity = 'E'
else:
pass
self.serial_handler = serial.Serial()
self.serial_handler.port = port
self.serial_handler.baudrate = baudrate
self.serial_handler.bytesize = bytesize
self.serial_handler.parity = parity
self.serial_handler.stopbits = stopbits
# # 连接若超时n秒,则结束连接
self.serial_handler.timeout = 15
def set_angle(self, devel_angle=None, elevation_angle=None):
self.serial_handler.timeout = 0.5 # 云台转动的时间,单位为秒
self.serial_handler.open()
if devel_angle != None:
# 右下角:FF 01 00 12 20 20 53
# 左上角:FF 01 00 0C 20 20 4D
# 40
# FF 01 00 4D 0F A0 FD
# FF01004D0FA0FD
# 20
# FF 01 00 4D 07 D0 25
# FF01004D07D025
devel_num = self.__devel(devel_angle)
# print(hex(devel_num)[2:])
d = hex(devel_num)[2:].upper()
self.serial_handler.write(bytes().fromhex(d))
self.serial_handler.readline()
# self.serial_handler.write(bytes().fromhex("FF010000000001"))
if elevation_angle != None:
elevation_num = self.__elevation(elevation_angle)
# print(hex(elevation_num)[2:])
e = hex(elevation_num)[2:].upper()
self.serial_handler.write(bytes().fromhex(e))
self.serial_handler.readline()
# self.serial_handler.write(bytes().fromhex("FF010000000001"))
self.serial_handler.close()
def open_and_write(self, cmd="FF 01 00 14 20 20 55"):
# 更改为写入信息并返回角度
'''
# PELCO-D协议:
一、数据格式:
1位起始位、8位数据、1位停止位,无效验位。波特率:2400B/S
二、命令格式:
字节1 字节2 字节3 字节4 字节5 字节6 字节7
同步字节 地址码 指令码1 指令码2 数据码1 数据码2 校验码
三、命令解释:
1.该协议中所有数值都为十六进制数
2.同步字节始终为FF
3.地址码为云台地址号,地址范围请了解云台说明
4.指令码表示不同的动作
5.数据码1、2分别表示水平、垂直方向速度(00-3FH),FFH表示“turbo”速度
6.校验码 = MOD[(字节2 + 字节3 + 字节4 + 字节5 + 字节6)/100H]
四、命令例子:
# 右下角:FF 01 00 12 20 20 53
# 左上角:FF 01 00 0C 20 20 4D
# 左下角:FF 01 00 14 20 20 55
# 右上角:FF 01 00 0A 20 20 4B
# 左:FF 01 00 04 20 00 25
# 上:FF 01 00 08 00 20 29
# 右:FF 01 00 02 20 00 23
# 下:FF 01 00 10 00 20 31
# 停止指令:FF 01 00 00 00 00 01
:return:
'''
self.serial_handler.timeout = 1 # 云台转动的时间,单位为秒
self.serial_handler.open()
# bytes().fromhex("FF 01 00 0A 20 20 4B")
# FF01004D1388E9
# FF01004D03E839
self.serial_handler.write(bytes().fromhex(cmd)) # FF 01 00 4D 13 88 E9 : FF01004B13884C
res = self.serial_handler.read(100)
# print(res)
# b"ff01000c20204d"
# chr(0x06).encode("utf-8")
# self.serial_handler.in_waiting(0xff010008002029)
# self.serial_handler.write(b'FF010000000001')
# print("串口设置:", self.serial_handler)
# print("我请求了!!!")
# self.serial_handler.write(bytes().fromhex("FF010000000001")) # 停止转动指令,如果没有,则走到世界尽头
# res = self.serial_handler.readline()
# print(res)
self.serial_handler.close()
# print(binascii.b2a_hex(res).decode())
res_str = binascii.b2a_hex(res).decode()[8:12] # 字节转换成字符串,并截取角度部分
# print(res_str)
res_16 = int(res_str, 16) # 转化成16进制
return res_16*self.__angle_per_num()
# 水平
def get_devel(self, cmd="FF 01 00 51 00 00 52"):
# print("水平")
# 查询指令: FF 01 00 51 00 00 52
res = self.open_and_write(cmd)
return res
# 仰角
def get_elevation(self, cmd="FF 01 00 53 00 00 54"):
# print("仰角")
# 查询指令: FF 01 00 53 00 00 54
res = self.open_and_write(cmd)
return res
def request(self, bytes_data=b'start'):
'''
通过串口发送字节数据,并返回字节类型的响应结果
:param bytes_data:
:return:
'''
try:
print("串口设置:", self.serial_handler)
print("请求数据:", bytes_data)
self.serial_handler.open()
self.serial_handler.write(bytes_data)
res_list = []
res_str = b""
while 1:
res = self.serial_handler.readline()
print("res的值:",res)
break
# if res == b'':
# print("连接串口失败或没有响应数据!")
# break
# elif res == b' ' or res == b"\x90":
# for ele in res_list:
# res_str += ele
# print("返回结果:", res_str)
# break
# else:
# print("每一次返回结果:", res)
# res_list.append(res)
self.serial_handler.close()
# 返回二进制结果
return res
except:
print("串口出问题了,请检查串口相关配置和硬件连线")
# return res
# raise IOError("串口出问题了,请检查串口相关配置和硬件连线")
def request_for_connect(self, bytes_data=b'start'):
'''
专门设计一个函数供给逻辑函数使用
通过串口发送字节数据,并返回字节类型的响应结果
:param bytes_data:
:return:
'''
try:
print("串口设置:", self.serial_handler)
print("请求数据:", bytes_data)
self.serial_handler.open()
self.serial_handler.write(bytes_data)
res_list = []
res_str = b""
num = 0
time_0 = time.time()
# while 1:
# print("qqqqqqqqqqqqqqqqqqqqqq")
res = self.serial_handler.read(10000)
# print("sdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsdsd")
print("res的值:",res)
# time_1 = time.time()
# break
# if res == b'':
# print("连接串口失败或没有响应数据!")
# if time_1 - time_0 >= num:
# break
# elif res == b' ' or res == b"\x90":
# for ele in res_list:
# res_str += ele
# print("返回结果:", res_str)
# if time_1 - time_0 >= num:
# break
# else:
# print("每一次返回结果:", res)
# res_list.append(res)
self.serial_handler.close()
# 返回二进制结果
return res
except:
print("串口出问题了,请检查串口相关配置和硬件连线")
def __angle_per_num(self):
# 返回:度/1数值
d_min = 0x0000
d_max = 0x8CA0
differ = d_max - d_min # 36000
# print(differ)
average = 360/differ # 数值1则代表0.01度
return average
def __angle_to_num(self, angle):
# 返回:num角度对应的数值(十进制)
average = self.__angle_per_num()
num = angle/average
# print(int(num))
return int(num)
def __devel(self, angle):
# 返回水平数值(十进制)
# 将角度转换成数值
num = self.__angle_to_num(angle)
# 高位数值
h = 0XFF01004B000000
# print(h)
# 中间数值
middle = num*0x100
# print(middle)
# 末尾数值
num_h_m = h+middle # 获取除校验位的所有数值
check_num = self.__check_code(num_h_m)
return h+middle+check_num
def __elevation(self, angle):
# 返回仰角数值(十进制)
# 将角度转换成数值
num = self.__angle_to_num(angle)
# 高位数值
h = 0XFF01004D000000
# print(h)
# 中间数值
middle = num*0x100
# print(middle)
# 末尾数值
num_h_m = h+middle # 获取除校验位的所有数值
check_num = self.__check_code(num_h_m)
return h+middle+check_num
def __check_code(self, num):
# 返回:校验码(十进制),算法是:校验码 = MOD[(字节2 + 字节3 + 字节4 + 字节5 + 字节6)/100H])
num_hex = hex(num)
# print(num_hex) # 0xff01004b8ca078
num_hex_deal = num_hex[4:-2] # 掐头去尾01004b8ca0
# print(num_hex_deal)
num_sum = sum([int(num_hex_deal[i:i+2], 16) for i in range(len(num_hex_deal)) if i % 2 == 0])
check_num = num_sum % 0x100
# print(check_num)
return check_num
if __name__ == '__main__':
res = SerialHandler().request_for_connect()
# SerialHandler().request()
# print(res)
# 控制云台
# SerialHandler(port="COM6", baudrate=2400, parity="无", bytesize=8, stopbits=1).open_and_write()
# SerialHandler(port="COM6", baudrate=2400, parity="无", bytesize=8, stopbits=1).devel(50)
# SerialHandler(port="COM6", baudrate=2400, parity="无", bytesize=8, stopbits=1).angle_to_num(53.02)
# SerialHandler(port="COM6", baudrate=2400, parity="无", bytesize=8, stopbits=1).devel(360)
# num = 0xFF01004B8CA078
# SerialHandler(port="COM6", baudrate=2400, parity="无", bytesize=8, stopbits=1).check_code(num)
# 结论:
# 1、开机自检的初始位置不定,但能确定是上一次保留的位置
# 2、俯仰角度范围:0到55.77 (水平于地面的位置为中间值,即0°实际角度是倾斜的)
# 3、水平位置范围:0到349.99
# 4、经测量,水平于地面的位置是19.88左右,误差2度
# 5、设置的角度范围不能超过上述范围,否则设置不成功,而没有报错,也没有实际转动
# SerialHandler(port="COM6", baudrate=2400, parity="无", bytesize=8, stopbits=1).set_angle(66, 19.88)
# # 设置一个主函数,用来运行窗口,便于若其他地方下需要调用串口是可以直接调用main函数
# ID, data = main()
#
# print("******")
# print(ID, data)
# # import serial
# ser = serial.Serial()
# ser.port = "COM1"
# ser.baudrate = 9600
# ser.bytesize = 8
# ser.parity = "N" # PARITY_NONE, PARITY_EVEN, PARITY_ODD PARITY_MARK, PARITY_SPACE
# ser.stopbits = 1
# ser.timeout = 1 # 连接超时,不再等待
# print(ser)
# ser.open()
# ser.write(b'start')
# res_list = []
# res_str = b""
# while 1:
# res = ser.read()
# # if res=="":
# # ser.write(b'start')
# # print("响应字节:", res)
# if res == b'':
# break
# if b" "==res or b"\x90"==res:
# for ele in res_list:
# res_str += ele
# print(res_str)
# break
# else:
# res_list.append(res)
# # print(res)
# # for i in range(10):
# # print(ser.read())
# ser.close()
# print(ser.read())
# import io
#
# sio = io.TextIOWrapper(io.BufferedRWPair(ser, ser))
# sio.write("start")
# sio.flush()
# hello = sio.readline()
# ser.close()