Sending commands from flight supervisor to guidance mode

Hi,

I have a custom guidance mode and I would like to send commands from Flight Supervisor to the guidance mode. I have already defined the command in the .proto file, and I know how to send events from guidance to fsup, but not otherwise.

I have done something similar in my cpp service (sending a command from flight supervisor) but I’m not sure how to do it in python and guidance mode, since there are no examples of this specific case in sample missions and I could not find the solution in other topics nor in documentation.

Could you please explain how to do it in this case?

Thank you very much,

Diego

Hi,
sending commands from flight supervisor to a guidance mode works the same as sending to services, you only have to attach it to the correct channel.
You can use attach_client_service_pair as in the road_runner example.
Then, you use the returned ServicePair object to send commands or events.
The example does this to send a command to a service here.

So for example:

import test_mission.guidance.test_msgs_pb2 as test_msgs
...
self.test_svc_pair = self.mc.attach_client_service_pair(self.mc.gdnc_channel, test_msgs)
self.test_svc_pair.cmd.sender.send_test()

In your guidance mode you have to implement the CommandHandler corresponding to the messages you want to handle.
This is for example implemented here in the hello example in the cv-service.

Hi,

Thanks for your response. Actually my problem was not in the code to put in the flight supervisor (I have the same than your example), but the part in guidance, since there are no examples. I have implemented a CommandHandler in a service too, following the ‘hello’ example, but I’m not sure how to do the ‘python version’ in the guidance.

I tried creating the command handler like this:

import guidance.core as gdnc_core
import test_mission.guidance.test_msgs_pb2 as test_msgs

self.msg_handler = gdnc_core.MessageHandler(test_msgs.Command.DESCRIPTOR.full_name)

because I saw in other example (road_runner or hello) that a MessageSender is created like this:

self.evt_sender = gdnc_core.MessageSender(test_msgs.Event.DESCRIPTOR.full_name)

I also noticed that attribute ‘guidance’ in guidance.core.Mode has methods like get_message_hub(), get_channel() and get_sender(), but nothing like “get_handler” or similar (as far as I know).

Then I did this:

self.msghub = self.guidance.get_message_hub()
self.msghub.attach_message_handler(self.msg_handler)

But I do not really know how to use that msg_handler or if this is the right way to implement the CommandHandler in python. Is this the right direction? Could you provide a simple example of the part of code in guidance?

Thank you

I have not used a python guidance myself.
However, in C++ guidance modes you create a class that inherits from the CommandHandler for your messages.
The road_runner example uses this here (it’s the same for guidance and services).
It implements the callback enableCv and attaches the message handler here.

Thanks. I have tried to replicate the code in road_runner and I feel I’m almost there, but still something is missing.

I found where the CommandHandler class is located in python (something like my_mission.guidance.my_guidance_mode.messages_msghub). Then I created my guidance mode class as a subclass of CommandHandler, just like is done in road_runner example. Something like this:

import my_mission.guidance.my_guidance_mode.messages_msghub as mode_msghub
import guidance.core as gdnc_core

class myMode(gdnc_core.Mode, mode_msghub.CommandHandler):

And then this:

self.msghub = self.guidance.get_message_hub()
self.msghub.attach_message_handler(self)

As I understand, in road_runner you set ‘this’ as argument because the Processing class is a subclass of CommandHandler and the ‘mMessageHub.attachMessageHandler()’ method is ok with that.

However, in python it raises a TypeError error because (I guess) it expects a MessageHandler type and gets a CommandHandler instead, even when the class CommandHandler is a subclass of MessageHandler as defined in messages_msghub.py:

class CommandHandler(msghub.MessageHandler):

The ‘attach_message_handler’ call is the only thing I need to solve know, and I’m sure the solution is silly but I can’t see it XD Maybe it is just a ‘python thing’ that I dont know how to do.

Thanks for your time

Hi @Diego,

Sorry for the delay. Thank you @_fisian for your reply. There are several ways to to handle a command. This is one of the simplest with Python:

Let’s start with the .proto file:

syntax = "proto3";

import "google/protobuf/empty.proto";

package [MISSION_NAME].guidance.[GUIDANCE_MODE_NAME].messages;

message Command {
    oneof id {
        bool test_cmd = 1;
    }
}

And the new python guidance mode file:


[...]

# messages
import [MISSION_NAME].guidance.[GUIDANCE_MODE_NAME].messages_pb2 as test_msgs
from msghub_utils import service_name

[...]

class CmdHandler(gdnc_core.MessageHandler):
    def __init__(self, mode):
        super().__init__(service_name(test_msgs.Command))
        self.mode = mode

        self.dispatch_table = {
            "test_cmd": self._on_test_cmd,
        }

    def handle(self, msg):
        msg = test_msgs.Command.FromString(msg.data)
        msgname = msg.WhichOneof("id")

        dispatch_fn = self.dispatch_table.get(msgname)
        if dispatch_fn:
            dispatch_fn(msg)
        else:
            self.log.error(f"no handler function for message {msgname}")

    def _on_test_cmd(self, msg):
        # your code here

class [GUIDANCE_MODE_NAME](gdnc_core.Mode):
    def __init__(self, guidance, name):
        super().__init__(guidance, name)
        self.loop = self.guidance.get_loop()
        self.msghub = self.guidance.get_message_hub()
        self.cmd_handler = CmdHandler(self)

    def shutdown(self):
        self.loop = None
        self.msghub = None
        self.cmd_handler = None

    def enter(self):
        self.msghub.attach_message_handler(self.cmd_handler)

    def exit(self):
        self.msghub.detach_message_handler(self.cmd_handler)

[...]

Regards,
Axel

Hi,

Thank you very much, it works! I also tried to implement the command handler class instead of the importing it, but I might have done something wrong.

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.