How to get connected Remote Model while inside arsdkengine

I have a need to determine the type of remote (sky controller) I’m connected to while inside a device’s peripheral class in arsdkengine.

The best method I have found is to use the UID provided via the device controller’s connector to look up the remote’s details in the persistent store.

if (droneController.getActiveProvider() != null) {
    final DeviceConnectorCore connector = droneController.getActiveProvider().getConnector();

    skyController = connector.getType() == DeviceConnector.Type.REMOTE_CONTROL;

    if (skyController && connector.getUid() != null) {
        final PersistentStore.Dictionary dict = droneController.getEngine().getPersistentStore().getDevice(connector.getUid());
        final Integer model = dict.getInt(KEY_DEVICE_MODEL);

        if (model != null) {
            useMux = == model || == model;

if (skyController) {

if (!useMux) {
    bebopLocalRtspServer = new BebopLocalRtspServer(skyController);

This seems like a lot of work just to figure out what kind of remote I’m connected to. Perhaps there’s an obvious option I’m simply missing?


We try to make arsdkengine component controllers as much as isolated pieces of code as possible. We rarely have dependencies between various component controllers (except maybe for piloting interfaces, that are somehow ‘managed’ by a central ‘PilotingItfActivationController’); we never have dependencies from a drone peripheral controller to the outside context as far as you try to do, so I cannot point you to some code sample you may study.

You approach seems correct to me, I am afraid there is no simpler solution to do what you want.

droneController.getActiveProvider().getConnector().getUid() is AFAICT the only way to retrieve the remote control uid from where you are.

With this uid, you basically may consider two approaches:

  • Either as you did, by querying the engine persistent store.
  • Or you may query the engine’s RemoteControlStore, which will give you access to the RemoteControlCore object that matches this uid: RemoteControlCore rc = droneController.getEngine().getUtilityOrThrow(RemoteControlStore.class).get(uid)
    Then you may query the model from this object: RemoteControl.Model model = rc.getModel()

Out of curiosity, are you trying to retrofit Bebop/2 + SkyController/2 support into arsdkengine ?


1 Like

Thank you for the pointer to the RemoteControlStore class. I may use it instead.

What drove me to go down this path was being surprised to find getActiveProvider().getConnector() return a Technology value of WIFI. I expected to see USB set and when I didn’t, I just assumed I was looking at the connector between the remote and drone, not the controller and remote.

final DeviceConnectorCore connector = droneController.getActiveProvider().getConnector();
skyController = connector.getType() == DeviceConnector.Type.REMOTE_CONTROL;

//always evaluates false
useMux = connector.getTechnology() == DeviceConnector.Technology.USB;

Later this evening I’ll take a look at droneController.getDevice().getDeviceStateCore().getConnectors() to see if there is one with Tech set to USB.

Yes, I am retrofitting groundsdk for Bebop/Disco arstream2 and Mambo rtsp handling.

The above is a snippet from a device class specific StreamServer peripheral that overrides the live stream URL with “{net or mux}/arstream2/bebop” that I later evaluate in native code to determine its final value before being passed along with an address to the stream demuxer.

    if (model instanceof Drone.Model) {
        Drone.Model droneModel = (Drone.Model) model;
        switch (droneModel) {
            case BEBOP_V1:
            case BEBOP_V2:
            case DISCO:
                return new BebopFamilyDroneController(this, uid, droneModel, name);
            case ANAFI_4K:
            case ANAFI_THERMAL:
                return new AnafiFamilyDroneController(this, uid, droneModel, name);
            case MAMBO:
                return new MiniatureFamilyDroneController(this, uid, droneModel, name);
    } else if (model instanceof RemoteControl.Model) {
        RemoteControl.Model rcModel = (RemoteControl.Model) model;
        switch (rcModel) {
            case SKY_CONTROLLER:
            case SKY_CONTROLLER_NG:
            case SKY_CONTROLLER_2:
            case SKY_CONTROLLER_2P:
            case SKY_CONTROLLER_3:
                return new SkyControllerFamilyController(this, uid, rcModel, name);

Beyond the basics of exposing the Model IDs and qualifying them, I have determined all that is needed to get things working for the bebop is to make sure the arstream2 data/stream parameters are passed via the initial json handshake for net connections with a loopback interface rtsp server (a very basic socket server) I embedded in the StreamServer issuing an sdp pointed to the drone’s Ip. libpdraw and librtsp are oblivious to the local redirect.

In packages/common/arsdk-ng/libarsdk/src/net/arsdk_net.h:

#define ARSDK_CONN_JSON_KEY_ARSTREAM2_STREAM_PORT  "arstream2_client_stream_port"
#define ARSDK_CONN_JSON_KEY_ARSTREAM2_CONTROL_PORT "arstream2_client_control_port"

In packages/common/arsdk-ng/libarsdk/src/net/arsdk_backend_net.c and packages/common/arsdk-ng/libarsdkctrl/src/net/arsdkctrl_backend_net.c after setting the QoS mode:

	/* Add requested QOS mode */
	json_object_object_add(jroot, ARSDK_CONN_JSON_KEY_QOS_MODE,

	/* silly Parrot dropped ARSTREAM2 port allocations */
	json_object_object_add(jroot, ARSDK_CONN_JSON_KEY_ARSTREAM2_STREAM_PORT,

	json_object_object_add(jroot, ARSDK_CONN_JSON_KEY_ARSTREAM2_CONTROL_PORT,

For mux connections it was even easier. I merely needed to truncate the URL as the muxer already has logic to use the mux stream channels if the URL is empty.

For the Mambo, the override for it was simply getting the IP address and stream URI set appropriately.

The only other item worth noting was that I had to comment out the Date header check/read in librtsp. The Mambo’s Rtsp server sets its date header to a non standard timestamp. Rather than modify rtsp.c to parse it, I simply skip checking it as it is not used downstream.

in packages/common/librtsp/src/rtsp.c after reading the CSeq header:

			if (!strncasecmp(field,
					 strlen(RTSP_HEADER_CSEQ))) {
				/* 'CSeq' */
				header->cseq = atoi(value);

			// } else if (!strncasecmp(field,
			// 			strlen(RTSP_HEADER_DATE))) {
			// 	/* 'Date' */
			// 	uint64_t epoch_sec = 0;
			// 	int32_t utc_offset_sec = 0;
			// 	ret = time_local_parse(
			// 		value, &epoch_sec, &utc_offset_sec);
			// 	if (ret < 0) {
			// 		ULOG_ERRNO("time_local_parse", -ret);
			// 		return ret;
			// 	}
			// 	header->date = epoch_sec;

Oh, and then there is all the analysis, retrofitting, and creation of instruments and peripherals to support the “legacy” ardrone3 and minidrone command sets and events. I’m going about this is in a manner that preserves the device agnostic interface.

Lastly I’ll tackle media / device storage management / handling. I’m not looking forward to this piece and may try to jimmy jam libARUtils with its dependencies into my workspace to cover all of the nuances between FTP and mux data transfers.


1 Like