ASTRO, short for Autonomous Satellite Test & Robotics Operations, is a ROS 2-based framework for connecting satellite simulation software and guidance, navigation, and control software in a modular way.
The current main branch contains an initial working ROS 2 package, distributed_satellite_sim, which ports a DLQR-based reference scenario from the STAR Lab standalone C++ executables into native ROS 2 nodes. The broader project direction, including native ROS 2 and bridge-based architectures, is documented in the no-merge/manuscripts branch.
The project is intended to replace ad hoc simulation-to-flight-software networking with a ROS 2 graph that is easier to extend, test, and integrate with other lab systems.
On main, the implemented path is:
- an environment node that advances the simulation state
- a GNC node that computes control using a fixed DLQR gain matrix
- a ROS 2 topic carrying state from environment to controller
- a ROS 2 service carrying actuator commands from controller back to the environment
At a project level, the design goal is broader than the current package. The manuscript branch describes two intended deployment modes:
- a fully internal ROS 2 configuration, where simulation and control both live inside the ROS 2 graph
- an external-simulator configuration, where a bridge adapts a non-ROS simulator to the same ROS 2 interfaces
The active package lives under src/DistributedSatelliteSim.
Implemented components:
env_nodegnc_nodeActuationCmd.srvsim.launch.py- environment-node unit tests
- GNC-node unit tests
- launch-based DLQR reference trajectory regression test
At the package level, the interfaces are:
- topic:
env_data - service:
actuation_cmd - launch arguments:
max_steps,min_subscribers
The current implementation is a ROS 2 port of the DLQR reference code in:
The package currently uses a hardcoded six-state model, a three-axis control input, and a default initial state of:
[20, 20, 20, 0.00930458, -0.0467472, 0.00798343]
Additional implementation details that are useful when modifying the package:
env_nodeadvances the model on a 100 ms wall timersim.launch.pydefaultsmax_stepsto91- setting
max_steps:=0runs the simulation without the launch-time stop condition env_nodecurrently owns the hardcodedAdandBdmatrices directly in codegnc_nodecurrently owns the hardcoded DLQR gain matrix directly in code- the environment publishes
std_msgs/msg/Float64MultiArraywith six state elements - the actuation service uses a fixed-length
float64[3]thrust vector
flowchart LR
ENV["env_node"] -- "env_data topic" --> GNC["gnc_node"]
GNC -- "actuation_cmd service" --> ENV
env_nodepublishes the simulated state onenv_datagnc_nodesubscribes toenv_data, computesu = -Kx, and sends thrust throughactuation_cmdsim.launch.pystarts both nodes together
In the current code, env_node is both the simulator and actuator sink. That is useful to keep in mind because the project-level architecture described in the manuscripts splits this more conceptually into environment dynamics, actuator modeling, and future adapter layers.
.
├── .devcontainer/
├── reference/
│ ├── DLQR/
│ └── QP_MPC/
└── src/
└── DistributedSatelliteSim/
Key directories:
src/DistributedSatelliteSim: active ROS 2 packagereference/DLQR: DLQR reference executables used for the current portreference/QP_MPC: QP_MPC reference code for future integration
Within src/DistributedSatelliteSim:
include/distributed_satellite_sim/env_node.hpp: current environment-node implementationsrc/gnc_node.cpp: DLQR controller nodesrv/ActuationCmd.srv: service definitionlaunch/sim.launch.py: combined launch entrypointtest/test_env_node.cpp: environment-node unit teststest/test_gnc_node.cpp: GNC-node unit teststest/test_dlqr_reference_launch.py: launch-based DLQR reference trajectory regression testtest/data/dlqr_reference_trajectory.csv: 91-step reference fixture from standalone DLQR executables
The repository is set up for ROS 2 Kilted and includes OS-specific devcontainer definitions under .devcontainer.
The Linux devcontainer is configured around the ghcr.io/accommodus/astro:latest image and sets ROS_AUTOMATIC_DISCOVERY_RANGE=LOCALHOST and ROS_DOMAIN_ID=42. Those defaults matter if you are debugging node discovery behavior or trying to compare container and non-container runs.
If you are not using the devcontainer, you will need:
- ROS 2 Kilted
colconrosdep- Eigen3
- a C++17-capable compiler
From the repository root:
source /opt/ros/kilted/setup.bash
rosdep update
rosdep install --from-paths src --ignore-src -y
colcon build --packages-select distributed_satellite_sim
source install/setup.bashLaunch the full DLQR demo:
ros2 launch distributed_satellite_sim sim.launch.pySet an explicit step limit:
ros2 launch distributed_satellite_sim sim.launch.py max_steps:=91Run nodes individually:
ros2 run distributed_satellite_sim env_node
ros2 run distributed_satellite_sim gnc_nodeUseful inspection commands:
ros2 topic echo /env_data
ros2 service call /actuation_cmd distributed_satellite_sim/srv/ActuationCmd "{thrust: [0.0, 0.0, 0.0]}"When running nodes individually, start env_node first so the actuation_cmd service exists before gnc_node begins trying to send requests.
Run the package tests with:
source /opt/ros/kilted/setup.bash
colcon test --packages-select distributed_satellite_sim
colcon test-result --verboseThe current tests cover:
- Env-node unit tests: zero-thrust propagation, non-zero-thrust propagation, default initial state behavior, service success responses, topic message sizing
- GNC-node unit tests: zero-state output, known-state output, large-state output, negative-component output
- DLQR reference trajectory regression: launches both nodes through
sim.launch.py, records 91 steps ofenv_data, and compares each value against the committed reference fixture (test/data/dlqr_reference_trajectory.csv) within a tolerance of1e-4
Completed milestones:
- ROS 2 DLQR implementation validated against the original reference executables
- end-to-end launch-based regression test committed and passing
Near-term work is centered on:
- parameterizing the environment model for alternate controller configurations
- integrating the QP_MPC controller path
The reference/QP_MPC code is already in the repository, but it is not wired into the ROS 2 package yet and uses different dynamics and timing than the current DLQR environment.
That difference is significant: the QP_MPC path is not just a second controller implementation. It will require environment reconfiguration as well, because the reference code uses different matrices, timing, and scenario assumptions than the current DLQR node pair.
- the environment dynamics are hardcoded rather than configured through parameters or YAML
- the launch flow currently targets the DLQR scenario only
- the external simulator bridge described in the project manuscripts is not implemented on
main
The no-merge/manuscripts branch contains the proposal, presentation, and progress reports for the broader ASTRO project:
Those materials are useful if you want the higher-level rationale for the project, especially:
- why the lab wants ROS 2 instead of ad hoc UDP coupling
- the distinction between internal ROS 2 and bridge-based simulator architectures
- the intended longer-term expansion toward alternate controllers and operator-facing tooling