You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ROS Python中如何在回调函数外获取/joy节点的按键输入以退出自动模式

ROS Python中如何在回调函数外获取/joy节点的按键输入以退出自动模式

看起来你遇到的核心问题是自动模式的while循环阻塞了ROS的回调处理,导致新的手柄按键消息没法被更新到循环里的data变量中。我来给你梳理下问题原因和解决办法:

问题根源

你原来的代码里,当进入automatic(data)函数后,while True是一个没有任何延迟的死循环,会一直占用CPU,导致ROS的回调线程没有机会处理新的/joy消息。而且就算回调能触发,循环里用到的data还是进入函数时的旧参数,不会自动同步最新的按键状态。

解决方案:用全局变量存储最新按键状态+ROS Rate控制循环

我们可以把手柄的按键状态存在全局变量里,让回调函数实时更新它,同时在自动模式的循环里用ROS的Rate来控制频率,给回调线程留出处理消息的时间。

步骤1:定义全局变量存储状态

先声明全局变量来保存最新的按键状态和当前模式:

import rospy
from sensor_msgs.msg import Joy
import cv2

# 根据你的手柄按键数量调整数组长度
latest_joy_buttons = [0] * 12
latest_joy_axes = [0] * 8  # 存储摇杆轴数据,供手动模式使用
automatic_mode = 0

步骤2:修改回调函数更新全局状态

让回调函数每次收到/joy消息时,就更新全局的按键和摇杆状态,同时处理模式切换:

def callback(data):
    global latest_joy_buttons, latest_joy_axes, automatic_mode
    rospy.loginfo(rospy.get_caller_id() + "motor variables: %s, %s, %s", data.axes[2], data.buttons[2], data.buttons[3])
    
    # 实时更新全局的按键和摇杆状态
    latest_joy_buttons = data.buttons.copy()
    latest_joy_axes = data.axes.copy()
    
    # 处理模式切换按钮
    if latest_joy_buttons[2] == 1:
        automatic_mode = 1
    if latest_joy_buttons[3] == 1:
        automatic_mode = 0

步骤3:重构自动模式函数

不要用死循环,改用ROS的Rate来控制循环频率,这样每次循环都会检查最新的全局按键状态,同时让ROS有时间处理回调:

def automatic():
    # 设置循环频率(比如30Hz,可根据你的需求调整)
    rate = rospy.Rate(30)
    
    # 循环条件:ROS没关闭,且当前处于自动模式
    while not rospy.is_shutdown() and automatic_mode == 1:
        # 这里放你的自动循线逻辑
        # 比如读取摄像头帧、检测黑线、计算电机控制指令...
        
        # 检查退出按键(按钮3是否被按下)
        if latest_joy_buttons[3] == 1:
            automatic_mode = 0
            rospy.loginfo("已退出自动模式")
            break
        
        # 必须调用这个,让ROS处理回调消息
        rate.sleep()

步骤4:重构手动模式函数

手动模式也基于全局的最新摇杆状态来处理,确保控制逻辑实时响应手柄输入:

def manual():
    # 获取最新的摇杆数据(比如你用到的axes[2])
    current_axis_value = latest_joy_axes[2]
    # 这里放手动控制电机的逻辑
    # 比如根据摇杆值调整左右电机转速...

步骤5:主线程循环处理模式切换

最后在主函数里,用一个循环来根据当前模式调用对应的函数,确保主线程不被阻塞:

def main():
    rospy.init_node('robot_controller', anonymous=True)
    # 订阅/joy话题
    rospy.Subscriber("/joy", Joy, callback)
    
    rate = rospy.Rate(30)
    while not rospy.is_shutdown():
        if automatic_mode == 1:
            automatic()
        else:
            manual()
        rate.sleep()

if __name__ == '__main__':
    try:
        main()
    except rospy.ROSInterruptException:
        pass

额外提示

  • 默认情况下ROS的回调是在单线程里执行的,所以只要不同时在多个线程修改全局变量,就不会有线程安全问题。
  • 你可以根据自己手柄的实际按键数量调整latest_joy_buttons的数组长度,避免索引越界。

备注:内容来源于stack exchange,提问作者Cooler Mann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 15:03:10