功能模块:任务调度器 - Ligcox/BTP_DM GitHub Wiki

程序的核心控制--任务调度器

在BTPDM中,使用了一个任务调度器来控制控制程序 应该 将系统性能分配到各个任务中去。通常来说,在BTPDM运行过程中,仅会执行一个任务,该任务会占据系统的 全部 性能。

以步兵机器人为例,步兵机器人可能包含了自瞄任务和能量机关任务。让步兵机器人占据能量机关激活点时,BCP会将connection对象的STATUS变量的mode字段设置为2。此时,任务调度器应当在执行完当前任务的一次loop时,将任务切换到能量机关识别相关的算法。

更准确地说,无论程序当前任务是否执行完,任务调度器都应该直接打断当前任务直接切换到应该执行的任务的逻辑中,类似于 中断函数 。但由于每个任务的执行周期通常小于200ms,因此,宏观上看,执行完当前任务再切换会不对程序的整体运行造成很大的影响。

上下文管理器机制

Python的with语句支持由 上下文管理器(context manager) 定义的上下文。在BTPDM的任务调度器实现,也正是通过构造上下文管理器来完成的。任务调度器通过__enter__()__exit__(exc_type, exc_val, exc_tb)这一对方法实现的。

当任务调度器在main.py中使用with语句创建时,会首先调用__enter__()方法,__enter__()返回了上下文管理器需要管理的对象,即任务调度器本身。

def __enter__(self):
    return self

当程序终止时,会调用__exit__(self, exc_type, exc_value, traceback)方法,__exit__(self, exc_type, exc_value, traceback)方法会首先打印错误信息,然后执行任务管理器的cleanup(self)方法,cleanup(self)主要包括了各个线程停止时的清理。

def __exit__(self, exc_type, exc_value, traceback):
    print(exc_type, exc_value, traceback.tb_frame)
    call_cnt = 20
    while call_cnt>0:
        print(str(traceback.tb_frame))
        cur = traceback
        if traceback.tb_next is not None:
            traceback = traceback.tb_next
            call_cnt-=1
    self.cleanup()

# 结束任务时的清理程序
def cleanup(self):
    cv2.destroyAllWindows()
    self.threading1.stop()
    self.threading2.stop()
    self.threadingxxxx.stop()
    sys.exit(0)

一个典型的线程清理例子是图像读取线程,当程序停止运行时,摄像头对象应该被立即释放。

def cleanup(self):
    if not self.device is None:
        self.device.release()
    super().cleanup()

运行机制

不同的机器人会只用不同的任务调度器,这些任务调度器都是由父类Schedule派生而来的。

Schedule及其派生类的构造方法中,会首先初始化和打开相应的线程,并且执行run()方法。run()方法会循环调用self.main_task()任务,这样做的目的是为了Logger能够对主进程进行监听和修饰。self.main_task()中会根据BCP数据帧的模式控制部分来对程序进行控制。

Schedule及其派生类的继承和调用组织关系如图所示:

Schedule及其派生类的继承关系