20230409
上位机程序,运行环境 python-jupyter lab
# 继续去除非必要通信数据,
import serial
arduino = serial.Serial('com4', 1000000) # 打开com x串口,波特率9600
# 布局 QGridLayout from https://realpython.com/python-pyqt-layout/
# 小部件 QDial QSlider from https://blog.csdn.net/MeteorBZ/article/details/105803964
#coding=utf-8
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
QApplication,
QGridLayout,
QWidget,
QLCDNumber,
QDial,
QPushButton,
)
# int DEFAULTNUMBER = 2000 # debug错误语法
DEFAULTNUMBER = 100
class Example(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(30, 50, 800, 500)
self.setWindowTitle('机器人关节控制')
lcd5 = QLCDNumber(self)
lcd5.display( DEFAULTNUMBER )
dial5 = QDial(self)
dial5.setRange(5,250)
dial5.setValue(DEFAULTNUMBER)
dial5.valueChanged.connect(lcd5.display)
dial5.valueChanged.connect(self.dial_changed) ##========================================
## <<<<< bug 旋钮的值174 可以.175报错: ValueError: byte must be in range(0, 256)
## <<<<< debug 命令 0x01 + 旋钮的值174 + 时间 0x50 = 0xFF, 再大 sumCHK溢出
lcd6 = QLCDNumber(self)
lcd6.display( DEFAULTNUMBER )
dial6 = QDial(self)
dial6.setRange(10,200)
dial6.setValue(DEFAULTNUMBER)
dial6.valueChanged.connect(lcd6.display)
lcd7 = QLCDNumber(self)
lcd7.display( DEFAULTNUMBER )
dial7 = QDial(self)
dial7.setRange(10,4000)
dial7.setValue(DEFAULTNUMBER)
dial7.valueChanged.connect(lcd7.display)
lcd8 = QLCDNumber(self)
lcd8.display( DEFAULTNUMBER )
dial8 = QDial(self)
dial8.setRange(10,4000)
dial8.setValue(DEFAULTNUMBER)
dial8.valueChanged.connect(lcd8.display)
lcd9 = QLCDNumber(self)
lcd9.display( DEFAULTNUMBER )
dial9 = QDial(self)
dial9.setRange(10,4000)
dial9.setValue(DEFAULTNUMBER)
dial9.valueChanged.connect(lcd9.display)
lcd10 = QLCDNumber(self)
lcd10.display( DEFAULTNUMBER )
dial10 = QDial(self)
dial10.setRange(10,4000)
dial10.setValue(DEFAULTNUMBER)
dial10.valueChanged.connect(lcd10.display)
lcd14 = QLCDNumber(self)
lcd14.display( DEFAULTNUMBER )
dial14 = QDial(self)
dial14.setRange(10,4000)
dial14.setValue(DEFAULTNUMBER)
dial14.valueChanged.connect(lcd14.display)
layout = QGridLayout()
layout.addWidget( lcd5, 0, 0)
layout.addWidget( lcd6, 0, 1)
layout.addWidget( lcd7, 0, 2)
layout.addWidget( lcd8, 0, 3)
layout.addWidget( lcd9, 0, 4)
layout.addWidget(lcd10, 0, 5)
layout.addWidget(lcd14, 0, 6)
layout.addWidget( dial5, 1, 0) #小周期总时间长度,可以超过大周期 #小周期在大周期里开始显示的时间
layout.addWidget( dial6, 1, 1)
layout.addWidget( dial7, 1, 2)
layout.addWidget( dial8, 1, 3)
layout.addWidget( dial9, 1, 4)
layout.addWidget(dial10, 1, 5)
layout.addWidget(dial14, 1, 6)
layout.addWidget(QPushButton("右髋"), 2, 0)
layout.addWidget(QPushButton("右膝"), 2, 1)
layout.addWidget(QPushButton("右踝"), 2, 2)
layout.addWidget(QPushButton("左髋"), 2, 3)
layout.addWidget(QPushButton("左膝"), 2, 4)
layout.addWidget(QPushButton("左踝"), 2, 5)
layout.addWidget(QPushButton("腰 "), 2, 6)
self.setLayout(layout)
self.show()
def dial_changed(self, value):
# print(type(value)) # <class 'int'>
# 构造数据包
packet = [0xFA, 0xAF, 0x0, 0x1, value,0x50,0x0,0x0 ]
#packet =bytearray( [0xFA, 0xAF, 0, 0x1, value,0x50,0x0,0x0, sumCHK, 0xED])
# 向arduino串口发送数据包
arduino.write(packet) # 使用pyserial发送到arduino
'''
layout.addWidget(QPushButton("Tm总长"), 1, 0)
layout.addWidget(QPushButton("Tm相位"), 1, 1)
layout.addWidget(QPushButton("Tm起"), 1, 2)
layout.addWidget(QPushButton("Tm止"), 1, 3)
layout.addWidget(QPushButton("接续"), 1, 4)
'''
# 适用于Jupyter :使用下面退出 程序,有报错 :Warning: To exit: use 'exit', 'quit', or Ctrl-D.
# https://www.jianshu.com/p/5a9bf7548fdb
if __name__ == '__main__':
app = QApplication(sys.argv)
app.aboutToQuit.connect(app.deleteLater)
ex = Example()
app.exec_()
'''
# 适用于 pycharm
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
'''
'''
# 适用于??
if __name__ == '__main__':
app = QApplication(sys.argv)
app.aboutToQuit.connect(app.deleteLater)
ex = Example()
sys.exit(app.exec_())
'''
下位机程序 运行环境--arduino
// todo bug 虚拟dail拨轮反复转动,串口会挂掉。 这个版本 , 在python上位机中, 精简通讯数据
// 这个版本 , Serial.begin(1000000); 用于PC通信
// 每次 if (Serial.available() > 0) { } 运行, Serial.read()都会读入一个字节, 攒够9个输出到舵机。如果半中间读到0xFA,就重置指针,作为头。
byte readSerialPort[10]; // 构造数据包
byte angle = 0x70; //debug <<<<<<<<<<<<<<<< 正确的语法是byte,而不是 int
byte sum =0; //debug <<<<<<<<<<<<<<<< 正确的语法是byte // 计算校验字节,sum(byte 2--byte 7)
byte SerialMemoPointer =0;
void setup() {
Serial.begin(1000000); // 打开第一条串口,用于通信
Serial1.begin(1000000); // 打开第二条串口,用于控制舵机 <<<<<<<<<<< debug 1MHz频率
}
void loop() {
if (Serial.available() > 0) { // 如果第一条串口有数据
byte incomingByte = Serial.read();
if ( incomingByte == 0xFA ){
SerialMemoPointer = 0; // set 记录器的指针
}
readSerialPort[SerialMemoPointer] = incomingByte ; // 记录
//Serial.print("I received: "); Serial.println(incomingByte ); // 等于 Serial.print("I received: DEC"); Serial.println(incomingByte, DEC);
//Serial.print("I received: HEX "); Serial.println(incomingByte, HEX);
if ( SerialMemoPointer == 7 ){ // readSerialPort[] 已经填满
OutPutToServo(); // 输出到舵机
SerialMemoPointer = 0; // set 记录器的指针
}
SerialMemoPointer ++; // set 记录器的指针 <<<<<<<<<<<<<<<<<<<<<< debug 这个加一必须放在尾部,不能在中间,否则ED字节读不到
delay(10); //-------------------------------------------------------------------- todo 算短等待时间
}
}
void OutPutToServo(){
sum =0; // 计算校验字节,sum(byte 2--byte 7)
for (int i = 2; i < 8; i++) {
sum += readSerialPort[i];
//Serial.print("sum = ");Serial.println(sum, HEX); //---------------------------------------------------------------
}
readSerialPort[8] = sum;
readSerialPort[9] = 0xED;
//Serial.print("sum = ");Serial.println(sum, HEX); //---------------------------------------------------------------
//Serial.print("END = ");Serial.println( readSerialPort[9], HEX); //---------------------------------------------------------------
//Serial.println("outPutToServo================================");
for (int i = 0; i < 10; i++) { // 发送数据包
Serial1.write(readSerialPort[i]); // 发送 字节数据
//Serial.println(readSerialPort[i], HEX);
}
}
控制设备 --去头的悟空躯体,12个舵机(悟空共14个舵机,另外的2个舵机在头里)
网友评论