AirSDK always uses default mission stack (ascent) ->

Context
I’m getting started with AirSDK and adapting the “Hello”/“Roadrunner” examples. As a first step I want the drone to climb to 13 m on takeoff. I tried to replace/override the ascent, but FSUP always executes the default takeoff.normal.ascent instead of my custom ascent.

Platform

  • Drone: ANAFI Ai
  • Controller: Olympe (desktop)
  • AirSDK mission: custom, based on default mission states

Stage Definition stage.py

from fsup.missions.default.takeoff.stage import Takeoff as DefaultTakeoff

from .normal import NORMAL_STATE
from .changed_ascent import CUSTOM_ASCENT_STATE
from ..uid import UID

_GROUND_MODE_NAME= "com.mycompany.missions.firstmission"

TAKEOFF_STAGE = {
    "name": "takeoff",
    "class": DefaultTakeoff,
    "initial": "normal",
    "children": [CUSTOM_ASCENT_STATE, NORMAL_STATE],
}

Normal State definition normal.py

from fsup.missions.default.takeoff.normal import (
    NORMAL_STATE as DEF_NORMAL_STATE,
)

_STATES_TO_REMOVE = ["ascent"]

NORMAL_STATE = {
    "name": "normal",
    "initial": "reset",
    "children": [
        child
        for child in DEF_NORMAL_STATE["children"]
        if not child["name"] in _STATES_TO_REMOVE
    ],
}

Own Ascent Configs changed_ascent.py

from fsup.genstate import guidance_modes
from fsup.missions.default.takeoff.normal import (
    Ascent as DefaultAscent,
)

from fsup.missions.default.uid import UID

import os
import cfgreader
import colibrylite.estimation_mode_pb2 as cbry_est

import guidance.ascent_pb2 as gdnc_ascent_msgs
from ..uid import UID

_STATES_TO_REMOVE = ["ascent"]

TARGET_ALTITUDE_M = 13.0



@guidance_modes(UID + ".ascent")
class Ascent(DefaultAscent):
    def enter(self, msg):
        self.gdnc_asc_svc = self.mc.attach_client_service_pair(
            self.mc.gdnc_channel, gdnc_ascent_msgs, forward_events=True
        )
        self.mc.dctl.cmd.sender.set_estimation_mode(cbry_est.TAKEOFF)
        self.log.info(f"[custom_ascent] target altitude = {TARGET_ALTITUDE_M} m")

        self.set_guidance_mode(
            "com.parrot.missions.default.ascent",
            gdnc_ascent_msgs.Config(
                type=gdnc_ascent_msgs.TYPE_DEFAULT,
                altitude=TARGET_ALTITUDE_M
            ),
        )


CUSTOM_ASCENT_STATE = {
    "name": "changed_ascent",
    "initial": "ascent",
    "children": [
        {
            "name": "ascent",
            "class": Ascent,
        },
    ],
}

mission.py

# only code is shown that is different to the init standard mission 
from .takeoff.stage import TAKEOFF_STAGE
def states(self):
        # Add your custom stages or override the default stages here
        return [
            DEF_GROUND_STAGE,
            TAKEOFF_STAGE,
            DEF_HOVERING_STAGE,
            FLYING_STAGE,
            DEF_LANDING_STAGE,
            DEF_CRITICAL_STAGE,
        ]

    def transitions(self):
        transitions = TRANSITIONS + DEF_TRANSITIONS
        return transitions
GdncAscent = lambda evt: msg_id(gdnc_ascent_msgs.Event, evt)  # noqa: E731

TRANSITIONS = [
    [
    Dctl("motors_ramping_done"),
    "takeoff.normal.wait_ascent",
    "takeoff.changed_ascent.ascent",
    ],
    [
    Dctl("motors_ramping_done"),
    "takeoff.normal.wait_motor_ramping",
    "takeoff.changed_ascent.ascent",
    ],

    [GdncAscent("done"), "takeoff.changed_ascent.ascent", "flying.manual"],

    ]

Mission builds and runs; logs show motors_ramping_done, but the next state is still takeoff.normal.ascent.

Hello @guessp ,

I reproduced your mission by modifying the RoadRunner mission and adapting the takeoff stage with your files. I could not reproduce the issue on my side.

Would it be possible for you to share your log.bin? It might show that CUSTOM_ASCENT_STATE is being skipped and the mission goes directly to NORMAL_STATE, or that there’s another issue elsewhere.

Best regards,
Hugo