Windows (native) WSL2 distro, rootless podman, --network host
mrrsim launcher ──── starts ───▶ Unreal (Simulation-Win64-Shipping.exe)
│ ▲ UDP 9002/9003 + 10i
└── wsl.exe -d mrr --exec podman ──▶ mrrsim-scene loads the scene, stays connected
mrrsim-sitl-0..N arducopter, one per vehicle
mrrsim-script Python 3.12 + DroneKit -> tcp:127.0.0.1:5762+10i
Windows and WSL share 127.0.0.1 through .wslconfig's networkingMode=mirrored option
| Folder | Contents |
|---|---|
| launcher/ | launcher UI and runtime |
| containers/ | sitl/ (pinned ArduPilot Copter ref) and script/ (Python 3.12 + DroneKit, pymavlink from MRR package index) |
| config/ | launcher settings |
| scripts/ | script examples |
| sim_config/ | Project AirSim scene + robot .jsonc |
Windows/ |
the packaged Unreal build |
mrrsim.cmd |
runs the launcher straight from this folder |
- WSL 2 must already be set up (Windows 11 22H2 or newer, WSL 2.0 or newer, virtualization on).
The installer (
MRRSimulationLauncher.iss) only checks this and stops with instructions if it is not; it never enables WSL itself. .\mrrsim.cmd doctorto see what is missing.- Copy the scene and robot
.jsoncfiles into sim_config/ and set[scene] scenein config/mrrsim.toml. See sim_config/README.md. .\mrrsim.cmd images build all(downloads base images and clones ArduPilot and Project AirSim)..\mrrsim.cmd uprunsscripts/takeoff_land.py. Useup --dry-runfirst to read the commands.
Run from the repository root:
tools\build_installer.cmdBuilds everything: the script images, the Linux payload, the launcher and the installer. Use it when anything under containers\ changed.
tools\build_installer.cmd quickRebuilds only the launcher and the installer, and reuses the existing Linux payload.
Either way, the result is Output\MRRSimulator-Setup-<version>.exe.
mrrsim images build scriptrebuilds the script images in yourmrrWSL distro (cached layers keep it quick). The payload is made from these images, so this step comes first.python tools/build_distro.pymakespayload/mrr-rootfs.tar.gz. The archive is a clean Ubuntu 24.04 WSL distro with rootless podman, amrruser, and the three simulator images already loaded.- On the first run it downloads the official Ubuntu image and checks it against a pinned checksum.
- It copies the images out of your
mrrwithpodman saveand tests the result. It only reads yourmrrand never changes it. - It writes a version stamp to
payload/distro_version.iss. The stamp changes whenever the images or the provisioning change.
launcher\build.cmdbuildsMRRSimulator.exeandMRRSimulatorGUI.exe.- Inno Setup compiles
MRRSimulationLauncher.issinto the setup program.
- WSL distro: at the end of an install, setup imports the payload as the WSL distro
mrrfor the account running setup.- An
mrrthat setup did not create is never replaced. - One that setup created is replaced when its version stamp differs from the installer's. Setup asks first; a silent install replaces it without asking.
- Your scripts and projects are not stored in the distro.
- An
MRRSimulator-Setup-<version>.exe /DISTRO=mrr-testThen set the distro to mrr-test in the installed config\mrrsim.toml too.
A camera in the simulator can send its pictures to the Python script that is running, as UDP packets to a port you choose. Switch it on in the Vehicles tab (the setting is saved with the design):
-
Select the camera, open Stream pictures to the script (UDP) and set Stream the pictures to true. Pick the Port (default 5600), how many Pictures per second at most, the Picture format (JPEG, or lossless PNG) and, to keep them small, Shrink wider than (a width in pixels). Which capture chooses the image type; that capture must have Send images to scripts on (the provided
DownCamerahas it on for the color image); the Problems list says so if it is not. -
Use the design when running (
mrrsim run script.py --design NAME). The launcher prints which port each camera sends to. -
In the script:
from mrrsim_camera import CameraReceiver with CameraReceiver(5600) as camera: # the port from the camera; CameraReceiver() uses the first camera's frame = camera.get(timeout=5) # the newest picture you have not seen yet (None if none came) image = frame.image() # NumPy array (BGR, like OpenCV); frame.data holds the JPEG/PNG bytes print(frame.vehicle, frame.camera, frame.width, frame.height)
camera.latest()returns the newest picture without waiting,for frame in camera.frames(timeout=5):loops over them as they come, andpython -m mrrsim_camera --port 5600shows what a camera sends without a script. scripts/camera_receiver.py is a complete example. Environment variablesSIM_CAMERA_PORT(first camera's port) andSIM_CAMERA_STREAMS(all of them, as JSON) are set for the script.
Good to know:
- Several cameras and all the vehicles of a run can send to one port: each picture says which vehicle (counted from
0, like
SIM_CONNECT_<n>) and which camera it came from. Use different ports to give each camera its own receiver. - Pictures are dropped rather than queued: a picture that lost a packet is discarded, and a script slower than
the camera skips to the newest picture (
camera.droppedcounts them). Lower the rate or the size if you need every picture. - The packets are small (1400 bytes) on purpose: WSL's mirrored networking silently loses larger UDP packets between programs on the computer. A 640x480 JPEG is about 6-40 packets; a large PNG is hundreds, so prefer JPEG.
- Only one program at a time can receive the simulator's pictures and sensor data, so the launcher's scene loader (which
holds that connection) does the receiving and relays the pictures; a script that subscribes to the camera itself
with the Project AirSim client would find nothing. The packet format is in
containers/script/mrrsim_camera.pyfor receivers written in another language. - Depth captures are sent as gray pictures (black = 0 m, white = Depth: white at meters or more).
| MAVLink SYSID | i + 1 |
| Physics UDP | 9003 + 10i (SITL receives sensors), 9002 + 10i (sim receives motor output) |
| SERIAL0 | udpclient to 127.0.0.1:14550 for a GCS (QGC / Mission Planner), all vehicles |
| SERIAL1 | tcp:127.0.0.1:5762 + 10i: DroneKit and scripts |
| SERIAL2 | tcp:127.0.0.1:5763 + 10i: launcher health monitor |