接着我的上一篇文章:MC9S12G128开发板—实现按键发送CAN报文指示小车移动功能。本篇文章主要记录下在实现小车九宫格方位移动功能过程中,遇到的一些程序问题以及解决措施。
1. 上位机小车响应开发板按键CAN报文指令的响应出错问题
问题现象描述:
开发板上按KEY2键指示小车离开初始化的位置(0,0)即九宫格的左上角向下移动一格,但是发现小车向下先后移动了两次。
出错原因排查:程序关键位置添加打印,通过打印出来的下面截图中的三个列表可以判断出小车向下移动两次是通过小车需要移动位置列表curr_orient=[2,0]更新判断出来的。程序里面小车是否需要移动的逻辑判断是通过比较列表curr_orient与列表origin_orient的一致性,只要小车需要移动位置列表curr_orient与小车当前位置的列表origin_orient不一致,就执行列表curr_orient表示的方位的移动。
def analyse_orientation(data_str, origin_orient):
data_list = data_str.split(" ")
valid_data = data_list[:4] # 前4字节表示方位的报文信息
if "01" in valid_data:
idx = valid_data.index("01")
orient = orient_dict[idx]
if orient == "上":
curr_orient = [origin_orient[0] - 1, origin_orient[1]]
elif orient == "下":
curr_orient = [origin_orient[0] + 1, origin_orient[1]]
elif orient == "左":
curr_orient = [origin_orient[0], origin_orient[1] - 1]
elif orient == "右":
curr_orient = [origin_orient[0], origin_orient[1] + 1]
else:
raise Exception("无效的方位")
# 判断更新的方位是否有效
if check_orient(origin_orient, curr_orient):
return curr_orient
else:
return origin_orient
else:
return origin_orient
def check_orient(origin_orient, curr_orient):
if (curr_orient[0] < 0) or (curr_orient[1] < 0):
return False
elif (curr_orient[0] > 2) or (curr_orient[1] > 2):
return False
elif (origin_orient[0]) == curr_orient[0] and (origin_orient[1] == curr_orient[1]):
return False
else:
return True
经分析主要是开发板按键一次发送向下移动报文后,会一直发送该条报文,导致小车会一直执行向下移动的指令。修改开发板程序后,上位机程序能够按照原逻辑正确解析报文指示小车移动。
2. 上位机小车响应一帧指示移动方位的报文存在延时响应或者响应不及时的问题
由于出现了问题1:上位机小车响应开发板按键CAN报文指令的响应出错问题,调整了开发板的程序每次只会发送一帧指示方位更新的报文,会导致上位机程序在接收处理报文信息时存在延时响应或者响应不及时的问题。
分析程序发现,目前造成信息不同步的原因主要是写入报文数据和读取报文数据判断方位的逻辑是不同线程控制的,两个线程之间存在信息不同步的问题。暂时可以通过以下方式解决该问题:设置读取报文数据判断方位的线程中run()方法执行1秒钟的延时。
def run(self):
while not self.stop_flag:
# 按“开始”按钮进入小车方位移动线程后,重新读取报文存储文件,通过最后一条报文判断小车应该前进的方位
msg_data = self.read_msg_fromtext()
curr_orient = analysis_msg.analyse_orientation(msg_data, self.origin_orient)
if curr_orient != self.origin_orient:
self.update_bitmap(curr_orient).SetBitmap(wx.Bitmap(self.img))
# time.sleep(5)
time.sleep(1)
self.origin_orient = curr_orient
3. CAN通信连接-断开-连接过程中,上位机界面显示接收到的报文帧序号出错
出错现象截图如下:
从上图可以看出,断开CAN通信后,接收到的报文帧序号后三位有的是从001开始依次增加1的,有的报文帧序号从断开CAN通信前的最后一帧报文序号384依次增加1的。
出错原因排查:分析程序代码,出错原因在于鼠标点击“断开”按钮后,程序执行关闭CAN通信的线程但是没有中断CAN通信接收报文的线程,重新点击“连接”按钮启动CAN通信接收报文的线程,导致存在先后两个CAN通信接收报文的线程执行。
使用知乎https://www.zhihu.com/question/595940230?utm_id=0上的Python中断线程方法成功解决了该问题,Python线程中断方法如下:
增加“断开”CAN通信中断CAN报文接收线程功能后,上位机界面成功运行的截图如下:
4. 关闭上位机界面,程序未响应,界面卡死
经分析发现是程序处理逻辑问题:只是按照上述问题3:CAN通信连接-断开-连接过程中,上位机界面显示接收到的报文帧序号出错,通过设置标志位的方式中止了线程中循环的执行,并没有堵塞线程,应该通过join()方式堵塞线程的执行使线程执行完成后正常退出。
# 窗口关闭事件
self.Bind(wx.EVT_CLOSE, self.exit_sys)
def exit_sys(self, event):
try:
# 先强制结束报文接收线程
self.link_thread.stop()
self.link_thread.join()
self.click_thread.stop()
self.click_thread.join()
if self.MyPanel1.m_button1.GetLabel() == "断开": # 表示处于CAN通信连接的状态
self.close_link()
except AttributeError:
pass
# 清空报文记录文件receive_msg.txt
open("receive_msg.txt", 'w').close()
self.Destroy()
sys.exit(1)