Nao机器人Python紧急开关优化咨询:终止抛异常、行走场景失效
NAO机器人紧急开关优化方案
原代码存在的问题
- 直接依赖全局
app实例,作用域混乱,且sys.exit(1)强制终止进程会引发qi框架线程异常 - 仅处理了文本播报的停止逻辑,未针对行走场景添加
ALMotion服务的停止操作 - 阻塞式调用
tts.say(),导致事件循环未完全启动,触摸事件响应异常 - 采用Python2风格的异常捕获语法,兼容性差
优化后的实现代码
# -*- encoding: UTF-8 -*- import qi import sys class EmergencySwitch(object): def __init__(self, app): super(EmergencySwitch, self).__init__() self.app = app # 保存app实例到类属性,避免全局引用 self.session = app.session self.app.start() # 初始化核心服务 self.tts = self.session.service("ALTextToSpeech") self.motion = self.session.service("ALMotion") # 新增行走服务支持 self.memory = self.session.service("ALMemory") # 订阅头部触摸传感器事件 self.touch_subscriber = self.memory.subscriber("FrontTactilTouched") self.touch_signal_id = self.touch_subscriber.signal.connect(self.trigger_emergency_stop) # 启动目标任务(播报/行走) self.start_task() def trigger_emergency_stop(self, touched): # 断开触摸事件订阅,防止重复触发 if self.touch_signal_id: self.touch_subscriber.signal.disconnect(self.touch_signal_id) self.touch_signal_id = None # 优雅停止所有运行中任务 try: self.tts.stopAll() # 终止播报 self.motion.stopMove() # 终止行走(需强制终止可替换为killMove()) self.app.stop() # 优雅停止qi应用框架 except RuntimeError as e: print(f"紧急停止出错: {str(e)}") finally: sys.exit(0) # 正常退出进程,避免强制终止引发异常 def start_task(self): # 示例1:异步播报任务(不阻塞事件循环) self.tts.setVolume(0.1) self.tts.say("Hallo sdiufhsfkasdkjasdnaskjfbnsdkfbskfjn", _async=True) # 示例2:异步行走任务(取消注释启用) # self.motion.moveInit() # self.motion.setWalkTargetVelocity(0.2, 0, 0, _async=True) if __name__ == "__main__": try: app = qi.Application(["EmergencySwitch", "--qi-url=tcp://192.168.95.80:9559"]) except RuntimeError: print("连接机器人失败") sys.exit(1) emergency_switch = EmergencySwitch(app) app.run()
关键优化说明
- 消除全局依赖:将
app实例保存为类属性,确保操作的是正确实例,避免作用域冲突 - 优雅终止流程:先通过
app.stop()停止qi框架服务,再正常退出进程,彻底解决异常抛出问题 - 适配行走场景:新增
ALMotion服务调用,紧急停止时主动终止行走动作 - 异步任务执行:所有任务调用添加
_async=True参数,避免阻塞事件循环,确保触摸事件能被及时响应 - 防止重复触发:断开触摸订阅后将信号ID置空,避免重复操作引发错误
内容的提问来源于stack exchange,提问作者Mathews
相关产品推荐
相关产品推荐

