x264参数注解:x264_param_t

本文详细介绍了x264编码器的主要参数配置,包括并行编码、视频属性、流参数、码率控制等核心内容,帮助读者理解并合理设置这些参数以达到最佳编码效果。

typedef struct x264_param_t

{

    /* CPU 标志位 */

    unsigned int cpu;

    int         i_threads;       /* 并行编码多帧 */

    int         b_deterministic; /*是否允许非确定性时线程优化*/

    int         i_sync_lookahead; /* 线程超前缓冲 */

 

    /* 视频属性 */

    int         i_width; /* 宽度*/

    int         i_height; /* 高度*/

    int         i_csp;  /* 编码比特流的CSP,仅支持i420,色彩空间设置 */

    int         i_level_idc; /* level值的设置*/

    int         i_frame_total; /* 编码帧的总数, 默认 0 */

/*Vui参数集视频可用性信息视频标准化选项 */

    struct

    {

        /* they will be reduced to be 0 < x <= 65535 and prime */

        int         i_sar_height;

        int         i_sar_width; /* 设置长宽比 */

 

        int         i_overscan;    /* 0=undef, 1=no overscan, 2=overscan 过扫描线,默认"undef"(不设置),可选项:show(观看)/crop(去除)*/

 

        /*见以下的值h264附件E */

        Int       i_vidformat;/* 视频格式,默认"undef",component/pal/ntsc/secam/mac/undef*/

        int       b_fullrange; /*Specify full range samples setting,默认"off",可选项:off/on*/

        int       i_colorprim; /*原始色度格式,默认"undef",可选项:undef/bt709/bt470m/bt470bg,smpte170m/smpte240m/film*/

        int   i_transfer; /*转换方式,默认"undef",可选项:undef/bt709/bt470m/bt470bg/linear,log100/log316/smpte170m/smpte240m*/

        int  i_colmatrix; /*色度矩阵设置,默认"undef",undef/bt709/fcc/bt470bg,smpte170m/smpte240m/GBR/YCgCo*/

        int         i_chroma_loc;    /* both top & bottom色度样本指定,范围0~5,默认0 */

    } vui;

 

    int         i_fps_num;

    int         i_fps_den;

/*这两个参数是由fps帧率确定的,赋值的过程见下:

{        float fps;       

 if( sscanf( value, "%d/%d", &p->i_fps_num, &p->i_fps_den ) == 2 )

            ;

        else if( sscanf( value, "%f", &fps ) )

        {

            p->i_fps_num = (int)(fps * 1000 + .5);

            p->i_fps_den = 1000;

        }

        else

            b_error = 1;

    }

Value的值就是fps。*/

 

    /*流参数 */

    int         i_frame_reference;  /* 参考帧最大数目 */

    int         i_keyint_max;       /* 在此间隔设置IDR关键帧 */

    int         i_keyint_min;       /* 场景切换少于次值编码位I, 而不是 IDR. */

    int         i_scenecut_threshold; /*如何积极地插入额外的I帧 */

    int         i_bframe;   /*两个相关图像间P帧的数目 */

    int         i_bframe_adaptive; /*自适应B帧判定*/

    int         i_bframe_bias; /*控制插入B帧判定,范围-100~+100,越高越容易插入B帧,默认0*/

    int         b_bframe_pyramid;   /*允许部分B为参考帧 */

/*去块滤波器需要的参数*/

    int         b_deblocking_filter;

    int         i_deblocking_filter_alphac0;    /* [-6, 6] -6 light filter, 6 strong */

    int         i_deblocking_filter_beta;       /* [-6, 6]  idem */

   /*熵编码 */

    int         b_cabac;

    int         i_cabac_init_idc;

 

    int         b_interlaced; /* 隔行扫描 */

    /*量化 */

    int         i_cqm_preset;         /*自定义量化矩阵(CQM),初始化量化模式为flat*/

    char        *psz_cqm_file;      /* JM format读取JM格式的外部量化矩阵文件,自动忽略其他—cqm 选项*/

    uint8_t     cqm_4iy[16];        /* used only if i_cqm_preset == X264_CQM_CUSTOM */

    uint8_t     cqm_4ic[16];

    uint8_t     cqm_4py[16];

    uint8_t     cqm_4pc[16];

    uint8_t     cqm_8iy[64];

    uint8_t     cqm_8py[64];

 

    /* 日志 */

    void        (*pf_log)( void *, int i_level, const char *psz, va_list );

    void        *p_log_private;

    int         i_log_level;

    int         b_visualize;

    char        *psz_dump_yuv;  /* 重建帧的名字 */

 

    /* 编码分析参数*/

    struct

    {

        unsigned int intra;     /* 帧间分区*/

        unsigned int inter;     /* 帧内分区 */

 

        int          b_transform_8x8; /* 帧间分区*/

        int          b_weighted_bipred; /*为b帧隐式加权 */

        int          i_direct_mv_pred; /*时间空间队运动预测 */

        int          i_chroma_qp_offset; /*色度量化步长偏移量 */

 

        int          i_me_method; /* 运动估计算法 (X264_ME_*) */

        int          i_me_range; /* 整像素运动估计搜索范围 (from predicted mv) */

        int          i_mv_range; /* 运动矢量最大长度(in pixels). -1 = auto, based on level */

        int          i_mv_range_thread; /* 线程之间的最小空间. -1 = auto, based on number of threads. */

        int          i_subpel_refine; /* 亚像素运动估计质量 */

        int          b_chroma_me; /* 亚像素色度运动估计和P帧的模式选择 */

        int          b_mixed_references; /*允许每个宏块的分区在P帧有它自己的参考号*/

        int          i_trellis;  /* Trellis量化,对每个8x8的块寻找合适的量化值,需要CABAC,默认0 0:关闭1:只在最后编码时使用2:一直使用*/

        int          b_fast_pskip; /*快速P帧跳过检测*/

        int          b_dct_decimate; /* 在P-frames转换参数域 */

        int          i_noise_reduction; /*自适应伪盲区 */

        float        f_psy_rd; /* Psy RD strength */

        float        f_psy_trellis; /* Psy trellis strength */

        int          b_psy; /* Toggle all psy optimizations */

 

        /*,亮度量化中使用的无效区大小*/

        int          i_luma_deadzone[2]; /* {帧间, 帧内} */

 

        int          b_psnr;    /* 计算和打印PSNR信息 */

        int          b_ssim;    /*计算和打印SSIM信息*/

    } analyse;

 

    /* 码率控制参数 */

    struct

    {

        int         i_rc_method;    /* X264_RC_* */

 

        int         i_qp_constant;  /* 0-51 */

        int         i_qp_min;       /*允许的最小量化值 */

        int         i_qp_max;       /*允许的最大量化值*/

        int         i_qp_step;      /*帧间最大量化步长 */

 

        int         i_bitrate;  /*设置平均码率 */

        float       f_rf_constant;  /* 1pass VBR, nominal QP */

        float       f_rate_tolerance;

        int         i_vbv_max_bitrate; /*平均码率模式下,最大瞬时码率,默认0(与-B设置相同) */

        int         i_vbv_buffer_size; /*码率控制缓冲区的大小,单位kbit,默认0 */

        float       f_vbv_buffer_init; /* <=1: fraction of buffer_size. >1: kbit码率控制缓冲区数据保留的最大数据量与缓冲区大小之比,范围0~1.0,默认0.9*/

        float       f_ip_factor;

        float       f_pb_factor;

 

        int         i_aq_mode;      /* psy adaptive QP. (X264_AQ_*) */

        float       f_aq_strength;

        int         b_mb_tree;      /* Macroblock-tree ratecontrol. */

        int         i_lookahead;

 

        /* 2pass 多次压缩码率控制 */

        int         b_stat_write;   /* Enable stat writing in psz_stat_out */

        char        *psz_stat_out;

        int         b_stat_read;    /* Read stat from psz_stat_in and use it */

        char        *psz_stat_in;

 

        /* 2pass params (same as ffmpeg ones) */

        float       f_qcompress;    /* 0.0 => cbr, 1.0 => constant qp */

        float       f_qblur;        /*时间上模糊量化 */

        float       f_complexity_blur; /* 时间上模糊复杂性 */

        x264_zone_t *zones;         /* 码率控制覆盖 */

        int         i_zones;        /* number of zone_t's */

        char        *psz_zones;     /*指定区的另一种方法*/

    } rc;

 

    /* Muxing parameters */

    int b_aud;                  /*生成访问单元分隔符*/

    int b_repeat_headers;       /* 在每个关键帧前放置SPS/PPS*/

    int i_sps_id;               /* SPS 和 PPS id 号 */

 

    /*切片(像条)参数 */

    int i_slice_max_size;    /* 每片字节的最大数,包括预计的NAL开销. */

    int i_slice_max_mbs;     /* 每片宏块的最大数,重写 i_slice_count */

    int i_slice_count;       /* 每帧的像条数目: 设置矩形像条. */

 

    /* Optional callback for freeing this x264_param_t when it is done being used.

     * Only used when the x264_param_t sits in memory for an indefinite period of time,

     * i.e. when an x264_param_t is passed to x264_t in an x264_picture_t or in zones.

     * Not used when x264_encoder_reconfig is called directly. */

    void (*param_free)( void* );

} x264_param_t;

#!/usr/bin/python3 # -*- coding: utf-8 -*- # 脚本解释器声明:指定使用 Python3 运行,编码格式为 UTF-8(支持中文注释和字符串) # 导入依赖库 import cv2 # OpenCV 库:图像处理、窗口显示、鼠标事件 import time # 时间库:延时、计时 import copy # 复制库:深拷贝数据,避免原数据被修改 import numpy as np # 数值计算库:矩阵运算、三角函数 import threading # 多线程库:独立线程处理图像显示(避免阻塞主逻辑) import queue # 队列库:线程间数据通信(图像显示队列、鼠标点击队列) from utils import * # 自定义工具库:包含抓取参数类(GrabParam)、坐标转换等函数 # ROS 相关库导入 import rospy # ROS 核心库:节点初始化、话题订阅/发布 from cv_bridge import CvBridge # 图像格式转换:ROS Image ↔ OpenCV 图像 from std_msgs.msg import Bool, String # ROS 标准消息:布尔、字符串 from sensor_msgs.msg import CameraInfo, Image, JointState # 传感器消息:相机参数、图像、关节状态 from user_msgs.msg import ObjDet, ObjDets # 自定义消息:单个目标检测结果、多个目标检测结果 from geometry_msgs.msg import PoseStamped # 几何消息:机械臂目标位姿 # ========================== 全局变量定义(跨函数/线程共享数据)========================== img_raw = None # 存储原始相机图像(从 ROS 话题订阅) cylinder_dets = None # 存储圆柱目标检测结果(从 YOLO 检测话题订阅) arm_ik_servo_degree = JointState() # 存储机械臂逆运动学计算出的关节角度 get_cmd_ik = False # 逆解结果接收标志:True=已收到有效关节角度 # 线程锁:解决多线程并发访问全局变量的冲突(图像和检测结果为多线程共享) img_lock = threading.Lock() # 图像数据锁:保护 img_raw 的读写 det_lock = threading.Lock() # 检测结果锁:保护 cylinder_dets 的读写 # 线程间通信队列 display_queue = queue.Queue(maxsize=1) # 图像显示队列(限制最大1个元素,避免缓存堆积) click_queue = queue.Queue() # 鼠标点击队列:存储鼠标左键点击的坐标(x,y) exit_event = threading.Event() # 线程退出事件:用于优雅关闭所有线程 # ========================== ROS 话题回调函数(数据接收)========================== def image_raw_cb(msg: Image): """ 相机图像回调函数:订阅相机原始图像,转换为 OpenCV 格式并存储到全局变量 :param msg: ROS 图像消息(/ascamera_hp60c/rgb0/image 话题) """ global img_raw bridge = CvBridge() # 创建图像转换实例 with img_lock: # 加锁:确保同一时间只有一个线程读写 img_raw img_raw = bridge.imgmsg_to_cv2(msg, 'bgr8') # ROS Image → OpenCV BGR 图像 def cylinder_dets_cb(msg: ObjDets): """ 圆柱检测结果回调函数:订阅 YOLO 检测到的圆柱目标,存储到全局变量 :param msg: 自定义消息(/usb_cam/obj_dets_with_pose 话题),包含所有检测到的圆柱信息 """ global cylinder_dets with det_lock: # 加锁:确保同一时间只有一个线程读写 cylinder_dets cylinder_dets = msg def arm_ik_servo_degree_cb(msg:JointState): """ 机械臂逆解结果回调函数:订阅机械臂逆运动学节点计算出的关节角度 :param msg: 关节状态消息(当前命名空间下的 arm_ik_servo_degree 话题) """ global arm_ik_servo_degree, get_cmd_ik arm_ik_servo_degree = msg # 更新关节角度数据 get_cmd_ik = True # 置位“已收到逆解结果”标志 # ========================== 图像处理与显示函数(多线程相关)========================== def draw_detections(img): """ 在图像上绘制检测结果:给每个圆柱目标画 bounding box 和标签 :param img: 原始 OpenCV 图像 :return: 绘制了检测结果的图像副本(不修改原图像) """ img_copy = img.copy() # 深拷贝图像,避免修改原数据 with det_lock: # 加锁:安全访问检测结果 if cylinder_dets is not None: # 如果有检测结果 for det in cylinder_dets.dets: # 遍历每个检测到的圆柱 det: ObjDet # 类型注解:明确 det 是 ObjDet 类型 # 计算 bounding box 左上角(tl)和右下角(br)坐标(像素) tl = (int(det.bbox.x1), int(det.bbox.y1)) br = (int(det.bbox.x2), int(det.bbox.y2)) # 设置颜色:红色圆柱→红色(0,0,255),蓝色圆柱→蓝色(255,0,0) color = (0, 0, 255) if det.label == "red_cylinder" else (255, 0, 0) # 绘制矩形框(线宽2) cv2.rectangle(img_copy, tl, br, color, 2) # 绘制标签文字(在矩形框左上角上方,字体、大小0.5、线宽1) cv2.putText(img_copy, det.label, (tl[0], tl[1]-5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 1) return img_copy # 返回绘制后的图像 def mouse_callback(event, x, y, flags, param): """ 鼠标回调函数:绑定到显示窗口,监听鼠标左键点击事件 :param event: 鼠标事件类型(如左键点击、移动等) :param x: 鼠标点击的 x 坐标(像素) :param y: 鼠标点击的 y 坐标(像素) :param flags: 鼠标按键状态(如是否按住) :param param: 额外参数(此处未使用) """ if event == cv2.EVENT_LBUTTONDOWN: # 如果是鼠标左键按下 click_queue.put((x, y)) # 将点击坐标放入队列,供主线程处理 def t_display(): """ 图像显示线程函数:独立线程运行,负责显示相机图像和检测结果,监听鼠标/键盘事件 作用:避免图像显示阻塞主逻辑(如机械臂控制、目标抓取) """ # 创建 OpenCV 显示窗口,窗口名=Camera cv2.namedWindow('Camera') # 绑定鼠标回调函数:将鼠标事件与 mouse_callback 关联 cv2.setMouseCallback('Camera', mouse_callback) # 循环运行,直到收到退出事件 while not exit_event.is_set(): try: current_img = None # 存储当前要显示的图像 with img_lock: # 加锁读取图像 if img_raw is not None: current_img = img_raw.copy() # 拷贝图像,避免原数据被修改 if current_img is None: # 如果没有收到图像,短暂休眠后继续 time.sleep(0.01) continue # 在图像上绘制检测结果 img_with_dets = draw_detections(current_img) # 显示图像 cv2.imshow('Camera', img_with_dets) # 监听键盘事件(等待1ms,避免阻塞) key = cv2.waitKey(1) & 0xff if key == 27: # 按下 ESC 键(ASCII 码27),触发退出事件 exit_event.set() break except Exception as e: # 捕获异常,打印错误日志并退出 rospy.logerr(f"Display thread error: {str(e)}") exit_event.set() break # 线程退出时,关闭所有 OpenCV 窗口 cv2.destroyAllWindows() # ========================== 主函数(核心逻辑:参数初始化+线程管理+抓取控制)========================== def main(): # 声明使用全局变量 global img_raw, cylinder_dets, arm_ik_servo_degree, get_cmd_ik # 1. 初始化 ROS 节点:节点名=grab_cylinder_node,anonymous=True→自动添加随机后缀(避免节点名冲突) rospy.init_node('grab_cylinder_node', anonymous=True) # 2. 从 ROS 命名空间判断机械臂方向(左/右) arm_ns = rospy.get_namespace() # 获取当前节点的命名空间(如 /arm_left/ 或 /arm_right/) arm_dir = arm_ns[5:-1] # 提取命名空间中的方向字段:/arm_left/ → 切片后为 left(索引5到-1,去除前缀/arm_和后缀/) # 判断机械臂方向:left→左臂(lr=True),right→右臂(lr=False),默认左臂 if arm_dir in ['l', 'L', 'left', 'Left', 'LEFT']: lr = True # 左臂标志 elif arm_dir in ['r', 'R', 'right', 'Right', 'RIGHT']: lr = False # 右臂标志 else: lr = True # 默认左臂 # 3. 初始化抓取参数(GrabParam 为自定义类,存储相机内参、坐标转换参数等) grab_param = GrabParam() # 等待并获取相机内参消息(/ascamera_hp60c/rgb0/camera_info 话题),超时则报错 camera_info_msg: CameraInfo = rospy.wait_for_message('/ascamera_hp60c/rgb0/camera_info', CameraInfo, timeout=None) # 相机内参赋值(K矩阵:fx, fy 为焦距;cx, cy 为主点坐标) grab_param.cx = camera_info_msg.K[2] grab_param.cy = camera_info_msg.K[5] grab_param.fx = camera_info_msg.K[0] grab_param.fy = camera_info_msg.K[4] # 从 ROS 参数服务器读取坐标转换参数(launch 文件中加载) grab_param.t_arm_2_car = rospy.get_param('translation', [0, 0, 0]) # 机械臂→车体的平移向量(x,y,z) grab_param.t_cam_2_car = rospy.get_param('/ascamera/translation', [0, 0, 0]) # 相机→车体的平移向量 grab_param.rpy_cam_2_car = rospy.get_param('/ascamera/rotation', [-90, 0, -90]) # 相机→车体的姿态(欧拉角,度) # 读取抓取相关参数(视觉识别区域、目标距离、机械臂爪部参数) grab_param.sight_middle_h = rospy.get_param('/grab_param/sight_middle_h', 300) # 视觉区域中线(高度方向像素) grab_param.sight_middle_w = rospy.get_param('/grab_param/sight_middle_w', [269, 457]) # 视觉区域左右边界(像素) grab_param.x_obj_to_cam_close = rospy.get_param('/grab_param/x_obj_to_cam_close', 0.205) # 目标→相机近距离(m) grab_param.x_obj_to_cam_middle = rospy.get_param('/grab_param/x_obj_to_cam_middle', 0.26) # 目标→相机中距离(m) grab_param.x_obj_to_cam_far = rospy.get_param('/grab_param/x_obj_to_cam_far', 0.34) # 目标→相机远距离(m) x_j5_2_claw = rospy.get_param('/grab_param/x_j5_2_claw', 0.085) # 关节5→爪部的x方向距离(m) z_j5_2_claw = rospy.get_param('/grab_param/z_j5_2_claw', 0.0115) # 关节5→爪部的z方向距离(m) # 计算关节5→爪部的直线距离和角度(用于逆运动学计算) grab_param.l_j5_2_claw = np.sqrt(x_j5_2_claw**2 + z_j5_2_claw**2) grab_param.theta_j5_2_claw = np.rad2deg(np.arctan2(z_j5_2_claw, x_j5_2_claw)) # 读取爪部开合角度参数(从参数服务器获取,左右臂独立配置) tight = rospy.get_param('claw_tight', 0) # 爪部夹紧角度(度) loose = rospy.get_param('claw_loose', 70) # 爪部松开角度(度) # 4. 初始化机械臂关节状态消息(6个关节:joint1~joint6) arm_servo_degree = JointState() arm_servo_degree.name = ["joint1", "joint2", "joint3", "joint4", "joint5", "joint6"] # 5. 创建 ROS 话题订阅者(接收数据) image_raw_sub = rospy.Subscriber('/ascamera_hp60c/rgb0/image', Image, image_raw_cb) # 订阅相机图像 cylinder_dets_sub = rospy.Subscriber('/usb_cam/obj_dets_with_pose', ObjDets, cylinder_dets_cb) # 订阅圆柱检测结果 arm_servo_degree_sub = rospy.Subscriber("arm_ik_servo_degree", JointState, arm_ik_servo_degree_cb) # 订阅逆解结果 # 6. 创建 ROS 话题发布者(发送指令) arm_target_pose_pub = rospy.Publisher('arm_target', PoseStamped, queue_size=3) # 发布机械臂目标位姿 arm_servo_degree_pub = rospy.Publisher('arm_joint_states', JointState, queue_size=3) # 发布机械臂关节角度指令 # 7. 初始化 TF 监听器(用于坐标转换,如相机坐标系→机械臂基坐标系) tf_buffer = tf2_ros.Buffer() tf_listener = tf2_ros.TransformListener(tf_buffer) # 8. 启动图像显示线程(后台运行,不阻塞主逻辑) display_thread = threading.Thread(target=t_display, daemon=True) # daemon=True→主线程退出时子线程自动退出 display_thread.start() # 9. 主循环:监听鼠标点击→选择目标→计算位姿→控制机械臂抓取 while not exit_event.is_set() and not rospy.is_shutdown(): try: # 检查鼠标点击队列是否有数据(用户是否点击了图像中的圆柱) if not click_queue.empty(): # 获取鼠标点击坐标(x,y 为像素坐标) x, y = click_queue.get(timeout=0.1) # 安全读取检测结果(加锁) with det_lock: if cylinder_dets is None: # 无检测结果,跳过 continue else: dets_copy: ObjDets = copy.copy(cylinder_dets) # 深拷贝,避免原数据被修改 # 初始化目标中心像素坐标和选中的检测结果 center_pix = [x, y] selected_det = None # 遍历所有检测结果,判断点击坐标是否在某个圆柱的 bounding box 内 for det in dets_copy.dets: det: ObjDet # 条件:点击坐标在当前圆柱的矩形框内(x1≤x≤x2 且 y1≤y≤y2) if (det.bbox.x1 <= x <= det.bbox.x2) and (det.bbox.y1 <= y <= det.bbox.y2): center_pix = [det.bbox.x, det.bbox.y] # 更新为圆柱的中心像素坐标 selected_det = det # 标记当前圆柱为选中目标 break # 找到选中目标,退出循环 # 如果未点击到任何圆柱,打印提示并继续等待 if selected_det is None: print("未点击到任何圆柱体,重新点击...") continue # 打印选中目标的信息(标签+中心像素坐标) print(f"\n选中圆柱体: {selected_det.label} ,中心像素坐标 ({center_pix[0]}, {center_pix[1]})\n") # 机械臂抓取范围检查:左臂只能抓左侧圆柱,右臂只能抓右侧圆柱 if lr: # 左臂 if center_pix[0] < grab_param.sight_middle_w[1]: # 圆柱在左半边视野(符合左臂抓取范围) pass else: print("左臂无法抓取右侧圆柱体,请点击左侧目标!") continue else: # 右臂 if center_pix[0] > grab_param.sight_middle_w[0]: # 圆柱在右半边视野(符合右臂抓取范围) pass else: print("右臂无法抓取左侧圆柱体,请点击右侧目标!") continue # 10. 计算机械臂抓取位姿 # calc_j5_from_claw:自定义函数(utils.py),根据像素坐标计算关节5的目标位姿 pose = calc_j5_from_claw(lr, center_pix, 0, grab_param) # calc_grab:自定义函数(utils.py),将关节5位姿转换为机械臂基坐标系下的目标位姿 pose_in_arm_base = calc_grab(arm_ns, pose, tf_buffer) # 发布机械臂目标位姿(供逆运动学节点计算关节角度) arm_target_pose_pub.publish(pose_in_arm_base) # 等待逆运动学计算结果(超时2秒) t0 = time.time() while not get_cmd_ik and (time.time() - t0 < 2): pass # 循环等待,直到收到逆解结果或超时 # 根据圆柱在图像中的位置,判断抓取优先级(middle/top/bottom) if det.bbox.y <= grab_param.sight_middle_h and grab_param.sight_middle_w[0] <= det.bbox.x <= grab_param.sight_middle_w[1]: position_level = "middle" # 中间区域(优先抓取) elif det.bbox.y <= grab_param.sight_middle_h: position_level = "top" # 上半区域 else: position_level = "bottom" # 下半区域 # 如果收到逆解结果,控制机械臂抓取 if get_cmd_ik: grab_degree = arm_ik_servo_degree.position # 获取逆解计算出的关节角度 get_cmd_ik = False # 复位逆解接收标志 print(f"开始抓取 {selected_det.label},抓取区域:{position_level}\n") # grab:自定义函数(arm_motions.py),控制机械臂按关节角度执行抓取动作 grab(grab_degree, loose, tight, lr, arm_servo_degree, arm_servo_degree_pub, position_level) else: # 没有鼠标点击,短暂休眠(避免占用过多CPU) time.sleep(0.01) except queue.Empty: # 队列空异常(正常情况,继续循环) continue except Exception as e: # 其他异常:打印错误日志并触发退出 rospy.logerr(f"Main thread error: {str(e)}") exit_event.set() # 11. 退出清理:触发退出事件,等待显示线程结束 exit_event.set() display_thread.join(timeout=1.0) # 等待1秒,确保显示线程正常关闭 # ========================== 程序入口 ========================== if __name__ == "__main__": main() # 启动主函数修改后完整代码发我
最新发布
12-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值