Introduction to Unity Robotics and Simulation Pro · Module 5 of 5
Getting data out of the simulation and onto disk: sensor images, LiDAR point clouds, and logged values as CSV.
By the end of this module you will have saved a PNG from a simulated camera, exported a point cloud and viewed it outside Unity, and written a CSV log of the robot's position over time.
Sensors publish messages; they do not write files. Saving output to disk is a separate component you add alongside the sensor - the Image Message Saver. It subscribes to a topic and writes what arrives.
- Select the
front_laser_linkobject on the robot. - Open the Sensors panel and add a Camera sensor.
- Add an Image Message Saver component. It can go on any GameObject in the Scene; putting it on the camera sensor keeps things together.
The topic must match. Scroll down on the Camera Sensor component to find the topic it publishes
to - Unity Camera by default - and enter that on the saver. The topic must be of type
ImageMsg, or there is nothing for the saver to write.
Settings:
| Setting | What it controls |
|---|---|
| Number of captures | How many images to take |
| Start time | When capturing begins |
| Interval | Time between captures |
| Save directory | Where the files are written |
| File name | Base name for the output files |
- On
ConnectionManager, disable the ROS Endpoint Connector and enable the Dummy Connection. - Add the Default Visualization Suite to the Scene so you can see what the camera is producing.
- Save and press Play.
When the Camera Sensor's Status reads Ready, the capture has happened. Select Open next to Save Directory to open the folder in your file browser.
The file appears as capture.png in your Assets folder. It will be small — the saver writes the
camera's configured resolution, so to change the image size, change image width and height on
the camera sensor itself, not on the saver.
- The Camera Sensor's Status reads Ready in Play mode.
- A
.pngexists in the save directory and shows the Scene from the camera's viewpoint.
Same pattern, different saver and a different message type. You need two things: a sensor that produces a point cloud, and the Point Cloud Message Saver.
- Select
front_laser_linkand add a Physics LiDAR sensor. - Set its output type to Point Cloud. A laser scan is planar and will not produce a point cloud file.
- Add a Point Cloud Message Saver component.
- Copy the LiDAR's topic into the saver. The topic must be of type
PointCloud2Msg.
The settings are the same as the image saver, with one addition:
| Setting | Options |
|---|---|
| File type | LAS or PCD |
Choose based on what will read the file.
Save and press Play. The Console confirms that the physics LiDAR's point cloud has been written. Open the save folder to find the file.
Rendering the cloud shows you what your robot is actually capturing, which tells you whether the sensor needs repositioning, whether its range or sample count is wrong, or whether a different sensor type would serve better.
- The Console logs the point cloud save.
- A
.lasor.pcdfile exists in the save directory. - Rendered externally, the cloud resembles the Scene geometry.
This does not require SimPro. It is ordinary Unity C# writing a file, and it works for any object in the Editor.
This section covers CSV only. JSON logging is not covered in this course.
For this you want direct control rather than the waypoint navigator:
- Enable the Differential Drive Keyboard Adapter on the AMR prefab.
- Leave the waypoint navigator unused.
Create a new MonoBehaviour named DataLogger in the Message Scripts folder. Inside the same
file, add a plain CSVLogger class. It does not inherit from MonoBehaviour, since it is just a file
writer.
using UnityEngine;
using System.IO;
using System.Linq;
public class DataLogger : MonoBehaviour
{
CsvLogger csvLogger;
void Start()
{
csvLogger = new CsvLogger("example.csv", "positionX", "positionY", "time");
}
// Update is called once per frame
void Update()
{
csvLogger.AddRow(transform.position.x, transform.position.y, Time.time);
}
private void OnApplicationQuit() {
csvLogger.Close();
}
}
public class CsvLogger
{
StreamWriter file;
public CsvLogger(string filename)
{
file = new StreamWriter(filename);
}
public CsvLogger(string filename, params string[] columnNames): this(filename)
{
file.WriteLine(string.Join(",", columnNames));
}
public void AddRow(params float[] values)
{
file.WriteLine(string.Join(",", values.Select(f=>f.ToString())));
}
public void Close()
{
file.Close();
}
}What each piece is for:
| Member | Purpose |
|---|---|
| First constructor | Opens the StreamWriter for the given file name |
| Second constructor | Calls the first, then writes the header row from the column names |
AddRow |
Converts a float array to strings and writes one comma-joined line |
Close |
Closes the file so it is flushed and readable |
Then in DataLogger:
- Hold a
CSVLoggerfield. - In
Start(), initialise it with the file nameexample.csvand the columnspositionX,positionY, andtime. - Add a row containing
transform.position.x,transform.position.y, andTime.time. - Add
OnApplicationQuit()and callClose()there, so logging stops cleanly and the file saves when the application exits.
Press Play and drive the robot around the Scene to generate positional data, then stop.
example.csv is written to the root project folder, not the Assets folder. Open it in any editor
or spreadsheet tool and you will find positionX, positionY, and time columns with a row per
logged sample.
example.csvexists in the project root after exiting Play mode.- It has a header row and one row per sample, with values that change as the robot moved.
That completes Introduction to Unity Robotics and Simulation Pro. Across the five modules you have:
| Module | What you built |
|---|---|
| 1 — Introduction | A Unity 6 project with SimPro and its samples, and a Panda arm imported from URDF and configured for stable physics |
| 2 — Messages | A publisher and subscriber exchanging messages over a Dummy Connection, and TF broadcasting for every joint on the arm |
| 3 — Sensors | Hands-on with every sensor SimPro ships: camera, fisheye, stereo depth, time of flight, three LiDAR implementations, and IMU |
| 4 — Creating a Simulation | A complete simulation with a live ROS 2 connection, an rclpy node navigating the robot by LiDAR and odometry |
| 5 — Capturing Data | Images, point clouds, and CSV logs exported from the running simulation |
- Robotics and physics fundamentals - driving ArticulationBodies directly, covered in a later course in this pathway.
- Setting up ROS 2 — this course assumed a working ROS 2 environment. A later course covers building one.
- Deploy to hardware. The point of the exercise: the
rclpynode from Module 4 is the same code that runs on a physical robot. Having tested it in a Unity living room, the next step is a real one.




