A short summary after five iterations of debugging the takeoff node (full history: Takeoff node evolution). These four rules are short, but each was paid for in disarm-on-arm loops that took a day or two to diagnose. Save yourself the time.
Rule 1 — Setpoints are only for a flying drone
# ❌ setpoint from tick 0
def loop(self):
self.sp_pub.publish(self.target)
# ✅ setpoint only after takeoff is confirmed
def loop(self):
if self.phase == 'hover':
self.sp_pub.publish(self.target)
/mavros/setpoint_position/local is a position-hold command for an already flying drone. On the ground, ArduPilot treats it as a conflict with NAV_TAKEOFF. Spamming setpoints before takeoff is one of the most reliable ways to disarm yourself.
Rule 2 — Strict command ordering
❌ arm → setpoint (conflict → DISARM)
✅ guided → arm → takeoff → setpoint (phases separated)
In each phase, send only the tool that phase requires. Never two at once.
Rule 3 — One timer, explicit phases
# ❌ nested create_timer (loops forever)
self.create_timer(2.0, self.do_takeoff) # inside a callback
# → do_takeoff is called every 2 seconds, forever
# ✅ one timer + a phase string
self.phase = 'wait'
self.create_timer(0.1, self.loop)
def loop(self):
if self.phase == 'wait': ...
elif self.phase == 'guided': ...
create_timer in ROS 2 is persistent, not one-shot. Use a phase field to separate steps, never nested timers.
Rule 4 — Check state, not just tick
# ❌ time-based transition
if self.tick > 70:
self.do_takeoff()
# ✅ state-confirmed transition
if self.tick > 70 and self.state.armed and self.state.mode == 'GUIDED':
self.do_takeoff()
Tick-based FSMs break when MAVROS / EKF settling is slow (15-25 s indoor). By the time tick > 70, the node may not even have state.connected yet. The full event-driven rewrite is in Takeoff node v7 event-driven.
Why these rules aren’t in the documentation
Every one of these came from a real ArduPilot SITL failure. The system explains its behavior through logs, not through docs. That’s the actual engineering pattern in robotics: write code → run it → read logs → revise the hypothesis. Documentation tells you what should work; logs tell you what does.