Hello @LouisGenetec,
This is a simple example to draw a square with relative displacements.
First, a new guidance mode needs to be added in Flying mode:
autopilot-plugins
└── fsup
├──flying << NEW_FOLDER
| ├── __init__.py
| └── stage.py
├── __init__.py
└── mission.py
That is the code of the file stage.py:
from fsup.utils import is_msg
from fsup.genstate import State, guidance_modes
from fsup.missions.default.flying.stage import FLYING_STAGE as DEF_FLYING_STAGE
import guidance.relative_move_pb2 as rm_pb
_MOVE_ALTITUDE = 0
_MOVE_FORWARD = 1
_ROTATION = 2
@guidance_modes("mission_relative_move")
class MovePolygon(State):
def enter(self, msg):
self.distance = 10
self.altitude = -1
self.counter = 4
self.yaw_drone = (360.0 / float(self.counter)) * np.pi / 180.0
self.is_last_move = False
self.last_action = _MOVE_ALTITUDE
dis = rm_pb.Displacement(
dx=0, dy=0, dz=self.altitude, dyaw=0
)
cfg = rm_pb.Config(
displacement=dis, last_move=self.is_last_move
)
self.set_guidance_mode("relative_move", cfg)
def step(self, msg):
# Repeat the guidance mode "mission_relative_move" until the drone
# arrives at its starting position
if is_msg(msg, rm_pb.Event, "move_validated"):
if self.counter > 0:
if self.last_action == _MOVE_FORWARD:
dis = rm_pb.Displacement(
dx=0, dy=0, dz=0, dyaw=self.yaw_drone
)
if self.counter == 1:
self.is_last_move = True
self.counter -= 1
self.last_action = _ROTATION
else:
dis = rm_pb.Displacement(
dx=self.distance, dy=0, dz=0, dyaw=0
)
self.last_action = _MOVE_FORWARD
cfg = rm_pb.Config(
displacement=dis, last_move=self.is_last_move
)
self.set_guidance_mode("relative_move", cfg)
MOVE_POLYGON_STATE = {
"name": "move_polygon",
"class": MovePolygon,
}
FLYING_STAGE = {
"name": "flying",
"class": DEF_FLYING_STAGE["class"],
"initial": "manual",
"children": [child for child in DEF_FLYING_STAGE["children"]]
+ [MOVE_POLYGON_STATE],
}
And this is the code of the file mission.py:
from fsup.genmission import AbstractMission
from fsup.utils import msg_id
###################################################
# Stages and transitions
from fsup.missions.default.ground.stage import (
GROUND_STAGE as DEF_GROUND_STAGE,
)
from fsup.missions.default.takeoff.stage import (
TAKEOFF_STAGE as DEF_TAKEOFF_STAGE,
)
from fsup.missions.default.hovering.stage import (
HOVERING_STAGE as DEF_HOVERING_STAGE,
)
from fsup.missions.default.landing.stage import (
LANDING_STAGE as DEF_LANDING_STAGE,
)
from fsup.missions.default.critical.stage import (
CRITICAL_STAGE as DEF_CRITICAL_STAGE,
)
from fsup.missions.default.mission import TRANSITIONS as DEF_TRANSITIONS
###################################################
# Messages
# to receive message from guidance relative_move mode
import guidance.relative_move_pb2 as rm_pb
# to receive message from guidance ascent mode
import guidance.ascent_pb2 as gdnc_ascent_msgs
###################################################
# UID
UID = "com.examplecompanyname.missions.move-polygon"
###################################################
# Overwritten Stages
from .flying.stage import FLYING_STAGE
###################################################
# Mission
class Mission(AbstractMission):
def __init__(self, env):
super().__init__(env)
# Init guidance modes message services
self.gdnc_relative_move_msgs = None
def on_load(self):
# Set guidance channel and message services registration
# To get message from relative_move guidance mode
self.gdnc_relative_move_msgs = self.mc.attach_client_service_pair(
self.mc.gdnc_channel, rm_pb, True
)
def on_unload(self):
# Guidance channel is cleaned by message center
self.mc.detach_client_service_pair(self.gdnc_relative_move_msgs)
self.gdnc_relative_move_msgs = None
def on_activate(self):
pass
def on_deactivate(self):
pass
def states(self):
return [
DEF_GROUND_STAGE,
DEF_TAKEOFF_STAGE,
DEF_HOVERING_STAGE,
FLYING_STAGE,
DEF_LANDING_STAGE,
DEF_CRITICAL_STAGE,
]
def transitions(self):
return TRANSITIONS + DEF_TRANSITIONS
GdncAscent = lambda evt: msg_id(gdnc_ascent_msgs.Event, evt)
MissionRelativeMove = lambda evt: msg_id(rm_pb.Event, evt)
TRANSITIONS = [
[GdncAscent("done"), "takeoff", "flying.move_polygon"],
[MissionRelativeMove("done"), "flying.move_polygon", "flying"],
]
When the mission is loaded into the drone, just send a takeoff command. Once the drone is flying, the mission start automatically and the drone “draw a square”.