visnet is a ROS 2 package for multi-camera UAV simulation, observation, and tracking in an urban scene: four fixed cameras around a Gazebo Purdue-campus world watch a drone (and a bird) fly configurable trajectories, with per-camera images, camera info, and camera/target poses published over ROS 2.
Validated setup: Ubuntu 24.04 + ROS 2 Jazzy with the Gazebo it ships (Harmonic) via binary ros_gz.
All four camera views from one sim.launch.py run. The circles are not hand-drawn: each target's /drone1/pose / /bird1/pose is projected through the published /cameraN/pose extrinsics and the camera intrinsics — the marks landing on the rendered targets is the geometric consistency check.
- Gazebo simulation launch files for full (
sim.launch.py) and headless (sim_headless.launch.py) runs - The Purdue-campus world
worlds/purdue.sdfwith a fixed four-camera rig: cameras at (±10, ±10, 10) m, yaw-only orientations (−2.35 / −0.78 / +0.78 / +2.35 rad), horizontal optical axes, 640×480 @ 30 Hz, hfov 1.5 rad (fx = fy ≈ 343.5 px) - Simulated drone (X500) and bird (eagle) targets flying Lissajous figure-8 trajectories
- Camera pose publication matching the rendered rig (see below), particle-filter tracking utilities, RViz/debug marker tools
- World-generation tooling (
scripts/generate_ivv_world.py) for custom camera layouts
Ubuntu 24.04 with ROS 2 Jazzy sourced, plus:
sudo apt install ros-jazzy-desktop ros-jazzy-ros-gz ros-jazzy-rqt-image-view \
python3-numpy python3-opencv python3-yaml(Gazebo Harmonic comes with ros-jazzy-ros-gz — no separate Gazebo install or source build needed.)
mkdir -p ~/visnet_ws/src && cd ~/visnet_ws/src
git clone https://github.com/Siddharth2511/visnet.git visnet
cd ..
colcon build --packages-select visnet
source install/setup.bashros2 launch visnet sim.launch.py # Gazebo + RViz
ros2 launch visnet sim_headless.launch.py # no GUIYou should see the Purdue world with the drone flying a loop. Verify:
ros2 topic list
# /camera_0..3/image rendered 640x480 frames
# /camera_0..3/info CameraInfo (intrinsics)
# /camera0..3/pose camera extrinsics in the world frame (note: no underscore)
# /drone1/pose /bird1/pose target poses (ground truth)
ros2 run rqt_image_view rqt_image_view # pick /camera_0/image
ros2 topic echo /camera0/pose --once # one camera extrinsic/cameraN/pose publishes the true rendered camera poses — the worlds/purdue.sdf rig, including each camera's [0.1, 0.05, 0.05] link offset — as optical-frame poses (z = boresight, x = image right, y = image down). This is the default (use_world_rig:=true), so images, camera info, and published extrinsics are mutually consistent out of the box.
The legacy configurable look-at layout is still available for pose-publication experiments:
ros2 launch visnet sim.launch.py use_world_rig:=false \
layout_radius:=6.0 camera_height:=10.0 look_at_z:=1.4but note it changes only the published poses — the rendering cameras are fixed in worlds/purdue.sdf. To render a different camera layout, generate a world with scripts/generate_ivv_world.py.
Target trajectory arguments (drone): target_amp_x 1.8, target_amp_y 1.2, target_angular_rate 0.45 rad/s, target_altitude 1.4, target_vertical_amp 0.2 — a 1:2 Lissajous figure-8, period ≈ 14 s. The bird flies the same default trajectory offset +3 m in x.
launch/: simulation, bridge, and headless launch filesworlds/: SDF worlds, includingpurdue.sdf(the four-camera rig)models/: Purdue environment, X500 drone, eagle targetscripts/: tracking, simulation, and helper scriptscamera_info/: real-hardware calibrations (1600×1200) — these describe the physical PURT cameras, not the 640×480 sim camerasconfig/: RViz configurationdocs/: README figures;make_layout_figure.pyregenerates the layout figure (the four-view composite is captured from a live run)
scripts/sim_camera_pose_pub.py: publishes the 4-camera poses and TF frames (world rig by default)scripts/sim_target_pose_pub.py: drives the drone or bird target along a configurable trajectory and mirrors that pose into Gazeboscripts/pf_track.py: particle-filter tracker fusing per-camera bounding boxes (needs the externallienppackage — not included)scripts/vis_debug_markers.py: RViz markers for camera axes, rays, particle cloudsscripts/generate_ivv_world.py: generates SDF worlds for custom camera layouts
- Target trajectories are driven by wall-clock time, so two runs are not comparable frame-for-frame.
- The bird's default path is the drone's path shifted +3 m in x (constant separation).
- Image topics are
camera_0/...(underscore); pose topics and TF frames arecamera0/...(no underscore).
- This branch builds on prior
visnetwork by Zhanpeng Yang (zp-yang). - If you share this repository, keep the commit history and the upstream reference so the original development lineage remains visible.
- The repo includes the simulation assets needed to reproduce the scene and target models.
- A standalone repository
LICENSEfile has not been added yet. Until that is finalized, treat reuse and redistribution as needing explicit permission from the repository owner(s).

