Drobotics Indoor Autonomous Drone Pipeline Test
SUPER + FAST-LIO + PX4 Offboard · 室内自主无人机流水线验证
SUPER Planner
FAST-LIO
PX4 Offboard
自主导航
通过 实机验证

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
通过 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
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
/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:
So the bridge was not commanding unwanted vertical movement.
/mavros/setpoint_position/local dZ ≈ 0.000 mSo 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]
[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
通过 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
/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.
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
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.
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

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