新建ros工程并运行

#include <ros/ros.h>
#include <rosbag/bag.h>
#include <rosbag/view.h>
#include <sensor_msgs/CompressedImage.h>
#include <sensor_msgs/Imu.h>
#include <livox_ros_driver/CustomMsg.h>
#include <cv_bridge/cv_bridge.h>
#include <opencv2/opencv.hpp>
#include <boost/filesystem.hpp>
#include <fstream>
#include <iomanip> // 用于设置浮点数精度

namespace fs = boost::filesystem;

int main(int argc, char** argv) {
    ros::init(argc, argv, "bag_extractor");
    ros::NodeHandle nh;

    std::string bag_file = "/home/chenqi/catkin_ws/Data/hku1.bag";
    std::string output_dir = "/home/chenqi/catkin_ws/Data/output_hkui_data";
    
    // 创建输出目录
    if (!fs::exists(output_dir)) {
        fs::create_directories(output_dir);
        ROS_INFO("Created output directory: %s", output_dir.c_str());
    }

    // 创建子目录
    std::string left_camera_dir = output_dir + "/left_camera";
    std::string right_camera_dir = output_dir + "/right_camera";
    std::string lidar_dir = output_dir + "/lidar";

    if (!fs::exists(left_camera_dir)) {
        fs::create_directories(left_camera_dir);
        ROS_INFO("Created left camera directory: %s", left_camera_dir.c_str());
    }
    if (!fs::exists(right_camera_dir)) {
        fs::create_directories(right_camera_dir);
        ROS_INFO("Created right camera directory: %s", right_camera_dir.c_str());
    }
    if (!fs::exists(lidar_dir)) {
        fs::create_directories(lidar_dir);
        ROS_INFO("Created lidar directory: %s", lidar_dir.c_str());
    }

    // 打开rosbag文件
    rosbag::Bag bag;
    try {
        bag.open(bag_file, rosbag::bagmode::Read);
        ROS_INFO("Opened rosbag file: %s", bag_file.c_str());
    } catch (const std::exception& e) {
        ROS_ERROR("Failed to open rosbag file: %s. Error: %s", bag_file.c_str(), e.what());
        return 1;
    }

    // 创建一个视图来读取所有消息
    rosbag::View view(bag);

    cv_bridge::CvImagePtr cv_ptr;
    
    for (const rosbag::MessageInstance& m : view) {
        std::string topic = m.getTopic();
        ROS_INFO("Processing topic: %s at time %f", topic.c_str(), m.getTime().toSec());

        if (topic == "/left_camera/image/compressed" || topic == "/right_camera/image/compressed") {
            // 处理压缩图像数据
            sensor_msgs::CompressedImageConstPtr img_msg = m.instantiate<sensor_msgs::CompressedImage>();
            if (img_msg != nullptr) {
                ROS_INFO("Received image message from topic: %s", topic.c_str());
                try {
                    cv_ptr = cv_bridge::toCvCopy(img_msg, sensor_msgs::image_encodings::BGR8);
                } catch (cv_bridge::Exception& e) {
                    ROS_ERROR("cv_bridge exception: %s", e.what());
                    continue;
                }

                // 根据主题选择合适的目录
                std::string image_dir = (topic == "/left_camera/image/compressed") ? left_camera_dir : right_camera_dir;

                // 生成图像文件名
                std::ostringstream img_name_stream;
                img_name_stream << image_dir << "/image_" << std::fixed << std::setprecision(6) << m.getTime().toSec() << ".jpg";
                std::string img_name = img_name_stream.str();

                // 保存图像
                if (cv::imwrite(img_name, cv_ptr->image)) {
                    ROS_INFO("Saved image: %s", img_name.c_str());
                } else {
                    ROS_ERROR("Failed to save image: %s", img_name.c_str());
                }
            } else {
                ROS_WARN("Failed to instantiate image message from topic: %s", topic.c_str());
            }
        } else if (topic == "/livox/imu") {
            // 处理IMU数据
            sensor_msgs::ImuConstPtr imu_msg = m.instantiate<sensor_msgs::Imu>();
            if (imu_msg != nullptr) {
                std::ofstream imu_file(output_dir + "/imu_data.txt", std::ios_base::app);
                imu_file << "timestamp: " << std::fixed << std::setprecision(6) << m.getTime().toSec() << "\n";
                imu_file << "orientation: [" << imu_msg->orientation.x << ", "
                         << imu_msg->orientation.y << ", "
                         << imu_msg->orientation.z << ", "
                         << imu_msg->orientation.w << "]\n";
                imu_file << "angular_velocity: [" << imu_msg->angular_velocity.x << ", "
                         << imu_msg->angular_velocity.y << ", "
                         << imu_msg->angular_velocity.z << "]\n";
                imu_file << "linear_acceleration: [" << imu_msg->linear_acceleration.x << ", "
                         << imu_msg->linear_acceleration.y << ", "
                         << imu_msg->linear_acceleration.z << "]\n\n";
                ROS_INFO("Saved IMU data at time: %f", m.getTime().toSec());
            } else {
                ROS_WARN("Failed to instantiate IMU message from topic: %s", topic.c_str());
            }
        } else if (topic == "/livox/lidar") {
            // 处理LiDAR数据
            livox_ros_driver::CustomMsgConstPtr lidar_msg = m.instantiate<livox_ros_driver::CustomMsg>();
            if (lidar_msg != nullptr) {
                std::ostringstream lidar_file_stream;
                lidar_file_stream << lidar_dir << "/lidar_data_" << std::fixed << std::setprecision(6) << m.getTime().toSec() << ".txt";
                std::string lidar_file = lidar_file_stream.str();
                std::ofstream ofs(lidar_file);
                
                // 遍历所有点并写入文件
                for (const auto& point : lidar_msg->points) {
                    ofs << point.x << " " << point.y << " " << point.z << "\n";
                }
                ROS_INFO("Saved LiDAR data at time: %f", m.getTime().toSec());
            } else {
                ROS_WARN("Failed to instantiate LiDAR message from topic: %s", topic.c_str());
            }
        }
    }

    bag.close();
    ROS_INFO("Data extraction completed. Files are saved in %s.", output_dir.c_str());

    return 0;
}

### 设置独立的 ROS 工程

1. **创建 ROS 工程**:
   ```bash
   cd ~/catkin_ws/src
   catkin_create_pkg bag_extractor roscpp sensor_msgs cv_bridge livox_ros_driver rosbag
   ```

2. **将代码放入 src 文件夹**:
   将上面的 C++ 代码保存为 `bag_extractor_node.cpp`,放入 `bag_extractor/src/` 文件夹中。

3. **编辑 `CMakeLists.txt`**:
   在 `CMakeLists.txt` 中添加以下内容以编译节点:

cmake_minimum_required(VERSION 3.0.2)
project(bag_extractor)

find_package(catkin REQUIRED COMPONENTS
  roscpp
  sensor_msgs
  cv_bridge
  livox_ros_driver
  rosbag
)

find_package(Boost REQUIRED COMPONENTS filesystem system)

find_package(OpenCV REQUIRED)

catkin_package()

include_directories(
  ${catkin_INCLUDE_DIRS}
  ${Boost_INCLUDE_DIRS}
  ${OpenCV_INCLUDE_DIRS}
)

add_executable(bag_extractor_node src/bag_extractor_node.cpp)

target_link_libraries(bag_extractor_node
  ${catkin_LIBRARIES}
  ${Boost_LIBRARIES}
  ${OpenCV_LIBRARIES}
)

4、编译

cd ~/catkin_ws
catkin_make

source devel/setup.bash

5、验证包是否识别

使用 rospackroscd 命令检查 ROS 是否识别到 bag_extractor 包。

rospack find bag_extractor

  

6、运行

终端1:

roscore

终端2:

rosrun bag_extractor bag_extractor_node

如果终端2失败,记得检查

7. 检查 ROS 环境变量

有时,ROS 环境变量可能未正确设置。通过以下命令查看 ROS_PACKAGE_PATH 是否包含你的工作空间:


echo $ROS_PACKAGE_PATH

你应该能看到类似 ~/catkin_ws/src 的路径。如果没有,确保已经正确源化了 setup.bash

 

需要:source devel/setup.bash

### 说明

- **话题订阅**: C++ 代码中通过 `rosbag::View` 和 `MessageInstance` 实例化消息,处理与 `.bag` 文件中的各个话题相关的不同消息类型。
- **图像处理**: 使用 `cv_bridge` 和 OpenCV 将图像从 ROS 格式转换为 OpenCV 格式并保存。
- **IMU 和 LiDAR 数据处理**: 分别读取 IMU 和 LiDAR 数据,并保存到文件中。

通过这个 C++ 实现,您可以独立处理 ROS bag 文件,并将数据提取到指定目录下。

<think>好的,我现在需要帮助用户了解如何创建ROS工程以及编写和运行launch文件。首先,我需要回忆一下ROS的基本结构和相关命令。用户提到了几个引用,特别是关于launch文件的制作和工程结构的,所以应该重点围绕这些部分展开。 首先,ROS工程的创建通常是从工作空间开始的,比如使用catkin_make来初始化工作空间。用户可能已经知道一些基础,但可能需要详细的步骤。引用2中提到在功能包内创建launch文件夹,编写.py文件,这可能需要进一步解释。ROS中的launch文件是XML格式的,但用户提供的引用中有提到.py文件,这可能是指Python节点文件,或者是launch文件的编写?需要确认,不过根据引用1,launch文件是XML实现的,所以这里可能是一个混淆点,需要澄清。 接下来,创建功能包的部分,需要使用catkin_create_pkg命令,这应该在src目录下执行。然后,在功能包中创建launch文件夹,在此文件夹内编写launch文件。需要确保用户知道如何修改CMakeLists.txt和package.xml文件,以支持launch文件的运行,比如添加安装指令。 关于launch文件的编写,引用1提到launch文件可以自动启动ROS Master,所以需要说明基本结构,比如使用<launch>标签,包含节点定义的<node>元素。引用3给出了一个roslaunch的命令行示例,可能需要解释参数传递,比如a:=1这样的参数是如何在launch文件中定义的。引用4提到param和arg的区别,这可能在launch文件中需要特别说明,param是ROS参数服务器的参数,而arg是launch文件内部的变量,可以在运行时传入。 用户可能遇到的常见问题包括:如何正确设置工作空间的环境变量(source devel/setup.bash),如何确保launch文件被正确安装到share目录中,以及如何在launch文件中传递参数和设置参数。此外,可能需要提醒用户注意功能包的依赖关系,在package.xml中添加必要的依赖,比如exec_depend。 最后,生成相关问题的时候,需要考虑用户可能进一步想知道的内容,比如如何调试launch文件,如何管理多个节点,或者如何结合param和arg使用。根据引用中的内容,可以设计相关问题,比如launch文件的调试方法,参数传递的最佳实践,或者如何组织大型工程中的多个launch文件。 总结步骤应该是:创建工作空间→创建功能包→编写节点代码→配置CMakeLists.txt→创建launch文件编写→编译工程运行launch文件。需要确保每个步骤都清晰,指出可能出错的点,比如环境变量的source,launch文件的位置是否正确,参数传递的语法等。</think>### 如何创建 ROS 工程运行 launch 文件教程 #### 1. 创建 ROS 工作空间 ```bash mkdir -p ~/catkin_ws/src cd ~/catkin_ws catkin_make source devel/setup.bash # 激活工作空间环境 ``` 工作空间是ROS工程的容器,`src`目录存放功能包代码[^2]。 --- #### 2. 创建功能包 ```bash cd ~/catkin_ws/src catkin_create_pkg my_package roscpp rospy std_msgs # 创建依赖基础通信库的功能包 ``` - 功能包命名需全小写,避免特殊符号 - `rospy`和`roscpp`分别对应Python/C++节点支持 --- #### 3. 编写节点代码 在功能包的`src`目录下创建Python/C++文件,例如`my_node.py`: ```python #!/usr/bin/env python3 import rospy def main(): rospy.init_node("my_node") rospy.loginfo("节点已启动!") if __name__ == "__main__": main() ``` 需赋予执行权限: ```bash chmod +x src/my_package/src/my_node.py ``` --- #### 4. 配置编译规则 修改功能包的`CMakeLists.txt`: ```cmake catkin_package() install(PROGRAMS src/my_node.py DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} ) ``` 此步骤将节点文件安装到可执行路径。 --- #### 5. 创建 launch 文件 1. 在功能包内新建`launch`文件夹 2. 创建`my_launch.launch`文件: ```xml <launch> <!-- 启动自定义节点 --> <node pkg="my_package" type="my_node.py" name="node1" output="screen"/> <!-- 参数服务器设置 --> <param name="param1" type="int" value="10"/> <!-- 参数传递示例 --> <arg name="arg1" default="test"/> <param name="arg_param" value="$(arg arg1)"/> </launch> ``` - `pkg`指定功能包,`type`对应可执行文件名 - `output="screen"`将日志输出到终端[^1] --- #### 6. 编译与运行 ```bash cd ~/catkin_ws catkin_make # 编译工程 source devel/setup.bash roslaunch my_package my_launch.launch arg1:=new_value # 运行覆盖参数 ``` 可通过`rqt_graph`查看节点运行状态[^3]。 --- #### 关键概念对比 | 类型 | 作用域 | 生命周期 | 示例 | |--------|----------------|----------------|-----------------------| | param | ROS参数服务器 | 持续到节点结束 | `<param name="rate" value="10"/>` | | arg | launch文件内部 | 仅在启动时有效 | `<arg name="mode" default="debug"/>` [^4] | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江河地笑

实践是检验真理的唯一标准

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值