完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
本人使用的设备/驱动:
本文直接从项目中加入相关功能说起,环境以及其他外设配置: CubeMX配合PlatformIO开发STM32, CubeMX配合PlatformIO开发STM32, CubeMX配合PlatformIO开发STM32, CubeMX配合PlatformIO开发STM32, CubeMX配合PlatformIO开发STM32, CubeMX配合PlatformIO开发STM32, CubeMX配合PlatformIO开发STM32, CubeMX配合PlatformIO开发STM32, CubeMX配合PlatformIO开发STM32, 每改一次pid都要重新烧太麻烦了,能在线调多美好啊 这是设计好的gui,核心部分是上面的滑轨以及右边显示的两列lcd,左边一列lcd是实时lcd,反应滑轨;右边一列lcd是lcd_saved,显示storm开发板中pid的参数。 大概的交互逻辑大致如下: 首先搞定显示的问题: 确定模块的功能设置: class GuiController(QWidget): def initUI(self): ##################参数P调整######################### self.PLcd_text = QLCDNumber(self) self.PLcd_text.setSegmentStyle(QLCDNumber.Filled) self.PLcd_text.display('P')#固定显示“P”这个字符 self.PSlider = QSlider(Qt.Horizontal, self) self.PSlider.setFocusPolicy(Qt.NoFocus) self.PSlider.setMinimum(0)#设置滑轨最小值以及最大值 self.PSlider.setMaximum(300) self.PSlider.setSingleStep(2)#滑轨的调整间隔 self.PSlider.setTickPosition(QSlider.TicksBelow) self.PSlider.valueChanged.connect(self.PChange_temp)#与一个函数PChange_temp连接,在滑轨值变化时调用这个函数 self.PLcd = QLCDNumber(self) #设置一个lcd,PChange_temp的改变反应到这上面来 self.PLcd.setSegmentStyle(QLCDNumber.Flat) self.PLcd.setSmallDecimalPoint(True) self.PLcd.setDigitCount(3) ##################参数I调整######################### self.ILcd_text = QLCDNumber(self) self.ILcd_text.setSegmentStyle(QLCDNumber.Filled) self.ILcd_text.display(1) self.ISlider = QSlider(Qt.Horizontal, self) self.ISlider.setFocusPolicy(Qt.NoFocus) self.ISlider.setMinimum(0) self.ISlider.setMaximum(300) self.ISlider.setSingleStep(2) self.ISlider.setTickPosition(QSlider.TicksBelow) self.ISlider.valueChanged.connect(self.IChange_temp) self.ILcd = QLCDNumber(self) self.ILcd.setSegmentStyle(QLCDNumber.Flat) self.ILcd.setSmallDecimalPoint(True) self.ILcd.setDigitCount(3) ##################参数D调整######################### self.DLcd_text = QLCDNumber(self) self.DLcd_text.setSegmentStyle(QLCDNumber.Filled) self.DLcd_text.display(0) self.DSlider = QSlider(Qt.Horizontal, self) self.DSlider.setFocusPolicy(Qt.NoFocus) self.DSlider.setMinimum(0) self.DSlider.setMaximum(300) self.DSlider.setSingleStep(2) self.DSlider.setTickPosition(QSlider.TicksBelow) self.DSlider.valueChanged.connect(self.DChange_temp) self.DLcd = QLCDNumber(self) self.DLcd.setSegmentStyle(QLCDNumber.Flat) self.DLcd.setSmallDecimalPoint(True) self.DLcd.setDigitCount(3) self.Select_motor =QComboBox(self) #下拉菜单 self.Select_motor.addItem('Pitch') self.Select_motor.addItem('Roll') self.Select_motor.addItem('Yaw') # self.Select_motor.setCurrentIndex('Pitch') self.Select_motor.currentIndexChanged[str].connect(self.motor_selected) # 条目发生改变,发射信号,传递条目内容 self.SetPIDButton = QPushButton("SetPID") #设置PID,将pid传入bgc,并显示到最右栏 self.SetPIDButton.clicked.connect(self.SetPIDCB) 这些功能都只在class中相互调用:如Xlcd显示XSlider的值;而上面说到的lcd_saved(写入板子的PID值)需要被多个class调用,如读到串口数据要更改,按下按钮“setPID”也要更改,所以写在代码开头,方便被各个class调用 #因为要跨类调用,所以定义在函数外部作全局用 PLcd_saved = QLCDNumber() PLcd_saved.setSegmentStyle(QLCDNumber.Flat) PLcd_saved.setSmallDecimalPoint(True) PLcd_saved.setDigitCount(3) ILcd_saved = QLCDNumber() ILcd_saved.setSegmentStyle(QLCDNumber.Flat) ILcd_saved.setSmallDecimalPoint(True) ILcd_saved.setDigitCount(3) DLcd_saved = QLCDNumber() DLcd_saved.setSegmentStyle(QLCDNumber.Flat) DLcd_saved.setSmallDecimalPoint(True) DLcd_saved.setDigitCount(3) 回到gui的class下,在grid形式下编程:确定模块的位置 self.grid.addWidget(self.PLcd_text, 2, 0)#显示“P”字符 self.grid.addWidget(self.PSlider, 2, 1, 1, 1)#滑轨 self.grid.addWidget(self.PLcd, 2, 2)#滑轨上的参数 self.grid.addWidget(PLcd_saved, 2, 3)#已保存到bgc的 self.grid.addWidget(self.ILcd_text, 3, 0) self.grid.addWidget(self.ISlider, 3, 1, 1, 1) self.grid.addWidget(self.ILcd, 3, 2) self.grid.addWidget(ILcd_saved, 3, 3) self.grid.addWidget(self.DLcd_text, 4, 0) self.grid.addWidget(self.DSlider, 4, 1, 1, 1) self.grid.addWidget(self.DLcd, 4, 2) self.grid.addWidget(DLcd_saved, 4, 3) self.grid.addWidget(self.Select_motor, 5, 1) self.grid.addWidget(self.SetPIDButton, 5, 0) 各个模块调用的功能函数,包括实时显示滑轨,下拉菜单选择的电机,按下setPID按钮的反应 def PChange_temp(self): value = float(self.PSlider.value())#获取滑轨的值 print("P:", value) self.PLcd.display(value)#在lcd中显示 def IChange_temp(self): value = float(self.ISlider.value()) print("I:", value) self.ILcd.display(value) def DChange_temp(self): value = float(self.DSlider.value()) print("D:", value) self.DLcd.display(value) def motor_selected(self): global motor_num value = self.Select_motor.currentText()#当前下拉栏中选择的文字。注意,刚初始化的没有选择过的下拉列表value读不到值 if value == "Pitch": motor_num = 0 elif value == "Roll": motor_num = 1 else: motor_num = 2 def SetPIDCB(self): #将PID传输出去,并更改显示 global P,I,D global origin_pid_flag global set_PID_flag if origin_pid_flag==1:#如果是开机读到的pid数据 PLcd_saved.display(origin_P) ILcd_saved.display(origin_I) DLcd_saved.display(origin_D) origin_pid_flag=0 else: P = float(self.PSlider.value())#将滑轨数据保存下来 I = float(self.ISlider.value()) D = float(self.DSlider.value()) set_PID_flag = 1 #使能向bgc的发送,防止乱跳 新建一个class,完成串口发送以及确认的功能。如果发送的数据的返回值跟发送值不同,则不停重发,有点暴力的协议但是实际还是有用的。 class sendThread(QThread): #send bytes def __init__(self): super().__init__() def run(self): global P, I, D global conn_flag, set_PID_flag global write_success_flag while True: time.sleep(0.01) if (conn_flag == 0) & (set_PID_flag == 1):#当串口连接以及按下写入按钮后执行 # data = [int(0), float(vmax), # float(angle), float(0.0)] while write_success_flag==0: #确定是否写入成功 data = [int(motor_num), float(P), float(I), float(D)] serial.writeData(data) #这是一个自己写的函数,通过串口发送数据,顺序为time yaw roll pitch print("write:", motor_num, "P:", P, "I:", I, "D:", D) time.sleep(0.005) print("Motor:", motor_num, "P:", P, "I:", I, "D:", D) PLcd_saved.display(P) #显示到最右侧的LCD上去 ILcd_saved.display(I) DLcd_saved.display(D) write_success_flag=0 set_PID_flag=0 注意,因为gui中需要这个功能,所以还需要在guicontroller的类下: def __init__(self, length): super().__init__() self.sendThread = sendThread() 接下来进入pio中,首先使能usart3的中断 允许usart接受中断: HAL_UART_Receive_IT(uart3_it.uart,&(uart3_it.tmp_buff),1); 在gui发来数据后触发中断,进入回调函数: void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart->Instance == USART3) { if (uart3_it.rx_bytes_count >= 18)//judge whether length is matched { uart3_it.rx_bytes_count = 0; memset(&(uart3_it.data), 0, sizeof(Serial_Receive_Stream_typeDef)); uart3_it.is_compelete = 0; } else { uint8_t *ptr = (uint8_t *)(&(uart3_it.data)); ptr[uart3_it.rx_bytes_count++] = uart3_it.tmp_buff;//read buffer if (ptr[uart3_it.rx_bytes_count - 2] == 'r' && ptr[uart3_it.rx_bytes_count - 1] == 'n')//last 2bytes { if(uart3_it.rx_bytes_count==18){//if length is matched,then enable a flag which means data is available uart3_it.is_compelete = 1; HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_13); uart3_it.rx_bytes_count = 0; }else{ uart3_it.rx_bytes_count = 0; memset(&(uart3_it.data), 0, sizeof(Serial_Receive_Stream_typeDef)); uart3_it.is_compelete = 0; } } else { uart3_it.is_compelete = 0; HAL_UART_Receive_IT(uart3_it.uart, &(uart3_it.tmp_buff), 1);// enable interrupt } } } } 主函数中根据传输成功的标志位进入函数: if(uart3_it.is_compelete){ uart3_it.is_compelete = 0; // updateEncoder(&roll_encoder); motor_num= uart3_it.data.time_stamp; if(sendpid(motor_num,&uart3_it.data.yaw,&uart3_it.data.roll,&uart3_it.data.pitch)) { serial_data.time_stamp = uart3_it.data.time_stamp; serial_data.yaw = uart3_it.data.yaw; serial_data.roll = uart3_it.data.roll; serial_data.pitch = uart3_it.data.pitch; SerialPrintTransmit(&serial_data); printf("transmited_to_clientrn"); } printf("transmited_to_clientrn"); HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_12); } 给PID赋值(通过返回标志位表示完成赋值) /* USER CODE BEGIN 4 */ int sendpid(int motornum,float *get_P, float *get_I, float *get_D) { static int PID_transmit_complete=0; PID_transmit_complete=0; if(motornum==0) { pitchPPara=*get_P; pitchIPara=*get_I; pitchDPara=*get_D; printf("storm_pitch:P:%f,I:%f,D:%frn",pitchPPara,pitchIPara,pitchDPara); } else if(motornum==1) { rollPPara=*get_P; rollIPara=*get_I; rollDPara=*get_D; printf("storm_roll:P:%f,I:%f,D:%frn",rollPPara,rollIPara,rollDPara); } else { yawPPara=*get_P; yawIPara=*get_I; yawDPara=*get_D; printf("storm_yaw:P:%f,I:%f,D:%frn",yawPPara,yawIPara,yawDPara); } PID_transmit_complete=1; return PID_transmit_complete; } /* USER CODE END 4 */ 通过串口发回去后,gui会判断是否停止发送。 至此,逻辑闭环 |
|
|
|
只有小组成员才能发言,加入小组>>
3182 浏览 9 评论
2870 浏览 16 评论
3375 浏览 1 评论
8800 浏览 16 评论
3975 浏览 18 评论
9607浏览 3评论
973浏览 3评论
497浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
497浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2218浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-9-18 11:32 , Processed in 0.884520 second(s), Total 50, Slave 41 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号