Drobotics logo DROBOTICSTechnical Library

SLAM Guide

Drobotics Indoor Autonomous Drone Pipeline Test | SUPER + FAST-LIO + PX4 Offboard 实机验证

All SLAM
Drobotics Indoor Autonomous Drone Pipeline Test | SUPER + FAST-LIO + PX4

Drobotics Indoor Autonomous Drone Pipeline Test

SUPER + FAST-LIO + PX4 Offboard · 室内自主无人机流水线验证

SUPER Planner FAST-LIO PX4 Offboard 自主导航 通过 实机验证
Screenshot 2026 08 22 at 12.10.01 AM
1. Objective

This test demonstrates a Drobotics indoor autonomous drone pipeline using Livox MID-360S LiDAR, FAST-LIO SLAM, SUPER trajectory planning, MAVROS, and PX4 OFFBOARD control.

The goal was to verify:
通过 LiDAR point cloud generation
通过 FAST-LIO odometry
通过 PX4 external vision input
通过 SUPER trajectory generation
通过 MAVROS setpoint bridge
通过 Autonomous multi-step movement
通过 Obstacle-aware goal planning behavior
2. System Pipeline
Livox MID-360S ↓ livox_ros_driver2 ↓ /super/livox/lidar + /super/livox/imu ↓ FAST-LIO ↓ /Odometry + /cloud_registered ↓ SUPER Planner ↓ /planning/pos_cmd ↓ Drobotics SUPER-to-MAVROS Bridge ↓ /mavros/setpoint_position/local ↓ MAVROS ↓ PX4 OFFBOARD Position Control ↓ Drone Motion
通过 3. Test Result Summary
The test successfully confirmed that the Drobotics SUPER pipeline generated real autonomous motion.
Measured from rosbag:
Forward 0.8 m command: actual movement ≈ 0.765 m
Slide / side movement: actual movement ≈ 0.863 m
The planner generated valid trajectories, and PX4 received position setpoints.
Important evidence:
/Odometry: ~10 Hz
/cloud_registered: ~10 Hz
/mavros/odometry/out: ~10 Hz
/mavros/local_position/odom: ~30 Hz
/mavros/setpoint_position/local: active
/goal_pose: published
SUPER planner: FOLLOW_TRAJ and Traj finish
Altitude setpoint from the Drobotics bridge stayed stable:
/mavros/setpoint_position/local dZ ≈ 0.000 m
So the bridge was not commanding unwanted vertical movement.
Image Placeholders:
[Insert Image 1: Flight path plot]
[Insert Image 2: Open3D / cloud_registered point cloud screenshot]
[Insert Image 3: Drone setup photo]
4. Behavior Explanation

The current system is goal-based autonomous navigation. It works like this:

auto-nav publishes /goal_pose ↓ SUPER checks map and point cloud ↓ if a safe path exists, SUPER generates trajectory ↓ Drobotics bridge converts trajectory to MAVROS setpoints ↓ PX4 follows the setpoints in OFFBOARD mode
If SUPER cannot find a safe path, it refuses to generate a trajectory. In that case the drone should hold instead of pushing through an obstacle.
Current capability:
通过 Known/static obstacle in cloud map → avoid or refuse path
通过 Blocked goal → planner fails safely
错误 Sudden moving obstacle/person → not fully reactive yet
The next improvement is a reactive avoidance layer using /cloud_registered clearance to choose left, right, or backward before SUPER fails.
5. Flight Commands
Terminal 1 — Start Known-Good SLAM Stack + Bag
tmux kill-session -t drobotics_super_auto 2>/dev/null || true tmux kill-session -t slam 2>/dev/null || true ~/start_slam_takeoff_test_mid360s.sh
Wait about 60 seconds.
Terminal 2 — Start SUPER Planner
source /opt/ros/humble/setup.bash source ~/slam_ws/install/setup.bash source ~/super_ws/install/setup.bash: > /tmp/drobotics_super_planner_auto_nav.log ros2 run super_planner fsm_node \ --ros-args \ -p config_name:=click_slow_f450.yaml \ > /tmp/drobotics_super_planner_auto_nav.log 2>&1
Terminal 3 — Start Drobotics SUPER-to-MAVROS Bridge
source /opt/ros/humble/setup.bash source ~/slam_ws/install/setup.bash source ~/super_ws/install/setup.bash ros2 run drobotics_super_bridge super_to_mavros_position \ --ros-args \ -p setpoint_rate_hz:=20.0 \ -p odom_timeout_s:=0.50 \ -p super_command_timeout_s:=0.50 \ -p max_odom_jump_m:=0.75 \ -p max_command_jump_m:=0.50 \ -p max_mission_xy_m:=2.00 \ -p max_mission_z_m:=0.75 \ -p max_setpoint_speed_mps:=0.10 \ -p max_yaw_rate_rps:=0.50 \ -p follow_super_z:=false \ -p follow_super_yaw:=false
Expected: Prestreaming current PX4 XYZ and yaw at 20.0 Hz
6. Health Check Before Flight
source /opt/ros/humble/setup.bash source ~/slam_ws/install/setup.bash source ~/super_ws/install/setup.bash echo "=== FAST-LIO ===" timeout 5 ros2 topic hz /Odometry echo "=== CLOUD ===" timeout 5 ros2 topic hz /cloud_registered echo "=== PX4 EV INPUT ===" timeout 5 ros2 topic hz /mavros/odometry/out echo "=== PX4 LOCAL ===" timeout 5 ros2 topic hz /mavros/local_position/odom echo "=== SETPOINTS ===" timeout 5 ros2 topic hz /mavros/setpoint_position/local echo "=== PLANNER ===" ros2 node list | grep fsm_node || echo "NO FSM NODE" echo "=== VEHICLE STATE ===" ros2 topic echo /mavros/state --once
Expected:
/Odometry ≈ 10 Hz
/cloud_registered ≈ 10 Hz
/mavros/odometry/out ≈ 10 Hz
/mavros/local_position/odom ≈ 30 Hz
/mavros/setpoint_position/local ≈ 20 Hz
/fsm_node exists
connected: true · armed: false
7. Flight Action
警告 Use RC ready.
1. Arm in POSCTL.
2. Take off manually.
3. Hover stable around 0.6–0.8 m.
4. Confirm no toilet-bowling/circling.
5. Switch to OFFBOARD.
6. Wait 1–2 seconds.
7. Confirm it holds position.
8. Run auto-nav in Terminal 4.
Terminal 4 — Run 0.8 m Auto-Nav Test With Log
source /opt/ros/humble/setup.bash source ~/slam_ws/install/setup.bash source ~/super_ws/install/setup.bash: > /tmp/super_auto_nav_slide.log ros2 run drobotics_super_bridge super_auto_nav_slide \ --ros-args \ -p forward_step_m:=0.80 \ -p side_step_m:=0.45 \ -p backward_step_m:=0.25 \ -p prefer_left:=true \ -p max_steps:=3 \ -p movement_wait_s:=16.0 \ -p min_progress_m:=0.35 \ -p step_settle_s:=3.0 \ -p goal_z_mode:=current \ -p require_armed_offboard:=true \ 2>&1 | tee /tmp/super_auto_nav_slide.log
Expected behavior:
Try forward 0.8 m
If valid path exists, drone moves forward
Then try side/diagonal movement
Stop after max_steps
Emergency rule:
Switch POSCTL immediately.
Land.
Disarm.
8. Post-Flight Commands
Check Latest Bag
source /opt/ros/humble/setup.bash source ~/slam_ws/install/setup.bash source ~/super_ws/install/setup.bash LATEST_BAG=$(cat ~/rosbags/.latest_indoor_hover) echo "$LATEST_BAG" du -sh "$LATEST_BAG" ros2 bag info "$LATEST_BAG" echo echo "=== AUTO NAV LOG ===" tail -120 /tmp/super_auto_nav_slide.log echo echo "=== PLANNER EVENTS ===" tail -200 /tmp/drobotics_super_planner_auto_nav.log \ | grep -E 'Get goal|SUCCESS|FAILED|min dis|GeneratePolytope|PlanFromRest|FOLLOW_TRAJ|Traj finish|OPT_FAILED'
Create Tiny Bag for Analysis
source /opt/ros/humble/setup.bash source ~/slam_ws/install/setup.bash source ~/super_ws/install/setup.bash FULL_BAG=$(cat ~/rosbags/.latest_indoor_hover) TINY_BAG=~/rosbags/tiny_$(basename "$FULL_BAG") rm -rf "$TINY_BAG" cat > /tmp/tiny_bag_filter.yaml <
9. Export /cloud_registered Preview Point Cloud
source /opt/ros/humble/setup.bash source ~/slam_ws/install/setup.bash source ~/super_ws/install/setup.bash FULL_BAG=$(cat ~/rosbags/.latest_indoor_hover) OUT_PLY=~/rosbags/drobotics_cloud_registered_preview.ply echo "Bag: $FULL_BAG" echo "Output: $OUT_PLY" python3 - <<'PY' from pathlib import Path import sqlite3 import struct import math import random from rclpy.serialization import deserialize_message from rosidl_runtime_py.utilities import get_message bag_path = Path.home().joinpath("rosbags/.latest_indoor_hover").read_text().strip() db_files = sorted(Path(bag_path).glob("*.db3")) if not db_files: raise SystemExit(f"ERROR: no db3 file found in {bag_path}") db_path = db_files[0] out_path = Path.home().joinpath("rosbags/drobotics_cloud_registered_preview.ply") conn = sqlite3.connect(str(db_path)) cur = conn.cursor() topic_row = cur.execute( "SELECT id, type FROM topics WHERE name = '/cloud_registered'" ).fetchone() if topic_row is None: raise SystemExit("ERROR: /cloud_registered not found in bag") topic_id, topic_type = topic_row MsgType = get_message(topic_type) rows = cur.execute( "SELECT data FROM messages WHERE topic_id = ? ORDER BY timestamp", (topic_id,), ) points = [] max_frames = 160 frame_stride = 4 point_stride = 25 max_points = 250000 def read_points_xyz(msg): fields = {f.name: f for f in msg.fields} if not all(k in fields for k in ("x", "y", "z")): return xoff = fields["x"].offset yoff = fields["y"].offset zoff = fields["z"].offset step = msg.point_step data = msg.data endian = ">" if msg.is_bigendian else "<" for i in range(0, msg.width * msg.height, point_stride): base = i * step try: x = struct.unpack_from(endian + "f", data, base + xoff)[0] y = struct.unpack_from(endian + "f", data, base + yoff)[0] z = struct.unpack_from(endian + "f", data, base + zoff)[0] except struct.error: continue if math.isfinite(x) and math.isfinite(y) and math.isfinite(z): points.append((x, y, z)) frame_count = 0 used_frames = 0 for index, (blob,) in enumerate(rows): frame_count += 1 if index % frame_stride != 0: continue msg = deserialize_message(blob, MsgType) read_points_xyz(msg) used_frames += 1 if used_frames >= max_frames or len(points) >= max_points: break if len(points) > max_points: random.seed(7) points = random.sample(points, max_points) with out_path.open("w") as f: f.write("ply\n") f.write("format ascii 1.0\n") f.write("comment Drobotics / 卓博泰智能科技 / www.drobotics.tech\n") f.write(f"element vertex {len(points)}\n") f.write("property float x\n") f.write("property float y\n") f.write("property float z\n") f.write("end_header\n") for x, y, z in points: f.write(f"{x:.4f} {y:.4f} {z:.4f}\n") print(f"DB: {db_path}") print(f"Frames in bag scanned: {frame_count}") print(f"Frames used: {used_frames}") print(f"Points written: {len(points)}") print(f"Output: {out_path}") PY ls -lh "$OUT_PLY"
Copy to Mac
scp drobotics@172.20.10.3:~/rosbags/drobotics_cloud_registered_preview.ply ~/Desktop/
10. View PLY on Mac With Python
python3 -m pip install open3d python3 - <<'PY' import open3d as o3d from pathlib import Path ply = Path.home() / "Desktop/drobotics_cloud_registered_preview.ply" pcd = o3d.io.read_point_cloud(str(ply)) print("File:", ply) print("Points:", len(pcd.points)) print("Bounds min:", pcd.get_min_bound()) print("Bounds max:", pcd.get_max_bound()) print("Center:", pcd.get_center()) pcd = pcd.voxel_down_sample(voxel_size=0.05) points = pcd.points colors = [] zs = [p[2] for p in points] zmin, zmax = min(zs), max(zs) span = max(zmax - zmin, 1e-6) for p in points: t = (p[2] - zmin) / span colors.append([t, 0.4, 1.0 - t]) pcd.colors = o3d.utility.Vector3dVector(colors) axis = o3d.geometry.TriangleMesh.create_coordinate_frame(size=0.5) o3d.visualization.draw_geometries( [pcd, axis], window_name="Drobotics / 卓博泰智能科技 — cloud_registered preview", width=1280, height=800, ) PY
Screenshot 2026 08 22 at 12.36.16 AM

平台:Jetson · ROS2 Humble · Livox MID-360S · FAST-LIO · SUPER · PX4
(c) 卓博泰科技 · Indoor Autonomous Drone Pipeline Test