Skip to content

Commit

Permalink
grpc: Support multiple device handling
Browse files Browse the repository at this point in the history
Updates Dronecore Server, grpc plugin api's to consider UUID
Updates Python Client examples to take UUID as a parameter for distinguishing between devices
Adds a serive in dronecore plugin to fetch the list of UUID's discovered by dronecore server
Adds multiple_device_handling.py to illustrate an example for handling multiple devices
  • Loading branch information
Rjasuja committed Dec 20, 2017
1 parent e89c354 commit df29901
Show file tree
Hide file tree
Showing 13 changed files with 148 additions and 56 deletions.
11 changes: 10 additions & 1 deletion grpc/proto/dronecore.proto
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,17 @@ syntax = "proto3";

package dronecorerpc;

import "google/protobuf/empty.proto" ;

// Interface exported by the server.
service DroneCoreRPC {
rpc Get_UUID_List(google.protobuf.Empty) returns(Active_UUID_List) {}
}

message UUID {
uint64 uuid = 1;
}

message Empty {}
message Active_UUID_List {
repeated UUID uuid_list = 1;
}
1 change: 1 addition & 0 deletions grpc/python_client/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ include(FindPythonInterp REQUIRED)
add_custom_target(pydronecore ALL)

set(plugins_dir ${CMAKE_SOURCE_DIR}/grpc/server/plugins)
set(plugins_list action mission telemetry)

if(${PYTHONINTERP_FOUND})
set(proto_dir ${CMAKE_SOURCE_DIR}/grpc/proto)
Expand Down
29 changes: 19 additions & 10 deletions grpc/python_client/async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
import grpc
import time
import threading
# import dronecore_pb2 as dc
# import dronecore_pb2_grpc
import sys
import action_pb2 as dc_action
import action_pb2_grpc
# import telemetry_pb2 as dc_telemetry
import telemetry_pb2_grpc
from google.protobuf import empty_pb2

import dronecore_pb2 as dronecore
import dronecore_pb2_grpc

class Colors:
BLUE = "\033[34m"
Expand All @@ -24,9 +24,9 @@ def wait_until(status):
return ret


def print_altitude(telemetry_stub, stop):
def print_altitude(telemetry_stub, device_uuid, stop):
for i, position in enumerate(
telemetry_stub.TelemetryPositionSubscription(empty_pb2.Empty())):
telemetry_stub.TelemetryPositionSubscription(device_uuid)):
# Position updates with SITL are too fast, we skip 9/10.
if i % 10 == 0:
print(Colors.BLUE, end="")
Expand All @@ -39,16 +39,25 @@ def print_altitude(telemetry_stub, stop):

def run():
channel = grpc.insecure_channel('0.0.0.0:50051')
# stub = dronecore_pb2_grpc.DroneCoreRPCStub(channel)
action_stub = action_pb2_grpc.ActionRPCStub(channel)
telemetry_stub = telemetry_pb2_grpc.TelemetryRPCStub(channel)
dronecore_stub = dronecore_pb2_grpc.DroneCoreRPCStub(channel)
response=dronecore_stub.Get_UUID_List(empty_pb2.Empty())
size=len(response.uuid_list)
print("Devices registered : {}".format(size))

device_uuid=dronecore.UUID()
if len(sys.argv) == 2:
device_uuid.uuid=int(sys.argv[1])
else :
device_uuid.uuid=response.uuid_list[0].uuid

# We use this stop event later to stop the thread.
t_stop = threading.Event()
t = threading.Thread(target=print_altitude, args=(telemetry_stub, t_stop))
t = threading.Thread(target=print_altitude, args=(telemetry_stub, device_uuid, t_stop))
t.start()

arm_result = action_stub.Arm.future(empty_pb2.Empty())
arm_result = action_stub.Arm.future(device_uuid)
arm_result = wait_until(arm_result)
if arm_result.result == dc_action.ActionResult.SUCCESS:
print("arming ok")
Expand All @@ -57,7 +66,7 @@ def run():

time.sleep(2)

takeoff_result = action_stub.TakeOff.future(empty_pb2.Empty())
takeoff_result = action_stub.TakeOff.future(device_uuid)
takeoff_result = wait_until(takeoff_result)
if takeoff_result.result == dc_action.ActionResult.SUCCESS:
print("takeoff ok")
Expand All @@ -66,7 +75,7 @@ def run():

time.sleep(5)

land_result = action_stub.Land.future(empty_pb2.Empty())
land_result = action_stub.Land.future(device_uuid)
land_result = wait_until(land_result)
if land_result.result == dc_action.ActionResult.SUCCESS:
print("landing ok")
Expand Down
26 changes: 20 additions & 6 deletions grpc/python_client/fly_mission.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
import grpc
import time
import threading
# import dronecore_pb2 as dc
# import dronecore_pb2_grpc
# import dronecore_pb2_grpc
import sys
# import action_pb2 as dc_action
import action_pb2_grpc
import mission_pb2 as dc_mission
import mission_pb2_grpc
from google.protobuf import empty_pb2
import dronecore_pb2 as dronecore
import dronecore_pb2_grpc


thread_status = True
Expand All @@ -31,6 +31,17 @@ def run():
# stub = dronecore_pb2_grpc.DroneCoreRPCStub(channel)
action_stub = action_pb2_grpc.ActionRPCStub(channel)
mission_stub = mission_pb2_grpc.MissionRPCStub(channel)
dronecore_stub = dronecore_pb2_grpc.DroneCoreRPCStub(channel)

response=dronecore_stub.Get_UUID_List(empty_pb2.Empty())
size=len(response.uuid_list)
print("Devices registered : {}".format(size))

device_uuid=dronecore.UUID()
if len(sys.argv) == 2:
device_uuid.uuid=int(sys.argv[1])
else :
device_uuid.uuid=response.uuid_list[0].uuid

mission_items = []

Expand Down Expand Up @@ -94,13 +105,16 @@ def run():
gimbal_yaw_deg=0,
camera_action=dc_mission.MissionItem.STOP_PHOTO_INTERVAL))

mission_stub.SendMission(dc_mission.Mission(mission_items=mission_items))
device_mission=dc_mission.Mission()
device_mission.uuid=device_uuid.uuid
device_mission.mission_items.extend(mission_items)
mission_stub.SendMission(device_mission)
time.sleep(1)

action_stub.Arm(empty_pb2.Empty())
action_stub.Arm(device_uuid)
time.sleep(1)

future_status = mission_stub.StartMission.future(empty_pb2.Empty())
future_status = mission_stub.StartMission.future(device_uuid)
t = threading.Thread(target=wait_func, args=(future_status,))
t.start()

Expand Down
49 changes: 49 additions & 0 deletions grpc/python_client/multiple_device_handling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env python

from __future__ import print_function
import grpc
import time
import action_pb2 as dc_action
import action_pb2_grpc
import dronecore_pb2 as dronecore
import dronecore_pb2_grpc
from google.protobuf import empty_pb2

def run():
channel = grpc.insecure_channel('0.0.0.0:50051')
action_stub = action_pb2_grpc.ActionRPCStub(channel)
dronecore_stub = dronecore_pb2_grpc.DroneCoreRPCStub(channel)
response=dronecore_stub.Get_UUID_List(empty_pb2.Empty())
size=len(response.uuid_list)
print("Devices registered : {}".format(size))
print(response.uuid_list[0].uuid)

for i in range(size):
uuid_item=dronecore.UUID()
uuid_item.uuid=response.uuid_list[i].uuid
print(uuid_item.uuid)
arm_result = action_stub.Arm(uuid_item)
if arm_result.result == dc_action.ActionResult.SUCCESS:
print("arming ok")
else:
print("arming failed: " + arm_result.result_str)

time.sleep(2)

takeoff_result = action_stub.TakeOff(uuid_item)
if takeoff_result.result == dc_action.ActionResult.SUCCESS:
print("takeoff ok")
else:
print("takeoff failed: " + takeoff_result.result_str)

time.sleep(5)

land_result = action_stub.Land(uuid_item)
if land_result.result == dc_action.ActionResult.SUCCESS:
print("landing ok")
else:
print("landing failed: " + land_result.result_str)


if __name__ == '__main__':
run()
22 changes: 17 additions & 5 deletions grpc/python_client/sync_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,46 @@
from __future__ import print_function
import grpc
import time
# import dronecore_pb2 as dc
# import dronecore_pb2_grpc
import sys
import action_pb2 as dc_action
import action_pb2_grpc
import dronecore_pb2 as dronecore
import dronecore_pb2_grpc
from google.protobuf import empty_pb2


def run():
channel = grpc.insecure_channel('0.0.0.0:50051')
action_stub = action_pb2_grpc.ActionRPCStub(channel)
dronecore_stub = dronecore_pb2_grpc.DroneCoreRPCStub(channel)

arm_result = action_stub.Arm(empty_pb2.Empty())
response=dronecore_stub.Get_UUID_List(empty_pb2.Empty())
size=len(response.uuid_list)
print("Devices registered : {}".format(size))

device_uuid=dronecore.UUID()
if len(sys.argv) == 2:
device_uuid.uuid=int(sys.argv[1])
else :
device_uuid.uuid=response.uuid_list[0].uuid

arm_result = action_stub.Arm(device_uuid)
if arm_result.result == dc_action.ActionResult.SUCCESS:
print("arming ok")
else:
print("arming failed: " + arm_result.result_str)

time.sleep(2)

takeoff_result = action_stub.TakeOff(empty_pb2.Empty())
takeoff_result = action_stub.TakeOff(device_uuid)
if takeoff_result.result == dc_action.ActionResult.SUCCESS:
print("takeoff ok")
else:
print("takeoff failed: " + takeoff_result.result_str)

time.sleep(5)

land_result = action_stub.Land(empty_pb2.Empty())
land_result = action_stub.Land(device_uuid)
if land_result.result == dc_action.ActionResult.SUCCESS:
print("landing ok")
else:
Expand Down
21 changes: 8 additions & 13 deletions grpc/server/dronecore_server.cpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "action/actionrpc_impl.h"
#include "mission/missionrpc_impl.h"
#include "telemetry/telemetryrpc_impl.h"
#include "dronecore/dronecorerpc_impl.h"

using grpc::Server;
using grpc::ServerBuilder;
Expand All @@ -35,17 +36,10 @@ template<typename T> ::grpc::Service *createInstances(DroneCore *dc_obj) {return

typedef std::map<std::string, ::grpc::Service*(*)(DroneCore *dc_obj)> map_type;

class DroneCoreRPCImpl final : public DroneCoreRPC::Service
{

public:

};

void RunServer()
{
std::string server_address("0.0.0.0:50051");
DroneCoreRPCImpl service;
DroneCoreRPCImpl service(&dc);

map_type map;
std::string plugin;
Expand All @@ -58,25 +52,26 @@ void RunServer()
std::vector<::grpc::Service *> list;
${PLUGIN_MAP_APPEND_STRING}


while (file >> plugin) {
auto service_obj = map[plugin](&dc);
list.push_back(service_obj);
}

bool discovered_device = false;
DroneCore::ConnectionResult connection_result = dc.add_udp_connection();
int discovered_device = 0;
DroneCore::ConnectionResult connection_result = dc.add_udp_connection(14550);
if (connection_result != DroneCore::ConnectionResult::SUCCESS) {
LogErr() << "Connection failed: " << DroneCore::connection_result_str(connection_result);
return;
}
LogInfo() << "Waiting to discover device...";
dc.register_on_discover([&discovered_device](uint64_t uuid) {
LogInfo() << "Discovered device with UUID: " << uuid;
discovered_device = true;
discovered_device += 1;
});
// We usually receive heartbeats at 1Hz, therefore we should find a device after around 2 seconds.
std::this_thread::sleep_for(std::chrono::seconds(2));
if (!discovered_device) {
std::this_thread::sleep_for(std::chrono::seconds(10));
if (discovered_device == 0) {
LogErr() << "No device found, exiting.";
return;
}
Expand Down
8 changes: 4 additions & 4 deletions grpc/server/plugins/action/action.proto
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
syntax = "proto3";

import "google/protobuf/empty.proto";
import "dronecore.proto";

package dronecorerpc;

service ActionRPC {
rpc Arm(google.protobuf.Empty) returns(ActionResult) {}
rpc TakeOff(google.protobuf.Empty) returns(ActionResult) {}
rpc Land(google.protobuf.Empty) returns(ActionResult) {}
rpc Arm(UUID) returns(ActionResult) {}
rpc TakeOff(UUID) returns(ActionResult) {}
rpc Land(UUID) returns(ActionResult) {}
}

message ActionResult {
Expand Down
14 changes: 7 additions & 7 deletions grpc/server/plugins/action/actionrpc_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using grpc::Status;
using grpc::ServerContext;
using dronecorerpc::ActionRPC;
using dronecorerpc::Empty;
using dronecorerpc::UUID;

using namespace dronecore;

Expand All @@ -17,28 +17,28 @@ class ActionRPCImpl final : public ActionRPC::Service
dc = dc_obj;
}

Status Arm(ServerContext *context, const ::google::protobuf::Empty *request,
Status Arm(ServerContext *context, const UUID* request,
dronecorerpc::ActionResult *response) override
{
const Action::Result action_result = dc->device().action().arm();
const Action::Result action_result = dc->device(request->uuid()).action().arm();
response->set_result(static_cast<dronecorerpc::ActionResult::Result>(action_result));
response->set_result_str(Action::result_str(action_result));
return Status::OK;
}

Status TakeOff(ServerContext *context, const ::google::protobuf::Empty *request,
Status TakeOff(ServerContext *context, const UUID* request,
dronecorerpc::ActionResult *response) override
{
const Action::Result action_result = dc->device().action().takeoff();
const Action::Result action_result = dc->device(request->uuid()).action().takeoff();
response->set_result(static_cast<dronecorerpc::ActionResult::Result>(action_result));
response->set_result_str(Action::result_str(action_result));
return Status::OK;
}

Status Land(ServerContext *context, const ::google::protobuf::Empty *request,
Status Land(ServerContext *context, const UUID* request,
dronecorerpc::ActionResult *response) override
{
const Action::Result action_result = dc->device().action().land();
const Action::Result action_result = dc->device(request->uuid()).action().land();
response->set_result(static_cast<dronecorerpc::ActionResult::Result>(action_result));
response->set_result_str(Action::result_str(action_result));
return Status::OK;
Expand Down
Loading

0 comments on commit df29901

Please sign in to comment.