Isaac Sim 4.5中iRobot Create 3机器人LightBeam传感器系统完整实现教程

首先打开script editor如下图 复制下面这个代码(注意修改相关路径为读者本地的),并运行如下图

js 复制代码
#!/usr/bin/env python3
"""
Isaac Sim 4.5 - 简化版:导入机器人和创建LightBeam传感器
"""

import omni
import omni.kit.commands
from omni.isaac.core.utils.stage import add_reference_to_stage
from omni.isaac.core.utils.extensions import enable_extension
from pxr import Gf, Sdf, UsdLux, UsdPhysics
import os
import asyncio

# ==================== 配置部分 ====================
USERNAME = os.getenv('USER') or 'user'

# 路径配置
ISAAC_ASSETS_BASE = f"/home/{USERNAME}/isaacsim_assets/Assets/Isaac/4.5"
ROBOT_USD_PATH = os.path.join(ISAAC_ASSETS_BASE, "Isaac/Robots/iRobot/create_3_with_arm.usd")
ROBOT_PRIM_PATH = "/World/create3_robot"

# 传感器配置
SENSORS_CONFIG = [
    # 底部高度传感器 - 4个方向
    {
        "name": "front_bottom",
        "relative_position": [0, 0, 0.1],
        "min_range": 0.5,
        "max_range": 8.0,
        "num_rays": 2,
        "curtain_length": 0.05,
        "forward_axis": [1, 0, 0]
    },
    {
        "name": "back_bottom",
        "relative_position": [0, 0, 0.1],
        "min_range": 0.5,
        "max_range": 8.0,
        "num_rays": 2,
        "curtain_length": 0.05,
        "forward_axis": [-1, 0, 0]
    },
    {
        "name": "left_bottom",
        "relative_position": [0, 0, 0.1],
        "min_range": 0.5,
        "max_range": 8.0,
        "num_rays": 2,
        "curtain_length": 0.05,
        "forward_axis": [0, 1, 0]
    },
    {
        "name": "right_bottom",
        "relative_position": [0, 0, 0.1],
        "min_range": 0.5,
        "max_range": 8.0,
        "num_rays": 2,
        "curtain_length": 0.05,
        "forward_axis": [0, -1, 0]
    },
    # 顶部高度传感器 - 4个方向
    {
        "name": "front_top",
        "relative_position": [0, 0, 0.9],
        "min_range": 1,
        "max_range": 8.0,
        "num_rays": 2,
        "curtain_length": 0.05,
        "forward_axis": [1, 0, 0]
    },
    {
        "name": "back_top",
        "relative_position": [0, 0, 0.9],
        "min_range": 0.5,
        "max_range": 8.0,
        "num_rays": 2,
        "curtain_length": 0.05,
        "forward_axis": [-1, 0, 0]
    },
    {
        "name": "left_top",
        "relative_position": [0, 0, 0.9],
        "min_range": 0.5,
        "max_range": 8.0,
        "num_rays": 2,
        "curtain_length": 0.05,
        "forward_axis": [0, 1, 0]
    },
    {
        "name": "right_top",
        "relative_position": [0, 0, 0.9],
        "min_range": 0.5,
        "max_range": 8.0,
        "num_rays": 2,
        "curtain_length": 0.05,
        "forward_axis": [0, -1, 0]
    }
]

print("🤖 开始导入机器人和创建传感器...")

# ==================== 基础设置 ====================
def setup_basic_scene():
    """设置基础场景"""
    print("🔧 设置基础场景...")
    
    stage = omni.usd.get_context().get_stage()
    
    # 创建物理场景
    physics_scene_path = "/World/physicsScene"
    if not stage.GetPrimAtPath(physics_scene_path):
        UsdPhysics.Scene.Define(stage, Sdf.Path(physics_scene_path))
        print("✅ 物理场景创建成功")
    
    # 添加光照
    light_path = "/World/DistantLight"
    if not stage.GetPrimAtPath(light_path):
        distantLight = UsdLux.DistantLight.Define(stage, Sdf.Path(light_path))
        distantLight.CreateIntensityAttr(1000)
        print("✅ 光照创建成功")
    
    return stage

def import_robot():
    """导入机器人模型"""
    print("🤖 导入机器人模型...")
    
    if not os.path.exists(ROBOT_USD_PATH):
        print(f"❌ 机器人文件不存在: {ROBOT_USD_PATH}")
        print("💡 请检查路径配置")
        return False
    
    try:
        add_reference_to_stage(usd_path=ROBOT_USD_PATH, prim_path=ROBOT_PRIM_PATH)
        print(f"✅ 机器人导入成功: {ROBOT_PRIM_PATH}")
        return True
    except Exception as e:
        print(f"❌ 机器人导入失败: {e}")
        return False

def create_lightbeam_sensors():
    """创建所有LightBeam传感器"""
    print("📡 创建LightBeam传感器...")
    
    # 启用传感器扩展
    enable_extension("isaacsim.sensors.physx")
    
    created_sensors = []
    
    for sensor_config in SENSORS_CONFIG:
        sensor_name = sensor_config["name"]
        sensor_path = f"{ROBOT_PRIM_PATH}/sensors/{sensor_name}"
        
        print(f"🔧 创建传感器: {sensor_name}")
        
        try:
            result, sensor = omni.kit.commands.execute(
                "IsaacSensorCreateLightBeamSensor",
                path=sensor_path,
                parent=None,  # 不指定父级,稍后手动连接
                min_range=sensor_config["min_range"],
                max_range=sensor_config["max_range"],
                translation=Gf.Vec3d(
                    sensor_config["relative_position"][0],
                    sensor_config["relative_position"][1],
                    sensor_config["relative_position"][2]
                ),
                orientation=Gf.Quatd(1, 0, 0, 0),
                forward_axis=Gf.Vec3d(
                    sensor_config["forward_axis"][0],
                    sensor_config["forward_axis"][1],
                    sensor_config["forward_axis"][2]
                ),
                num_rays=sensor_config["num_rays"],
                curtain_length=sensor_config["curtain_length"],
            )
            
            if result:
                created_sensors.append(sensor_name)
                print(f"✅ {sensor_name} 传感器创建成功")
            else:
                print(f"❌ {sensor_name} 传感器创建失败")
                
        except Exception as e:
            print(f"❌ {sensor_name} 传感器创建异常: {e}")
    
    print(f"📊 总共创建了 {len(created_sensors)} 个传感器")
    return created_sensors

# ==================== 主要执行函数 ====================
async def main():
    """主要执行函数"""
    try:
        # 1. 设置场景
        stage = setup_basic_scene()
        
        # 2. 导入机器人
        if not import_robot():
            print("❌ 机器人导入失败,停止执行")
            return
        
        # 等待导入完成
        await omni.kit.app.get_app().next_update_async()
        
        # 3. 创建传感器
        created_sensors = create_lightbeam_sensors()
        
        if created_sensors:
            print(f"\n✅ 成功创建 {len(created_sensors)} 个传感器")
            print("📋 创建的传感器列表:")
            for sensor_name in created_sensors:
                sensor_path = f"{ROBOT_PRIM_PATH}/sensors/{sensor_name}"
                print(f"   📡 {sensor_name}: {sensor_path}")
            
            print("\n💡 接下来请您手动:")
            print("1. 在Stage面板中找到机器人和传感器")
            print("2. 为每个传感器创建Fixed Joint连接到机器人")
            print("3. 点击'Play'按钮测试传感器")
        else:
            print("❌ 没有成功创建任何传感器")
        
    except Exception as e:
        print(f"❌ 执行失败: {e}")
        import traceback
        traceback.print_exc()

# 运行主函数
asyncio.ensure_future(main())

print("🚀 脚本开始执行...")

运行后输出如下图

手动加一个地板用于测试,最后删掉地板资源即可

再将下面代码覆盖到script editor中,运行

js 复制代码
#!/usr/bin/env python3
"""
Isaac Sim 4.5 - Action Graph光线可视化脚本
为8个LightBeam传感器创建可视化Action Graph
"""

import omni
import omni.graph.core as og
from omni.isaac.core.utils.extensions import enable_extension
import asyncio

# ==================== 配置部分 ====================
ROBOT_PRIM_PATH = "/World/create3_robot"

# 传感器名称列表
SENSOR_NAMES = [
    "front_bottom", "back_bottom", "left_bottom", "right_bottom",
    "front_top", "back_top", "left_top", "right_top"
]

# 颜色配置 - 不同方向和层级使用不同颜色
COLOR_CONFIG = {
    # 底层传感器 - 深色系
    "front_bottom": [1.0, 0.0, 0.0, 1.0],    # 红色
    "back_bottom": [0.0, 0.0, 1.0, 1.0],     # 蓝色
    "left_bottom": [0.0, 1.0, 0.0, 1.0],     # 绿色
    "right_bottom": [1.0, 1.0, 0.0, 1.0],    # 黄色
    
    # 顶层传感器 - 浅色系
    "front_top": [1.0, 0.5, 0.5, 1.0],       # 浅红色
    "back_top": [0.5, 0.5, 1.0, 1.0],        # 浅蓝色
    "left_top": [0.5, 1.0, 0.5, 1.0],        # 浅绿色
    "right_top": [1.0, 1.0, 0.5, 1.0],       # 浅黄色
}

print("🎨 开始创建Action Graph可视化...")

def enable_required_extensions():
    """启用必要的扩展"""
    print("🔧 启用必要扩展...")
    
    extensions = [
        "isaacsim.sensors.physx",
        "isaacsim.util.debug_draw",
        "omni.graph.action",
        "omni.graph.core"
    ]
    
    for ext in extensions:
        try:
            enable_extension(ext)
            print(f"✅ {ext} 扩展已启用")
        except Exception as e:
            print(f"⚠️ {ext} 扩展启用失败: {e}")

def create_single_sensor_visualization(sensor_name):
    """为单个传感器创建可视化Action Graph"""
    sensor_path = f"{ROBOT_PRIM_PATH}/sensors/{sensor_name}"
    graph_path = f"/ActionGraph_{sensor_name}_Viz"
    
    print(f"🎨 创建 {sensor_name} 的可视化图表...")
    
    # 获取颜色配置
    color = COLOR_CONFIG.get(sensor_name, [1.0, 0.0, 0.0, 1.0])
    
    try:
        # 检查传感器是否存在
        stage = omni.usd.get_context().get_stage()
        if not stage.GetPrimAtPath(sensor_path):
            print(f"❌ 传感器不存在: {sensor_path}")
            return False
        
        # 创建Action Graph
        (action_graph, new_nodes, _, _) = og.Controller.edit(
            {"graph_path": graph_path, "evaluator_name": "execution"},
            {
                og.Controller.Keys.CREATE_NODES: [
                    ("OnPlaybackTick", "omni.graph.action.OnPlaybackTick"),
                    ("IsaacReadLightBeam", "isaacsim.sensors.physx.IsaacReadLightBeam"),
                    ("DebugDrawRayCast", "isaacsim.util.debug_draw.DebugDrawRayCast"),
                ],
                og.Controller.Keys.SET_VALUES: [
                    ("IsaacReadLightBeam.inputs:lightbeamPrim", sensor_path),
                    ("DebugDrawRayCast.inputs:beamWidth", 0.02),  # 光束宽度
                    ("DebugDrawRayCast.inputs:color", color),     # 光束颜色
                ],
                og.Controller.Keys.CONNECT: [
                    ("OnPlaybackTick.outputs:tick", "IsaacReadLightBeam.inputs:execIn"),
                    ("IsaacReadLightBeam.outputs:execOut", "DebugDrawRayCast.inputs:exec"),
                    ("IsaacReadLightBeam.outputs:beamOrigins", "DebugDrawRayCast.inputs:beamOrigins"),
                    ("IsaacReadLightBeam.outputs:beamEndPoints", "DebugDrawRayCast.inputs:beamEndPoints"),
                    ("IsaacReadLightBeam.outputs:numRays", "DebugDrawRayCast.inputs:numRays"),
                ],
            },
        )
        
        print(f"✅ {sensor_name} 可视化图表创建成功")
        return True
        
    except Exception as e:
        print(f"❌ {sensor_name} 可视化图表创建失败: {e}")
        return False

def create_all_visualizations():
    """为所有传感器创建可视化"""
    print("🎨 为所有传感器创建可视化...")
    
    success_count = 0
    
    for sensor_name in SENSOR_NAMES:
        if create_single_sensor_visualization(sensor_name):
            success_count += 1
    
    print(f"📊 成功创建了 {success_count}/{len(SENSOR_NAMES)} 个可视化图表")
    return success_count

def list_created_graphs():
    """列出创建的Action Graph"""
    print("\n📋 创建的Action Graph列表:")
    
    stage = omni.usd.get_context().get_stage()
    
    for sensor_name in SENSOR_NAMES:
        graph_path = f"/ActionGraph_{sensor_name}_Viz"
        color = COLOR_CONFIG.get(sensor_name, [1.0, 0.0, 0.0, 1.0])
        color_desc = f"RGB({color[0]:.1f}, {color[1]:.1f}, {color[2]:.1f})"
        
        if stage.GetPrimAtPath(graph_path):
            print(f"   ✅ {sensor_name}: {graph_path} - {color_desc}")
        else:
            print(f"   ❌ {sensor_name}: 图表未创建")

# ==================== 主要执行函数 ====================
async def main():
    """主要执行函数"""
    try:
        # 1. 启用必要扩展
        enable_required_extensions()
        
        # 等待扩展加载
        await omni.kit.app.get_app().next_update_async()
        
        # 2. 创建所有可视化
        success_count = create_all_visualizations()
        
        # 3. 列出创建结果
        list_created_graphs()
        
        if success_count > 0:
            print(f"\n🎉 Action Graph创建完成!")
            print("📋 颜色说明:")
            print("   🔴 红色系: 前方传感器")
            print("   🔵 蓝色系: 后方传感器") 
            print("   🟢 绿色系: 左侧传感器")
            print("   🟡 黄色系: 右侧传感器")
            print("   🎨 深色: 底层传感器 | 浅色: 顶层传感器")
            print("\n💡 使用说明:")
            print("1. 点击'Play'按钮开始仿真")
            print("2. 观察8条不同颜色的光束线条")
            print("3. 在场景中添加物体测试光束碰撞")
            print("4. 可在Window > Visual Scripting > Action Graph查看图表")
        else:
            print("❌ 没有成功创建任何可视化图表")
            print("💡 请确保:")
            print("   1. 传感器已正确创建")
            print("   2. 机器人路径正确")
            print("   3. 必要扩展已启用")
        
    except Exception as e:
        print(f"❌ 执行失败: {e}")
        import traceback
        traceback.print_exc()

# 运行主函数
asyncio.ensure_future(main())

print("🚀 Action Graph可视化脚本开始执行...")

有些小bug,需要手动修改高度如下图

然后按左侧play键,显示如下图,没有添加关节,所以光线不会跟随机器人,是正常的

然后手动添加关节(避免父子关系错误)如下图

依次把8个传感器都链接如下图,注意ctrl先点baselink再点对应传感器,顺序影响父子关系

然后将下图文件夹移至baselink文件夹中

之后在script editor运行以下代码

js 复制代码
import omni.usd
from pxr import UsdPhysics

def complete_sensor_cleanup():
    """完整清理传感器的物理属性和Joint"""
    stage = omni.usd.get_context().get_stage()
    
    sensor_names = [
        "front_bottom", "back_bottom", "left_bottom", "right_bottom", 
        "front_top", "back_top", "left_top", "right_top"
    ]
    
    base_path = "/World/create3_robot/create_3/base_link"
    
    for sensor_name in sensor_names:
        sensor_path = f"{base_path}/{sensor_name}"
        sensor_prim = stage.GetPrimAtPath(sensor_path)
        
        print(f"🔧 完整清理传感器: {sensor_name}")
        
        if sensor_prim.IsValid():
            # 1. 移除所有物理API
            if sensor_prim.HasAPI(UsdPhysics.RigidBodyAPI):
                sensor_prim.RemoveAPI(UsdPhysics.RigidBodyAPI)
                print(f"   ✅ 移除RigidBodyAPI")
            
            if sensor_prim.HasAPI(UsdPhysics.CollisionAPI):
                sensor_prim.RemoveAPI(UsdPhysics.CollisionAPI)
                print(f"   ✅ 移除CollisionAPI")
                
            if sensor_prim.HasAPI(UsdPhysics.MassAPI):
                sensor_prim.RemoveAPI(UsdPhysics.MassAPI)
                print(f"   ✅ 移除MassAPI")
        
        # 2. 删除FixedJoint
        joint_path = f"{sensor_path}/FixedJoint"
        joint_prim = stage.GetPrimAtPath(joint_path)
        
        if joint_prim.IsValid():
            stage.RemovePrim(joint_path)
            print(f"   🗑️ 删除FixedJoint")
        
        # 3. 验证传感器状态
        if sensor_prim.IsValid():
            print(f"   ✅ {sensor_name} 清理完成")
        else:
            print(f"   ❌ {sensor_name} 不存在")
    
    print("\n🎉 传感器完整清理完成!")
    print("💡 现在传感器通过层级关系连接,无需Joint")

# 运行完整清理
complete_sensor_cleanup()

现在运行效果如下(笔者再次修改了高度后的效果)

然后也可以实时输出每个传感器方向测量的距离,在script editor运行下面代码

js 复制代码
#!/usr/bin/env python3
"""
Isaac Sim 4.5 - LightBeam Sensor Distance Monitor (ASCII Only)
Monitor all sensor distances every 5 seconds - ASCII characters only
"""

import omni
from isaacsim.sensors.physx import _range_sensor
import time
import asyncio
import numpy as np

# ==================== Configuration ====================
ROBOT_PRIM_PATH = "/World/create3_robot"

# Sensor configuration (ASCII only)
SENSORS_CONFIG = [
    {"name": "front_bottom", "layer": "Bottom", "direction": "Front", "symbol": "^"},
    {"name": "back_bottom", "layer": "Bottom", "direction": "Back", "symbol": "v"},
    {"name": "left_bottom", "layer": "Bottom", "direction": "Left", "symbol": "<"},
    {"name": "right_bottom", "layer": "Bottom", "direction": "Right", "symbol": ">"},
    {"name": "front_top", "layer": "Top", "direction": "Front", "symbol": "^"},
    {"name": "back_top", "layer": "Top", "direction": "Back", "symbol": "v"},
    {"name": "left_top", "layer": "Top", "direction": "Left", "symbol": "<"},
    {"name": "right_top", "layer": "Top", "direction": "Right", "symbol": ">"},
]

print("Starting LightBeam Sensor Distance Monitor...")

class LightBeamMonitor:
    def __init__(self):
        self.lightbeam_interface = None
        self.timeline = None
        self.monitoring = False
        self.last_output_time = 0
        self.output_interval = 5.0  # 5 seconds
        
    def initialize(self):
        """Initialize sensor interface"""
        try:
            self.lightbeam_interface = _range_sensor.acquire_lightbeam_sensor_interface()
            self.timeline = omni.timeline.get_timeline_interface()
            print("SUCCESS: Sensor interface initialized")
            return True
        except Exception as e:
            print(f"ERROR: Sensor interface failed - {e}")
            return False
    
    def get_sensor_distance(self, sensor_path):
        """Get distance data from single sensor"""
        try:
            if not self.timeline.is_playing():
                return None, 0, []
            
            # Get sensor data
            linear_depth = self.lightbeam_interface.get_linear_depth_data(sensor_path)
            beam_hit = self.lightbeam_interface.get_beam_hit_data(sensor_path)
            hit_pos = self.lightbeam_interface.get_hit_pos_data(sensor_path)
            
            if linear_depth is not None and len(linear_depth) > 0:
                valid_distances = []
                min_distance = float('inf')
                hit_count = 0
                
                for i in range(len(linear_depth)):
                    if beam_hit[i]:  # If beam hit
                        distance = linear_depth[i]
                        if distance > 0.1:  # Filter invalid data
                            valid_distances.append(distance)
                            min_distance = min(min_distance, distance)
                            hit_count += 1
                
                final_distance = min_distance if min_distance != float('inf') else None
                return final_distance, hit_count, valid_distances
            
            return None, 0, []
            
        except Exception as e:
            return None, 0, []
    
    def get_distance_status(self, distance):
        """Get status based on distance"""
        if distance is None:
            return "NO_DETECT", "[X]", "----"
        elif distance < 1.0:
            return "VERY_CLOSE", "[!]", "CRIT"
        elif distance < 2.0:
            return "CLOSE", "[*]", "WARN"
        elif distance < 4.0:
            return "MEDIUM", "[-]", "NORM"
        elif distance < 6.0:
            return "FAR", "[+]", "SAFE"
        else:
            return "VERY_FAR", "[=]", "DIST"
    
    def format_distance(self, distance):
        """Format distance display"""
        if distance is None:
            return "----m"
        else:
            return f"{distance:.2f}m"
    
    def output_all_sensor_data(self):
        """Output all sensor data"""
        if not self.timeline.is_playing():
            print("PAUSE: Simulation not running, cannot get sensor data")
            return
        
        print("\n" + "="*90)
        print(f"iRobot Create 3 - LightBeam Distance Monitor | {time.strftime('%H:%M:%S')}")
        print("="*90)
        
        # Group by layer
        layers = {"Top": [], "Bottom": []}
        
        for sensor_config in SENSORS_CONFIG:
            sensor_name = sensor_config["name"]
            # Updated sensor path - now under base_link
            sensor_path = f"{ROBOT_PRIM_PATH}/create_3/base_link/{sensor_name}"
            direction = sensor_config["direction"]
            layer = sensor_config["layer"]
            symbol = sensor_config["symbol"]
            
            # Get distance data
            distance, hit_count, all_distances = self.get_sensor_distance(sensor_path)
            status_text, status_icon, status_code = self.get_distance_status(distance)
            distance_text = self.format_distance(distance)
            
            # Build display info
            if hit_count > 1:  # Multiple beams
                avg_distance = np.mean(all_distances) if all_distances else None
                avg_text = self.format_distance(avg_distance)
                info = f"  {symbol} {direction:>5} | {distance_text:>8} (min) | {avg_text:>8} (avg) | {hit_count}rays | {status_code} {status_icon}"
            else:
                info = f"  {symbol} {direction:>5} | {distance_text:>8} | {hit_count}rays | {status_code} {status_icon}"
            
            layers[layer].append(info)
        
        # Output top layer sensors
        print("TOP Layer Sensors (Z = +0.1m):")
        for info in layers["Top"]:
            print(info)
        
        print("")
        
        # Output bottom layer sensors
        print("BOTTOM Layer Sensors (Z = -0.5m):")
        for info in layers["Bottom"]:
            print(info)
        
        # Statistics
        all_distances = []
        total_hits = 0
        active_sensors = 0
        
        for sensor_config in SENSORS_CONFIG:
            sensor_name = sensor_config["name"]
            sensor_path = f"{ROBOT_PRIM_PATH}/create_3/base_link/{sensor_name}"
            distance, hit_count, _ = self.get_sensor_distance(sensor_path)
            if distance is not None:
                all_distances.append(distance)
                active_sensors += 1
            total_hits += hit_count
        
        if all_distances:
            min_dist = min(all_distances)
            max_dist = max(all_distances)
            avg_dist = np.mean(all_distances)
            
            print("")
            print("STATISTICS:")
            print(f"  Closest: {min_dist:.2f}m | Farthest: {max_dist:.2f}m | Average: {avg_dist:.2f}m")
            print(f"  Total hits: {total_hits} | Active sensors: {active_sensors}/8")
            
            # Safety assessment
            if min_dist < 1.0:
                safety = "DANGER - AVOID IMMEDIATELY"
                safety_level = "CRITICAL"
            elif min_dist < 2.0:
                safety = "WARNING - BE CAREFUL"
                safety_level = "WARNING"
            elif min_dist < 4.0:
                safety = "CAUTION - KEEP WATCHING"
                safety_level = "CAUTION"
            else:
                safety = "SAFE - NORMAL OPERATION"
                safety_level = "NORMAL"
            
            print(f"  Safety Status: {safety} ({safety_level})")
            
            # Direction analysis
            direction_analysis = self.analyze_directions(all_distances)
            if direction_analysis:
                print(f"  Direction Advice: {direction_analysis}")
        else:
            print("")
            print("STATISTICS: No obstacles detected")
            print("  Safety Status: SAFE - NO OBSTACLES")
        
        print("="*90)
    
    def analyze_directions(self, distances):
        """Analyze safety in different directions"""
        if not distances:
            return None
        
        min_dist = min(distances)
        if min_dist > 4.0:
            return "Open space - free movement"
        elif min_dist > 2.0:
            return "Reduce speed - proceed carefully"
        else:
            return "STOP or retreat to safe distance"
    
    def start_monitoring(self):
        """Start monitoring"""
        if not self.initialize():
            return
        
        self.monitoring = True
        print("SUCCESS: Monitoring started - Output every 5 seconds")
        print("INFO: Make sure to click 'Play' button to start simulation")
        print("INFO: Press Ctrl+C to stop monitoring")
        print("INFO: Sensor paths updated for cleaned hierarchy structure\n")
        
        # Output immediately
        self.output_all_sensor_data()
        self.last_output_time = time.time()
    
    def update(self):
        """Update monitoring - call in main loop"""
        if not self.monitoring:
            return
        
        current_time = time.time()
        if current_time - self.last_output_time >= self.output_interval:
            self.output_all_sensor_data()
            self.last_output_time = current_time
    
    def stop_monitoring(self):
        """Stop monitoring"""
        self.monitoring = False
        print("\nSTOP: Monitoring stopped")
    
    def set_output_interval(self, seconds):
        """Set output interval"""
        self.output_interval = seconds
        print(f"INFO: Output interval set to {seconds} seconds")

# ==================== Global monitor instance ====================
monitor = LightBeamMonitor()

# ==================== Main execution function ====================
async def main():
    """Main execution function"""
    try:
        # Start monitoring
        monitor.start_monitoring()
        
        # Keep running monitoring
        while monitor.monitoring:
            monitor.update()
            await asyncio.sleep(0.1)  # Avoid high CPU usage
            
    except KeyboardInterrupt:
        print("\nINFO: Stop signal received...")
        monitor.stop_monitoring()
    except Exception as e:
        print(f"ERROR: Monitoring error - {e}")
        monitor.stop_monitoring()

def start_monitoring():
    """Convenient function to start monitoring"""
    asyncio.ensure_future(main())

def stop_monitoring():
    """Convenient function to stop monitoring"""
    monitor.stop_monitoring()

def set_interval(seconds):
    """Convenient function to set monitoring interval"""
    monitor.set_output_interval(seconds)

# Auto start monitoring
start_monitoring()

print("READY: Distance monitoring script started!")
print("INFO: Available commands:")
print("  - stop_monitoring(): Stop monitoring")
print("  - set_interval(seconds): Set output interval")
print("  - start_monitoring(): Restart monitoring")
js 复制代码
stop_monitoring()       #如果需要停止监控,在Script Editor中运行:

笔者添加了一个物体测试输出距离(记得开启物理属性)

不想显示光线将下面几个文件deactivate即可

最后可以调整文件布局为下图baocun

相关推荐
guygg8828 分钟前
ubuntu手动编译VTK9.3 Generating qmltypes file 失败
linux·运维·ubuntu
诗意亭序3 小时前
ubuntu16.04 虚拟机与电脑共用wifi
ubuntu
applebomb9 小时前
没合适的组合wheel包,就自行编译flash_attn吧
python·ubuntu·attention·flash
Rudon滨海渔村11 小时前
解决阿里云ubuntu内存溢出导致vps死机无法访问 - 永久性增加ubuntu的swap空间 - 阿里云Linux实例内存溢出(OOM)问题修复方案
linux·运维·ubuntu
2401_8616152813 小时前
跨平台的ARM 和 x86 Docker 镜像:汇编语言实验环境搭建
linux·汇编·ubuntu·docker·容器
Ronin30514 小时前
【Linux系统】vim编辑器 | 编译器gcc/g++ | make/Makefile
linux·运维·服务器·ubuntu·编辑器·vim
Natsuagin15 小时前
【保姆级目标检测教程】Ubuntu 20.04 部署 YOLOv13 全流程(附训练/推理代码)
yolo·目标检测·ubuntu·计算机视觉
牧以南歌〆1 天前
在Ubuntu主机中修改ARM Linux开发板的根文件系统
linux·arm开发·驱动开发·ubuntu
cuijiecheng20181 天前
Ubuntu下布署mediasoup-demo
linux·运维·ubuntu