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

ROS中rosrun可生成CSV存储文件但roslaunch无法生成的问题排查及树莓派4适配方案咨询

Why Your CSV File Isn't Generating When Using roslaunch (And How to Fix It)

Let's break down exactly what's going on here, fix your current code, and share some Raspberry Pi-friendly data storage alternatives tailored for ROS launch scenarios.

Core Problem: Working Directory Differences

When you run nodes with rosrun, each node uses the current working directory of your terminal (like your ROS package folder or workspace root). That's why your storage_csv.csv shows up exactly where you expect it.

But roslaunch has a default behavior: it sets each node's working directory to a hidden ROS log folder (usually ~/.ros/log/<unique-launch-ID>/). Your listener node is writing the CSV file—it's just hiding in that log directory, not where you're looking. If the log folder has weird permissions, it might even fail to create the file entirely.

Secondary Code Pitfalls

Your listener code has a couple of issues that make this problem worse (and could cause silent data loss even when it works):

  • Frequent file open/close: You're opening and closing the CSV file every time a message arrives. This is inefficient, and if messages come faster than the file can open/close, you'll get unreported failures.
  • No error checking: You never verify if the file actually opened successfully. If there's a path or permission issue, your code just skips writing data without telling you.

Fixing Your Current Code

Let's fix the path issue first, then clean up the file handling.

Step 1: Use Absolute Paths (or ROS Parameters)

Ditch relative paths—instead, use an absolute path to your desired storage location, or make it flexible with ROS parameters. Here's the updated listener code:

//header
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
#include <fstream>
std::ofstream MyFile; // Keep global, but open once at startup

//callback function
void storage_callback(const std_msgs::String::ConstPtr& msg) {
    if (MyFile.is_open()) { // Always check if the file is usable first
        MyFile << msg->data << "\n";
        ROS_INFO("I recieve: [%s]", msg->data.c_str());
    } else {
        ROS_ERROR("Failed to write data—file is not open!");
    }
}

//main
int main(int argc, char **argv) {
    ros::init(argc, argv, "listener_node");
    ros::NodeHandle n;
    ROS_INFO("Storage code initialized");

    // Get file path from ROS params (fallback to a Pi-friendly absolute path)
    std::string file_path;
    n.param<std::string>("storage_file_path", file_path, "/home/pi/catkin_ws/src/storage/storage_csv.csv");

    // Open the file once at startup (append mode to avoid overwriting old data)
    MyFile.open(file_path, std::ios::out | std::ios::app);
    if (!MyFile.is_open()) {
        ROS_FATAL("Could not open file at %s! Check permissions or path.", file_path.c_str());
        return 1; // Exit immediately if we can't open the file
    }
    MyFile << "listener data.\n";

    ros::Subscriber sub = n.subscribe("/chatter", 1, storage_callback);
    ros::spin();

    // Close the file only when the node exits
    MyFile.close();
    return 0;
}

Step 2: Fix the Launch File Typo

You have a small typo (takler_node instead of talker_node—it might work, but let's clean it up and add the optional path parameter):

<launch>
  <node name="talker_node" pkg="storage" type="talker1_executable" output="screen"/>
  <node name="listener_node" pkg="storage" type="listener1_executable" output="screen">
    <!-- Optional: Override the file path here -->
    <param name="storage_file_path" value="/home/pi/my_data/storage_csv.csv" />
  </node>
</launch>

Raspberry Pi-Friendly Data Storage Alternatives for ROS Launch

Since the Pi has limited resources (CPU, SD card speed), here are better options than raw CSV writes:

1. Use rosbag (Simplest, Most ROS-Native)

rosbag is ROS's built-in tool for recording and replaying topic data. It's perfect for the Pi because it's lightweight, requires no custom code, and stores data in a compact, standardized format.

Add a bag recorder to your launch file:

<launch>
  <node name="talker_node" pkg="storage" type="talker1_executable" output="screen"/>
  <node name="listener_node" pkg="storage" type="listener1_executable" output="screen"/>
  <!-- Record the /chatter topic to a specific file -->
  <node name="bag_recorder" pkg="rosbag" type="record" args="/chatter -O /home/pi/rosbags/chatter_log.bag" output="screen"/>
</launch>
  • To replay the data later: rosbag play /home/pi/rosbags/chatter_log.bag
  • Pros: No code changes, supports multiple topics, easy to analyze later with tools like rqt_bag.

2. SQLite for Structured Storage

If you need to query or organize data (not just log it), SQLite is a great embedded database for the Pi—no separate server needed, just a local file.

Install the ROS SQLite package first:

sudo apt-get install ros-<your-ros-version>-sqlite3

Then modify your listener node to write to a SQLite database instead of CSV. This is more efficient than frequent CSV writes, especially on slow SD cards.

3. Batch-Write CSV (If You Must Stick to CSV)

If CSV is non-negotiable, optimize it by buffering data and writing in batches:

  • Collect 10-100 messages in a queue, then write all of them to the file at once.
  • Enable file buffering with MyFile.rdbuf()->pubsetbuf(0, 8192); to reduce SD card wear.

内容的提问来源于stack exchange,提问作者kartikeya singh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 22:22:36