Overview

UgCS .Net SDK gives access to core services of our Universal Control Server. Using this SDK it is possible to develop third party client applications that can programmatically:

  • access various UgCS entities like missions, routes, vehicles, vehicle profiles, payloads, telemetry, etc;

  • subscribe to notifications like telemetry, vehicle connection, routes change, ads-b collision, etc;

  • issue commands to vehicles;

  • calculate routes;

  • access elevation data.

SDK gives developer a way to implement a simple widget to display telemetry parameter or full functional drone control client application.

Release history

Please find the release history and release notes at https://www.nuget.org/packages/ugcs-dotnet-sdk.

Prerequisites

Visual Studio 2017 Community Edition

.Net Framework 4.5 or later

NuGet package manager (shall be a part of Visual Studio)

Installed UgCS application, 3.7 or later. Please note that SDK release version should be the same as UgCS version https://www.ugcs.com/en/page/download

Note : number of allowed UgCS client connections to UGCS Server depends on the license type. For Open and One versions only one connection allowed. For Pro 3 and Enterprise is unlimited. This means that for Open and One it is not possible to have UgCS standard client and your application running at the same time.

Getting started

Creating project

Open Visual Studio and select on of possible C# projects. To use SDK you have to add references to appropriate assemblies. The most recent assemblies are available in our nugget repository. To get package open your package manager command line and type: nuget install ugcs-dotnet-sdk

image0

After successful download the following references shall appear in your project:

  • Sdk.dll

  • Protobuf-net.dll

We use protobuf as a container for our messages so SDK uses it as a dependency.

Add the following namespaces to your “using” sections of C# code:

using UGCS.Sdk.Protocol;
using UGCS.Sdk.Protocol.Encoding;
using UGCS.Sdk.Tasks;
using ProtoBuf;

Basic concepts

There are two ways of communication between client application and UGCS Server:

  • asynchronous request/ response;

  • subscription.

Though all communication is asynchronous there are certain ways to implement synchronous workflow on the client.

Typically you will use requests/responses to make standard CRUD operations and to list objects. For example get list of vehicles, create vehicle profile, remove payload, etc.

Subscriptions are useful to listen for some events. For example if you want to get telemetry stream for the vehicle you typically subscribe to telemetry events. It is more appropriate way comparing to setting timer on the client and pulling UCS every N seconds.

Connecting to UGCS Server

Establishing connection to UGCS Server is the first step to be performed. It consists of the following main operations:

  1. establishing TCP connection;

  2. authorizing client session

Create instance of TcpClient class and pass host and port as parameters. If UgCS Server is running on the same computer then specify “localhost” for a host and 3334 as a port number.

TcpClient tcpClient = new TcpClient("localhost", 3334);
MessageSender messageSender = new MessageSender(tcpClient.Session);
MessageReceiver messageReceiver = new MessageReceiver(tcpClient.Session);
MessageExecutor messageExecutor = new MessageExecutor(messageSender, messageReceiver, new InstantTaskScheduler());
messageExecutor.Configuration.DefaultTimeout = 10000;
var notificationListener = new NotificationListener();
messageReceiver.AddListener(-1, notificationListener);

To test your application you need UgCS Server running. Check that clicking UgCS icon in tray.

image1

Compile and run that simple application. If client object instantiated successfully than you may find your session object in client.Session property.

The next step is to get clientID. ClientID is a thing that you must specify for every request towards UgCS Server. But before that we need to prepare some code for sending and receiving messages.

AuthorizeHciRequest request = new AuthorizeHciRequest();
request.ClientId = -1;
request.Locale = "en-US";
var future = messageExecutor.Submit<AuthorizeHciResponse>(request);
future.Wait();
AuthorizeHciResponse AuthorizeHciResponse = future.Value;
int clientId = AuthorizeHciResponse.ClientId

What we do here is just sending AuthorizeHciRequest to UgCS Server. Request has to parameters:

  • ClientID and we set it to default -1 value;

  • Locale – client locale (optional), en-US by default here. Local defines localization for strings that UgCS Server sends to client.

Another important thing to note is how we get response from the UgCS Server. We employ future (or promise) concept here for asynchronous communication. Typically this means that you submit some response , specify callback and do not wait for response doing something. But here we explicitly wait for response invoking Value property of authFuture object. That is a general approach for making pseudo-synchronous requests/responses.

We are almost ready to do something really useful. The only thing that has to be done is to login into the system. UgCS Server uses login based authentication model. Look at the source code:

LoginRequest loginRequest = new LoginRequest();
loginRequest.UserLogin = "admin";
loginRequest.UserPassword = "admin";
loginRequest.ClientId = clientId;
var loginResponcetask = messageExecutor.Submit<LoginResponse>(loginRequest);
loginResponcetask.Wait();

It is pretty straightforward. Note that we use clientID as an argument to LoginRequest. The only question is how to deal with login and password. Generally you must specify login and password from user list. But there is a trick. If you have only one user registered then you can put empty strings and SDK will try to make autologin.

That’s it. Now we are logged in into UGCS server and can do something.

Accessing server objects

Vehicles

List

This example shows how to get vehicle list from the server. First of all we need find appropriate request/response pair. There is a universal operation for getting object lists called GetObjectList. It works similar for many objects. You need to specify clientId and ObjectType. In our case object type “Vehicle”

GetObjectListRequest getObjectListRequest = new GetObjectListRequest()
{
    ClientId = clientId,
    ObjectType = "Vehicle",
    RefreshDependencies = true
};
getObjectListRequest.RefreshExcludes.Add("PayloadProfile");
getObjectListRequest.RefreshExcludes.Add("Route");
var task = messageExecutor.Submit<GetObjectListResponse>(getObjectListRequest);
task.Wait();

Nothing new in this sample. And we did a half of the job. Now we need to access vehicle data itself. Response object contains a lot of general properties and some specific ones. Actual data resides in Objects collection. So to list vehicles we can use the following code:

var list = task.Value;
foreach (var v in list.Objects)
{
    System.Console.WriteLine(string.Format("name: {0}; id: {1}; type: {2}",
           v.Vehicle.Name, v.Vehicle.Id, v.Vehicle.Type.ToString()));
}
Vehicle vehicle = task.Value.Objects.FirstOrDefault().Vehicle;

Update

This example shows how to update vehicle on the server.

CreateOrUpdateObjectRequest createOrUpdateObjectRequest = new CreateOrUpdateObjectRequest()
{
    ClientId = clientId,
    Object = new DomainObjectWrapper().Put(vehicle, "Vehicle"),
    WithComposites = true,
    ObjectType = "Vehicle",
    AcquireLock = false
};
var createOrUpdateObjectResponseTask = messageExecutor.Submit<CreateOrUpdateObjectResponse>(createOrUpdateObjectRequest);
createOrUpdateObjectResponseTask.Wait();

Delete

This example shows how to delete vehicle on the server.

DeleteObjectRequest request = new DeleteObjectRequest()
{
    ClientId = clientId,
    ObjectId = vehicle.Id,
    ObjectType = "Vehicle"
};
var task = messageExecutor.Submit<DeleteObjectResponse>(request);

Vehicle profiles

List

MessageFuture<GetObjectListResponse> listFuture =
    messageExecutor.Submit<GetObjectListResponse>(
    new GetObjectListRequest
    {
        ClientId = clientId,
        ObjectType = "VehicleProfile"
    });
GetObjectListResponse listResp = listFuture.Value;

Response object contains data in Objects property. Each object is of DomainObjectWrapper type. Wrapper has a lot of properties for different object types. In this case we need VehicleProfile property. Each profile stores it’s parameters in Parameters collection.

Payloads

List

MessageFuture<GetObjectListResponse> listFuture =    messageExecutor.Submit<GetObjectListResponse>(
    new GetObjectListRequest
    {
        ClientId = clientId,
        ObjectType = "PayloadProfile"
    });
GetObjectListResponse listResp = listFuture.Value;

Response object contains data in Objects property. Each object is of DomainObjectWrapper type. Wrapper has a lot of properties for different object types. In this case we need PayloadProfile property. Each profile stores it’s parameters in Parameters collection.

Missions

Create mission

Mission mission = new Mission
{
    CreationTime = 1270011748,
    Name = "Mission name",
    Owner = user
};
CreateOrUpdateObjectRequest request = new CreateOrUpdateObjectRequest()
{
    ClientId = 1,
    Object = new DomainObjectWrapper().Put(mission, "Mission"),
    WithComposites = true,
    ObjectType = "Mission",
    AcquireLock = false
};
var task = messageExecutor.Submit<CreateOrUpdateObjectResponse>(request);

Import mission from xml

var byteArray = File.ReadAllBytes("Demo mission.xml");
ImportMissionRequest importMissionRequest = new ImportMissionRequest()
{
    ClientId = clientId,
    MissionData = byteArray,
    Filename = "Demo mission.xml"
};
var importMissionResponse = messageExecutor.Submit<ImportMissionResponse>(importMissionRequest);
importMissionResponse.Wait();

//importedMission contains imported mission from Demo mission.xml
var importedMission = importMissionResponse.Value.Mission;

Get mission from server

GetObjectRequest getMissionObjectRequest = new GetObjectRequest()
{
    ClientId = clientId,
    ObjectType = "Mission",
    ObjectId = mission.Id,
    RefreshDependencies = true
};
var getMissionObjectResponse = messageExecutor.Submit<GetObjectResponse>(getMissionObjectRequest);
getMissionObjectResponse.Wait();
//missionFromUcs contains retrieved mission
var missionFromUcs = getMissionObjectResponse.Value.Object.Mission;

Routes

Import route to server from xml

Stept to import route: 1) Import route to client from xml file 2) Add vehicle profile to imported route 3) Add mission to route 4) Save route

var byteArrayRoute = File.ReadAllBytes("Demo route for Copter.xml");
ImportRouteRequest importRouteRequest = new ImportRouteRequest()
{
    ClientId = clientId,
    RouteData = byteArrayRoute,
    Filename = "Demo route for Copter.xml"
};
var importRouteResponse = messageExecutor.Submit<ImportRouteResponse>(importRouteRequest);
importRouteResponse.Wait();
//importedRoute contains imported route from Demo route for Copter.xml
var importedRoute = importRouteResponse.Value.Route;
System.Console.WriteLine("Demo route for Copter.xml imported to UCS with name '{0}'", importedRoute.Name);
//Add vehicle profile to route
GetObjectRequest requestVehicle = new GetObjectRequest()
{
    ClientId = clientId,
    ObjectType = "Vehicle",
    ObjectId = 1, //EMU-COPTER-17
    RefreshDependencies = true
};
var responseVehicle = messageExecutor.Submit<GetObjectResponse>(requestVehicle);
responseVehicle.Wait();
importedRoute.VehicleProfile = responseVehicle.Value.Object.Vehicle.Profile;
//Add route to mission
importedRoute.Mission = missionFromUcs;
//Save route on server
CreateOrUpdateObjectRequest routeSaveRequest = new CreateOrUpdateObjectRequest()
{
    ClientId = clientId,
    Object = new DomainObjectWrapper().Put(importedRoute, "Route"),
    WithComposites = true,
    ObjectType = "Route",
    AcquireLock = false
};
var updateRouteTask = messageExecutor.Submit<CreateOrUpdateObjectResponse>(routeSaveRequest);
updateRouteTask.Wait();

Get route from server

GetObjectRequest getRouteObjectRequest = new GetObjectRequest() { ClientId = clientId, ObjectType = “Route”, ObjectId = updateRouteTask.Value.Object.Route.Id, RefreshDependencies = true }; var geRouteObjectResponse = messageExecutor.Submit(getRouteObjectRequest); geRouteObjectResponse.Wait(); //routeFromUcs contains retrieved route var routeFromUcs = geRouteObjectResponse.Value.Object.Route;

Accessing telemetry storage

Here is a sample of telemetry request to obtain telemetry for the last hour. Not that we specify vehicle object (see Vehicles sample) as a parameter. Another important parameters are ToTime and FromTime – time interval. Limit defines maximum number of telemetry records to be fetched. Zero means no limit.

DateTime utcTime = DateTime.Now.ToUniversalTime();
DateTime posixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
TimeSpan span = utcTime - posixEpoch;
var beginningMilliseconds = (long)span.TotalMilliseconds;
GetTelemetryRequest telemetryRequest = new GetTelemetryRequest
{
    ClientId = clientId,
    FromTime = beginningMilliseconds,
    Limit = 10,
    Vehicle = new Vehicle() { Id = 1 }
};
var responseTelemetry = messageExecutor.Submit<GetTelemetryResponse>(telemetryRequest);
responseTelemetry.Wait();

Response object contains data in Telemetry property. Each object is of TelemetryDto type. Field “Type” contains field type, “Value” contains value and “Time” is a POSIX time.

The following types available:

Type

Description

TT_BATTERY_VOLTAGE

TT_ROLL

Roll

TT_PITCH

Pitch

TT_YAW

Yaw

TT_ROLL_SPEED

TT_PITCH_SPEED

TT_YAW_SPEED

TT_LATITUDE

Latitude from autopilot (filtered)

TT_LONGITUDE

Longitude from autopilot (filtered)

TT_MSL_ALTITUDE

AMSL Altitude

TT_AGL_ALTITUDE

AGL altitude

TT_GROUND_SPEED_X

Ground speed X part (filtered)

TT_GROUND_SPEED_Y

Ground speed Y part (filtered)

TT_GROUND_SPEED_Z

Ground speed Z part (filtered)

TT_LATITUDE_GPS

Latitude raw

TT_LONGITUDE_GPS

Longitude raw

TT_ALTITUDE_GPS

TT_GROUND_SPEED_GPS

TT_ACCELERATION_X_RAW

TT_ACCELERATION_Y_RAW

TT_ACCELERATION_Z_RAW

TT_ANGULAR_SPEED_X_RAW

TT_ANGULAR_SPEED_Y_RAW

TT_ANGULAR_SPEED_Z_RAW

TT_MAGNETIC_X_RAW

TT_MAGNETIC_Y_RAW

TT_MAGNETIC_Z_RAW

TT_ABSOLUTE_PRESSURE

TT_DIFFERENTIAL_PRESSURE

TT_TEMPERATURE

TT_AIR_SPEED

TT_GROUND_SPEED

Ground speed (vector sum of X and Y) ??

TT_HEADING

Heading

TT_THROTTLE

TT_CLIMB_RATE

Vertical speed

TT_GPS_SATELLITES_VISIBLE

TT_ROUTE_MILAGE

TT_TELEMETRY_DROP_RATE

TT_DOWNLINK_CONNECTED

TT_UPLINK_CONNECTED

TT_CONTROL_MODE

TT_STATE

TT_COURSE

TT_RELATIVE_ALTITUDE

TT_ELEVATION

Ground elevation

TT_PAYLOAD_1_ROLL

TT_PAYLOAD_1_TILT

TT_PAYLOAD_1_YAW

TT_CAMERA_1_FOV_HORIZONTAL

TT_CAMERA_1_FOV_VERTICAL

TT_GPS_FIX_TYPE

TT_RC_LINK_QUALITY

TT_ADSB_TRANSPONDER_MODE

TT_ADSB_IDENT_STATE

TT_ADSB_SQUAWK_CODE

TT_ADSB_ALTITUDE_SOURCE

TT_ADSB_ALTITUDE

TT_ADSB_ERROR_FLAGS

TT_PAYLOAD_2_ROLL

TT_PAYLOAD_2_TILT

TT_PAYLOAD_2_YAW

TT_CAMERA_2_FOV_HORIZONTAL

TT_CAMERA_2_FOV_VERTICAL

TT_PAYLOAD_1_CONTROL_MODE

TT_PAYLOAD_2_CONTROL_MODE

TT_PAYLOAD_1_AVAILABLE

TT_PAYLOAD_2_AVAILABLE

TT_PAYLOAD_1_POWERED

TT_PAYLOAD_2_POWERED

TT_CAMERA_1_ZOOM

TT_CAMERA_2_ZOOM

TT_CAMERA_1_RECORDING

TT_CAMERA_2_RECORDING

TT_CAMERA_1_IMAGE_COUNT

TT_CAMERA_2_IMAGE_COUNT

TT_CAMERA_1_IMAGE_CAPACITY

TT_CAMERA_2_IMAGE_CAPACITY

TT_CAMERA_1_VIDEO_COUNT

TT_CAMERA_2_VIDEO_COUNT

Note : telemetry recording is disabled in UgCS for Emulator by default. For development purposes is convenient to switch it on. To do that open <UgCS Installation Dir>:raw-latex:Server:raw-latex:`\ucs`:raw-latex:`\ucs`.properties and change field ucs.emulator.storeTelemetry= true.

Subscriptions

Vehicle subscription.

Code below initiates vehicle subscription.

var eventSubscriptionWrapper = new EventSubscriptionWrapper();
eventSubscriptionWrapper.ObjectModificationSubscription = new ObjectModificationSubscription();
eventSubscriptionWrapper.ObjectModificationSubscription.ObjectId = vehicle.Id;
eventSubscriptionWrapper.ObjectModificationSubscription.ObjectType = "Vehicle";
SubscribeEventRequest requestEvent = new SubscribeEventRequest();
requestEvent.ClientId = clientId;
requestEvent.Subscription = eventSubscriptionWrapper;
var responce = messageExecutor.Submit<SubscribeEventResponse>(requestEvent);
responce.Wait();
var subscribeEventResponse = responce.Value;
SubscriptionToken st = new SubscriptionToken(subscribeEventResponse.SubscriptionId, (
    (notification) =>
    {
        //Vehicle notification
    }
), eventSubscriptionWrapper);
notificationListener.AddSubscription(st);

Telemetry subscription.

Code describes how to subscribe telemetry

var telemetrySubscriptionWrapper = new EventSubscriptionWrapper();
telemetrySubscriptionWrapper.TelemetrySubscription = new TelemetrySubscription();
SubscribeEventRequest requestTelemetryEvent = new SubscribeEventRequest();
requestTelemetryEvent.ClientId = clientId;
requestTelemetryEvent.Subscription = telemetrySubscriptionWrapper;
var responceTelemetry = messageExecutor.Submit<SubscribeEventResponse>(requestTelemetryEvent);
responceTelemetry.Wait();
var subscribeEventResponseTelemetry = responceTelemetry.Value;
SubscriptionToken stTelemetry = new SubscriptionToken(subscribeEventResponseTelemetry.SubscriptionId, (
    (notification) =>
    {
        foreach (Telemetry t in notification.Event.TelemetryEvent.Telemetry)
        {
            System.Console.WriteLine("Vehicle id: {0} Code: {1} Semantic {2} Subsystem {3} Value {4}", notification.Event.TelemetryEvent.Vehicle.Id, t.TelemetryField.Code, t.TelemetryField.Semantic, t.TelemetryField.Subsystem, getTelemetryValue(t.Value));
        }
    }
), telemetrySubscriptionWrapper);
notificationListener.AddSubscription(stTelemetry);

Working with routes

Route consists of segments. Each segment has parameters. Refer here https://github.com/ugcs/ugcs-dotnet-sdk/wiki/Algorithms-And-Calculation-workflow for the list of parameters for different segments.

Create new route

Route route = new Route
{
    CreationTime = ServiceHelpers.CreationTime(),
    Name = routeName,
    Mission = mission
};

ChangeRouteVehicleProfileRequest request = new ChangeRouteVehicleProfileRequest
{
    ClientId = _connect.AuthorizeHciResponse.ClientId,
    Route = route,
    NewProfile = new VehicleProfile { Id = vehicleProfile.Id }
};
MessageFuture<ChangeRouteVehicleProfileResponse> future =
    _connect.Executor.Submit<ChangeRouteVehicleProfileResponse>(request);
future.Wait();
route = future.Value.Route;
route.Mission = mission;
route.TrajectoryType = TrajectoryType.TT_STAIR;
route.MaxAltitude = 50.0;
route.SafeAltitude = 3.0;
route.CheckAerodromeNfz = false;
route.CheckAerodromeNfzSpecified = true;
route.InitialSpeed = 0.0;
route.MaxSpeed = 0.0;
route.CheckCustomNfz = false;
route.CheckCustomNfzSpecified = true;
route.Failsafes.Add(new Failsafe()
{
    Action = FailsafeAction.FA_GO_HOME,
    ActionSpecified = true,
    Reason = FailsafeReason.FR_RC_LOST,
    ReasonSpecified = true,
});
route.Failsafes.Add(new Failsafe()
{
    Action = FailsafeAction.FA_LAND,
    ActionSpecified = true,
    Reason = FailsafeReason.FR_LOW_BATTERY,
    ReasonSpecified = true
});
route.Failsafes.Add(new Failsafe()
{
    Action = FailsafeAction.FA_WAIT,
    ActionSpecified = true,
    Reason = FailsafeReason.FR_GPS_LOST,
    ReasonSpecified = true
});
route.Failsafes.Add(new Failsafe()
{
    Action = FailsafeAction.FA_GO_HOME,
    ActionSpecified = true,
    Reason = FailsafeReason.FR_DATALINK_LOST,
    ReasonSpecified = true
});
CreateOrUpdateObjectRequest request = new CreateOrUpdateObjectRequest()
{
    ClientId = clientId,
    Object = new DomainObjectWrapper().Put(route, "Route"),
    WithComposites = true,
    ObjectType = "Route",
    AcquireLock = false
};
var task = messageExecutor.Submit<CreateOrUpdateObjectResponse>(request);

Add waypoint to route

TraverseAlgorithm wpAlgorithm = _mappingRequestService.GetAlgoritmByClassName("com.ugcs.ucs.service.routing.impl.WaypointAlgorithm");
SegmentDefinition newSegment = new SegmentDefinition
{
    Uuid = Guid.NewGuid().ToString(),
    AlgorithmClassName = wpAlgorithm.ImplementationClass
};
newSegment.Figure = new Figure { Type = wpAlgorithm.FigureType };

newSegment.ParameterValues.Add(new ParameterValue()
{
    Name = "speed",
    Value = "5.0",
    ValueSpecified = true,
});
newSegment.ParameterValues.Add(new ParameterValue()
{
    Name = "wpTurnType",
    Value = "SPLINE",
    ValueSpecified = true
});
newSegment.ParameterValues.Add(new ParameterValue()
{
    Name = "avoidObstacles",
    Value = "True",
    ValueSpecified = true
});
newSegment.ParameterValues.Add(new ParameterValue()
{
    Name = "avoidTerrain",
    Value = "True",
    ValueSpecified = true
});
//AGL, WGS84, RANGEFINDER (Only for Ardupilot)
newSegment.ParameterValues.Add(new ParameterValue()
{
    Name = "altitudeType",
    Value = "AGL",
    ValueSpecified = true
});


newSegment.Figure.Points.Add(new FigurePoint()
{
    AglAltitude = 20,
    AglAltitudeSpecified = true,
    AltitudeType = AltitudeType.AT_AGL,
    AltitudeTypeSpecified = true,
    Latitude = lat, //0.99443566874164979,
    LatitudeSpecified = true,
    Longitude = lng, //0.42015588448045021,
    LongitudeSpecified = true,
    Wgs84Altitude = 0.0,
    Wgs84AltitudeSpecified = true
});

route.Segments.Insert(index, newSegment);

Calculating the route

Code below initiates roite calculation

var updatedRoute = GetUpdatedRouteById(routeId);
ProcessRouteRequest request = new ProcessRouteRequest
{
    ClientId = _connect.AuthorizeHciResponse.ClientId,
    Route = updatedRoute,
};

MessageFuture<ProcessRouteResponse> task = _connect.Executor.Submit<ProcessRouteResponse>(request);
task.Wait();

if (task.Exception != null || task.Value == null)
{
    logger.LogException(task.Exception);
    throw new Exception("Calculate error: " + task.Exception.Message);
}
var processedRoute = task.Value.ProcessedRoute;

Uploading the route

Code below upload ProcessedRoute to selected vehicle

UploadRouteRequest request = new UploadRouteRequest
{
    ClientId = _connect.AuthorizeHciResponse.ClientId,
    ProcessedRoute = route,
    Vehicle = vehicle,
};
MessageFuture<UploadRouteResponse> task = messageExecutor.Submit<UploadRouteResponse>(request);
task.Wait();

Getting home position

Home location is availble from vehicle telemetry.

TT_HOME_LATITUDE TT_HOME_LONGITUDE TT_HOME_AMSL_ALTITUDE

Issuing command to a vehicle

Code below show how to send specific command to Vehicle

var sendCommandRequestGuided = new SendCommandRequest
{
    ClientId = clientId,
    Command = new UGCS.Sdk.Protocol.Encoding.Command
    {
        Code = "commandCode",
        Subsystem = Subsystem.S_FLIGHT_CONTROLLER
    }
};
sendCommandRequestGuided.Vehicles.Add(new Vehicle { Id = 2 });
var sendCommandResponseGuided = messageExecutor.Submit<SendCommandResponse>(sendCommandRequestGuided);
sendCommandResponseGuided.Wait();

Send command examples. Arm example:

var sendCommandRequestGuided = new SendCommandRequest
{
    ClientId = clientId,
    Command = new UGCS.Sdk.Protocol.Encoding.Command
    {
        Code = "arm",
        Subsystem = Subsystem.S_FLIGHT_CONTROLLER
    }
};
sendCommandRequestGuided.Vehicles.Add(new Vehicle { Id = 2 });

Takeoff command with argument:

SendCommandRequest request = new SendCommandRequest
{
    ClientId = _connect.AuthorizeHciResponse.ClientId,
    Command = new UGCS.Sdk.Protocol.Encoding.Command
    {
        Code = "takeoff_command",
        Subsystem = Subsystem.S_FLIGHT_CONTROLLER,
        Silent = true,
        ResultIndifferent = true
    }
};

request.Vehicles.Add(new Vehicle() { Id = 1 });
List<CommandArgument> list = new List<CommandArgument>();
list.Add(new CommandArgument { Code = "relativeAltitude", Value = new Value() { StringValue = Settings.Default.MinimumOperatingAltitude.ToString("0.00", System.Globalization.CultureInfo.InvariantCulture) }  });
request.Command.Arguments.AddRange(list);

Click&Go command with argument:

 var sendCommandRequest = new SendCommandRequest
{
    ClientId = clientId,
    Command = new UGCS.Sdk.Protocol.Encoding.Command
    {
        Code = "waypoint",
        Subsystem = Subsystem.S_FLIGHT_CONTROLLER
    }
};

sendCommandRequest.Command.Arguments.AddRange(new CommandArgument[] {
                        new CommandArgument { Code = "latitude", Value = new Value { DoubleValue = 0.994445232147517 }},
                        new CommandArgument { Code = "longitude", Value = new Value { DoubleValue = 0.4201742565140717 }},
                        new CommandArgument { Code = "altitude_agl", Value = new Value { DoubleValue = 5.0 }},
                        new CommandArgument { Code = "ground_speed", Value = new Value { DoubleValue = 5.0 }},
                        new CommandArgument { Code = "heading", Value = new Value { DoubleValue = 0.017453292519943295 }}
                    });

sendCommandRequest.Vehicles.Add(new Vehicle { Id = 2 });
var sendCommandResponse = messageExecutor.Submit<SendCommandResponse>(sendCommandRequest);

References

Operation

Messages

Comments

Authorize client session

AuthorizeHciRequest/R esponse

Login

LoginRequest/Response

List objects

GetObjectsListRequest /Response

Works for different object types:- Vehicle- VehicleProfile- …