Livox ROS Driver 2,录制/livox/lidar话题为rosbag,并将PointCloud2点云数据合并保存为pcd

首先创建功能包,也可以使用已有功能包

catkin_create_pkg pcd_packge rospy roscpp std_msgs geometry_msgs

然后,新建pcd_get.py,完整python代码如下

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import rospy
import rosbag
from sensor_msgs.msg import PointCloud2
from sensor_msgs import point_cloud2
import open3d as o3d
import numpy as np
import os

# 回调函数:收到第一个点云数据后开始录制 rosbag
def point_cloud_callback(msg, bag):
    # 将收到的点云消息写入 rosbag 文件
    bag.write("/livox/lidar", msg)

# 录制 rosbag
def record_and_save_pcd(time_record, bag_save_path):
    rospy.init_node('lidar_record_node', anonymous=True)

    # 设置循环频率
    rate = rospy.Rate(10)  # 10 Hz,即每秒检查10次

    # 创建 rosbag 文件对象
    with rosbag.Bag(bag_save_path, 'w') as bag:
        # 订阅 /livox/lidar 点云话题
        lidar_subscriber = rospy.Subscriber("/livox/lidar", PointCloud2, point_cloud_callback, callback_args=bag)

        # 等待第一次接收到点云数据,才开始录制
        rospy.loginfo("Waiting for first point cloud message...")

        # 用于记录开始时间
        start_time = None
        recording_started = False

        # 继续运行直到录制时间达到 time_record
        while not rospy.is_shutdown():
            if not recording_started:
                # 如果尚未开始录制,则记录开始时间
                start_time = rospy.get_time()
                recording_started = True
                rospy.loginfo("Recording started.")

            # 检查是否已经录制了足够的时间
            if rospy.get_time() - start_time >= time_record:
                rospy.loginfo("Recording finished. Stopping rosbag...")
                # 停止订阅话题
                lidar_subscriber.unregister()
                break

            rate.sleep()  # 按照设定频率休眠

# 从 rosbag 文件读取数据并保存为 pcd
def bag_to_pcd(bag_path, pcd_path, voxel_size):
    """
    将 .bag 文件中的 PointCloud2 数据转换为 PCD 文件并保存,
    先进行体素下采样,再保存为 PCD 文件。
    
    参数:
    bag_path: .bag 文件路径
    pcd_path: 保存 PCD 文件的路径
    voxel_size: 体素下采样的尺寸(体素大小)
    """
    # 读取 .bag 文件
    bag_file = rosbag.Bag(bag_path, 'r')

    # 获取 '/livox/lidar' 话题的数据
    lidar_data = bag_file.read_messages(topics=['/livox/lidar'])

    # 创建一个空的点云对象
    pcd = o3d.geometry.PointCloud()

    # 解析 PointCloud2 消息并提取点云
    def parse_point_cloud2(msg):
        # 使用 sensor_msgs 的 point_cloud2 来解析消息
        pc_data = point_cloud2.read_points(msg, field_names=("x", "y", "z"), skip_nans=True)
        # 将点云数据转换为 numpy 数组
        pc_array = np.array(list(pc_data))
        return pc_array

    # 遍历所有消息并合并点云
    for _, msg, _ in lidar_data:
        # 将 PointCloud2 消息解析为 numpy 数组
        points = parse_point_cloud2(msg)
        
        # 将点云数据添加到 open3d 点云对象中
        pcd.points.extend(o3d.utility.Vector3dVector(points))

    # 进行体素下采样
    pcd_downsampled = pcd.voxel_down_sample(voxel_size)

    # 可视化下采样后的点云
    # o3d.visualization.draw_geometries([pcd_downsampled])

    # 保存下采样后的点云为 PCD 文件
    o3d.io.write_point_cloud(pcd_path, pcd_downsampled)

    # 关闭 bag 文件
    bag_file.close()

if __name__ == "__main__":
    try:
        time_record = 2.0  # 录制时间,单位为秒
        bag_save_path = "../file/livox_bag.bag"  # rosbag 保存路径
        pcd_save_path = "../file/livox_pointcloud.pcd"
        
        # 确保文件目录存在
        dir_path = os.path.dirname(bag_save_path)  # 获取文件路径的目录部分
        if not os.path.exists(dir_path):
            os.makedirs(dir_path)  # 创建文件夹(包括必要的中间目录)
            print(f"Directory {dir_path} created.")

        # 录制并保存为 pcd
        record_and_save_pcd(time_record, bag_save_path)
        bag_to_pcd(bag_save_path, pcd_save_path, voxel_size=0.01)  # 转换为 pcd
        
    except rospy.ROSInterruptException:
        pass

该代码可以将多帧的点云数据(因为livox雷达是非重复式扫描)合并到一个pcd文件。
运行:

sudo chmod +x pcd_get.py
python3 pcd_get.py  
# 或者使用rosrun运行也可
rosrun pcd_packge pcd_get.py
<think>好的,我现在需要帮用户解决如何在Ubuntu中编写一个bash脚本,实现打开新终端窗口、切换目录执行rosbag记录命令,而不立即运行它。首先,我得理清楚用户的具体需求。用户希望脚本能够自动执行这些操作,但关键点在于“不立即运行”,也就是说可能需要预先设置好命令,但实际执行时可能需要手动触发?或者用户希望将这些命令准备好,但不要立即启动rosbag record,可能是在适当的时机再运行? 不过,根据用户的问题描述,更可能的情况是用户希望脚本能够自动打开终端、切换目录,准备好rosbag命令,但不要马上开始记录,可能需要用户确认或其他操作后再执行。不过通常rosbag record一旦执行就会开始记录,所以这里可能存在理解上的偏差。或者用户可能希望将这些步骤自动化,但每个步骤需要在不同的终端窗口中运行,或者需要分步执行。 接下来,我需要回忆如何在bash脚本中打开新终端窗口执行命令。在Ubuntu中,通常可以使用gnome-terminal或xterm等终端模拟器命令来打开新窗口。例如,使用gnome-terminal --命令来启动新终端执行指定的命令。 用户需要切换到指定目录/home/optobot/ssd_disk/bag/,然后执行rosbag record命令。所以,在脚本中,每个新打开的终端窗口都需要执行cd命令切换到该目录,然后运行rosbag命令。但是,如果直接在脚本中使用gnome-terminal -e命令,需要注意参数传递的方式,可能需要使用bash -c来执行复合命令,比如: gnome-terminal -- bash -c "cd /path/to/dir && rosbag record ..." 但这里有个问题,当使用&&时,如果前面的cd命令失败,后面的命令就不会执行。所以更好的做法可能是将命令放在一个子shell中,或者用分号分隔。例如: gnome-terminal -- bash -c "cd /home/optobot/ssd_disk/bag/; rosbag record -O test.bag /livox/lidar /livox/imu /galaxy_camera/galaxy_camera/image_raw" 这样,即使cd失败,rosbag命令仍会执行,但可能不在预期的目录下。所以需要确保目录存在,或者在脚本中先检查目录是否存在。 另外,用户提到“而不立即运行它”,这可能是指rosbag record命令不要立即开始记录?但rosbag record一旦执行就会开始记录,所以可能需要用户进一步的确认。但根据用户的问题,可能误解了需求,用户可能希望将这些命令准备好,但不要马上执行,而是等待用户输入或其他条件。但根据常规理解,脚本的作用是自动执行命令,所以可能用户的意思是,脚本的作用是生成一个可以随时执行的命令,或者将命令放在终端中等待用户触发。 不过,根据用户的问题,更可能的情况是用户希望脚本启动后,自动打开终端窗口,切换到指定目录,运行rosbag命令,也就是立即开始记录。但用户的问题描述中写的是“执行'rosbag record...'命令而不立即运行它”,这里可能存在矛盾。或者可能用户希望将命令写入脚本,但不要执行,但这样的话,脚本只是生成另一个脚本文件,然后用户手动执行? 这时候需要明确用户的需求。如果用户希望创建一个脚本,当运行该脚本时,会自动打开新终端窗口,让这些窗口准备好执行相应的rosbag命令,但不要立即启动记录,可能需要用户手动按回车或其他操作。但rosbag record一旦执行就会开始,所以这个需求可能存在矛盾。 另一种可能是用户希望将命令放入终端中,但暂停执行,比如在命令前加上read等待用户输入,或者使用sleep。但用户的问题中没有提到需要暂停,只是要执行命令而不立即运行,这可能需要进一步澄清。不过根据用户提供的示例引用,其中涉及设置环境变量和创建目录,可能用户希望脚本准备好所有环境,然后执行命令,但可能引用中的步骤是分开的。 现在回到问题本身,用户需要三个步骤:打开终端、切换目录、执行rosbag命令。这可以通过在bash脚本中使用gnome-terminal命令来实现。例如,脚本中的每一行打开一个新终端窗口,执行相应的命令。例如: #!/bin/bash gnome-terminal -- bash -c "cd /home/optobot/ssd_disk/bag/ && rosbag record -O test.bag /livox/lidar /livox/imu /galaxy_camera/galaxy_camera/image_raw; exec bash" 这里,使用&&来连接cd和rosbag命令,确保只有cd成功后才执行rosbag。而exec bash是为了让终端窗口在执行完命令后保持打开状态,否则终端会立即关闭。但rosbag record会一直运行直到用户终止,所以可能不需要exec bash,因为rosbag进程会持续运行。不过为了确保终端不会在命令结束后关闭,可以添加exec bash。 但用户提到“而不立即运行它”,这可能需要进一步解释。如果用户希望脚本生成这些命令,但不要实际执行,那么可能需要将命令写入一个脚本文件,然后让用户自己去执行。但根据用户的问题,应该是希望脚本运行时自动打开终端执行这些命令。因此,可能用户表达有误,或者需要澄清。 假设用户确实希望脚本运行时自动打开终端执行这些命令,那么正确的脚本应该是: 创建一个bash脚本,比如start_rosbag.sh,内容如下: #!/bin/bash gnome-terminal --working-directory="/home/optobot/ssd_disk/bag/" -- rosbag record -O test.bag /livox/lidar /livox/imu /galaxy_camera/galaxy_camera/image_raw 这里,--working-directory选项可以直接指定新终端的工作目录,无需使用cd命令。这样更简洁,而且避免了因为cd失败导致的问题。然后直接执行rosbag命令。这样,当运行脚本时,会打开一个新终端窗口,在这个目录下执行rosbag record命令。 但用户可能需要同时打开多个终端窗口,每个执行不同的命令?不过问题中只提到一个rosbag record命令,所以可能只需要一个终端。但原问题中的命令是执行一个rosbag记录多个topic,所以只需要一个终端窗口。 因此,最终的脚本可能很简单,只需要使用gnome-terminal的--working-directory参数,传递rosbag命令即可。 另外,需要确保用户有执行权限,脚本需要chmod +x。 总结步骤: 1. 创建脚本文件,如start_recording.sh。 2. 添加shebang。 3. 使用gnome-terminal命令,指定工作目录和要执行的命令。 4. 给脚本执行权限。 5. 运行脚本。 可能的脚本内容: #!/bin/bash gnome-terminal --working-directory="/home/optobot/ssd_disk/bag/" -- rosbag record -O test.bag /livox/lidar /livox/imu /galaxy_camera/galaxy_camera/image_raw 这样,当运行这个脚本时,会打开一个新的终端窗口,切换到指定目录,开始记录rosbag。但用户提到“而不立即运行它”,这可能有矛盾。如果用户希望不立即运行rosbag,而是准备好命令让用户手动执行,那么可能需要将命令写入一个脚本文件,然后在终端中让用户手动运行。例如: 在脚本中创建另一个脚本文件,比如record_bag.sh,内容为rosbag命令,然后打开终端,切换到目录,等待用户输入执行。 但这种情况可能需要更复杂的交互,比如: #!/bin/bash mkdir -p /home/optobot/ssd_disk/bag/ cd /home/optobot/ssd_disk/bag/ echo 'rosbag record -O test.bag /livox/lidar /livox/imu /galaxy_camera/galaxy_camera/image_raw' > record_command.sh chmod +x record_command.sh gnome-terminal --working-directory="/home/optobot/ssd_disk/bag/" -- bash 这样,打开终端后,用户需要手动运行./record_command.sh。但这样可能不符合用户的需求。 回到原问题,用户可能希望脚本执行时自动打开终端,运行该命令,而“不立即运行”可能是指不在原终端中运行,而是在新终端中运行,这样原脚本可以继续执行其他操作。这种情况下,使用gnome-terminal命令是正确的,因为该命令会启动新终端异步执行命令,原脚本会继续执行后续命令(如果有的话)。 因此,用户可能误解了“不立即运行”的意思,实际上他们希望在新终端中运行,而不是阻塞原脚本。因此,正确的解决方案是使用gnome-terminal来启动新窗口执行命令,这样原脚本会立即继续执行,而rosbag命令在新窗口中运行。 因此,最终的脚本应该是: #!/bin/bash gnome-terminal --working-directory="/home/optobot/ssd_disk/bag/" -- rosbag record -O test.bag /livox/lidar /livox/imu /galaxy_camera/galaxy_camera/image_raw 用户需要确保gnome-terminal已安装,且有权限访问目录和topic。 可能的错误点:目录不存在,或者rosbag命令路径问题。因此,在脚本中添加目录检查: #!/bin/bash TARGET_DIR="/home/optobot/ssd_disk/bag/" if [ ! -d "$TARGET_DIR" ]; then echo "错误:目录 $TARGET_DIR 不存在!" exit 1 fi gnome-terminal --working-directory="$TARGET_DIR" -- rosbag record -O test.bag /livox/lidar /livox/imu /galaxy_camera/galaxy_camera/image_raw 这样更健壮。 总结,用户需要的是一个bash脚本,使用gnome-terminal打开新窗口,切换到指定目录,执行rosbag命令。因此,正确的脚本应包含上述内容,处理可能的错误情况。</think>以下是为您创建的Bash脚本解决方案: ```bash #!/bin/bash # 定义目标目录和命令 TARGET_DIR="/home/optobot/ssd_disk/bag" RECORD_CMD="rosbag record -O test.bag /livox/lidar /livox/imu /galaxy_camera/galaxy_camera/image_raw" # 检查目录是否存在 if [ ! -d "$TARGET_DIR" ]; then echo "错误:目标目录 $TARGET_DIR 不存在" >&2 exit 1 fi # 在新终端执行命令 gnome-terminal --working-directory="$TARGET_DIR" -- bash -c "$RECORD_CMD; exec bash" ``` §§ 1. 将上述代码保存为`start_rosbag.sh` 2. 赋予执行权限:`chmod +x start_rosbag.sh` 3. 执行脚本:`./start_rosbag.sh` 这个脚本通过以下方式满足需求: - 使用`--working-directory`参数直接指定工作目录 - `exec bash`保持终端窗口持续打开[^1] - 包含目录存在性检查 - 使用变量定义保证可维护性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值