Skip to content

Commit

Permalink
ROS1 Communication Support (#173)
Browse files Browse the repository at this point in the history
* Add ros-core container to ROS1-based NetApps

* Add new properties; connectionBuilderFactory tests

* WIP: new ros helper

* Added teleoperation NetApp import scripts

* Prepare new RosDistro struct

* Orchestrator use new RosDistro struct

* Remove RosDistro enum, add more tests
  • Loading branch information
Artonus committed Jun 29, 2023
1 parent 73739fc commit 59be9a0
Show file tree
Hide file tree
Showing 23 changed files with 576 additions and 119 deletions.
2 changes: 2 additions & 0 deletions Middleware.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,10 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=depl/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Distro/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Embb/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Fuerte/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=imsi/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=kube/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Multus/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Noetic/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Replan/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Urllc/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: teleoperation
spec:
selector:
matchLabels:
app: teleoperation
replicas: 1
template:
metadata:
labels:
app: teleoperation
spec:
containers:
- name: teleoperation
resources: {}
image: alenrobots/5gera_teleop
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
apiVersion: v1\nkind: Service\nmetadata:\n name: teleoperation\nspec:\n selector:\n app: teleoperation\n type: LoadBalancer\n ports:\n - protocol: TCP\n port: 5896\n targetPort: 5896\n name: teleop\n \n
36 changes: 36 additions & 0 deletions docs/Administrator/ImportTaskTemplates/teleoperation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"Id": "6077c8c0-d354-487d-b81e-fe187826c6ec",
"Name": "Teleoperation task",
"TaskPriority": 1,
"ActionSequence": [
{
"Id": "6a1232e4-9d44-487e-b5b4-b46dc5878ca5",
"Name": "Teleoperation",
"Order": 1,
"ActionPriority": "Normal",
"ActionStatus": "None",
"MinimumRam": 0,
"MinimumNumCores": 0,
"Services": [
{
"Id": "26cf305a-e84c-4c40-aac2-f3a714bbd479",
"Name": "Teleoperation",
"IsReusable": false,
"MinimumRam": 512,
"MinimumNumCores": 2,
"ContainerImage": {
"Id": "cbb48148-1e61-4af9-b11e-a1b9dc8db23c",
"Name": "Teleoperation",
"Description": "The example network application onboarding for the webinar",
"K8SDeployment": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: teleoperation\nspec:\n selector:\n matchLabels:\n app: teleoperation\n replicas: 1\n template:\n metadata:\n labels:\n app: teleoperation\n spec:\n containers:\n - name: teleoperation\n resources: {}\n image: alenrobots/5gera_teleop \n",
"K8SService": "apiVersion: v1\nkind: Service\nmetadata:\n name: teleoperation\nspec:\n selector:\n app: teleoperation\n type: LoadBalancer\n ports:\n - protocol: TCP\n port: 5896\n targetPort: 5896\n name: teleop\n \n"
}
}
]
}
],
"Tags": [
"5G-ERA",
"teleoperation"
]
}
103 changes: 103 additions & 0 deletions src/Models/Domain/RosDistro.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
using Middleware.Models.Exceptions;

namespace Middleware.Models.Domain;

public enum RosVersion
{
Ros1 = 1,
Ros2 = 2
}

public struct RosDistro
{
public static RosDistro Electric { get; } = new("Electric", RosVersion.Ros1);
public static RosDistro Groovy { get; } = new("Groovy", RosVersion.Ros1);
public static RosDistro Fuerte { get; } = new("Fuerte", RosVersion.Ros1);
public static RosDistro Hydro { get; } = new("Hydro", RosVersion.Ros1);
public static RosDistro Indigo { get; } = new("Indigo", RosVersion.Ros1);
public static RosDistro Kinetic { get; } = new("Kinetic", RosVersion.Ros1);
public static RosDistro Lunar { get; } = new("Lunar", RosVersion.Ros1);
public static RosDistro Noetic { get; } = new("Noetic", RosVersion.Ros1);
public static RosDistro Ardent { get; } = new("Ardent", RosVersion.Ros2);
public static RosDistro Dashing { get; } = new("Dashing", RosVersion.Ros2);
public static RosDistro Bouncy { get; } = new("Bouncy", RosVersion.Ros2);
public static RosDistro Crystal { get; } = new("Crystal", RosVersion.Ros2);
public static RosDistro Humble { get; } = new("Humble", RosVersion.Ros2);
public static RosDistro Eloquent { get; } = new("Eloquent", RosVersion.Ros2);
public static RosDistro Melodic { get; } = new("Melodic", RosVersion.Ros2);
public static RosDistro Galactic { get; } = new("Galactic", RosVersion.Ros2);
public static RosDistro Foxy { get; } = new("Foxy", RosVersion.Ros2);

public RosDistro(string name, short rosVersion)
{
Name = name;
RosVersion = (RosVersion)rosVersion;
RosVersionInt = rosVersion;
}

public RosDistro(string name, RosVersion rosVersion)
{
Name = name;
RosVersion = rosVersion;
RosVersionInt = (short)rosVersion;
}

public string Name { get; }
public short RosVersionInt { get; set; }
public RosVersion RosVersion { get; set; }
}

public static class RosDistroHelper
{
private static readonly List<RosDistro> Distros = new()
{
RosDistro.Electric,
RosDistro.Groovy,
RosDistro.Fuerte,
RosDistro.Hydro,
RosDistro.Indigo,
RosDistro.Kinetic,
RosDistro.Lunar,
RosDistro.Noetic,
RosDistro.Ardent,
RosDistro.Dashing,
RosDistro.Crystal,
RosDistro.Humble,
RosDistro.Foxy,
RosDistro.Melodic,
RosDistro.Bouncy,
RosDistro.Eloquent,
RosDistro.Galactic
};

/// <summary>
/// Parses the name of the ROS distribution to return information about ros version
/// </summary>
/// <param name="name"></param>
/// <exception cref="IncorrectRosDistroNameException"></exception>
/// <returns></returns>
public static RosDistro FromName(string name)
{
var sanName = name.ToLower();
var distro = Distros.FirstOrDefault(d => d.Name.ToLower() == sanName);
return distro;
}

/// <summary>
/// Return all possible ROS distribution names
/// </summary>
/// <returns></returns>
public static IReadOnlyList<string> GetRosDistroNames()
{
return Distros.Select(d => d.Name).ToList();
}

/// <summary>
/// Return ROS distribution names for specified ROS version
/// </summary>
/// <returns></returns>
public static IReadOnlyList<string> GetRosDistroNamesByVersion(RosVersion rosVersion)
{
return Distros.Where(d => d.RosVersion == rosVersion).Select(d => d.Name).ToList();
}
}
22 changes: 0 additions & 22 deletions src/Models/Enums/RosDistro.cs

This file was deleted.

9 changes: 9 additions & 0 deletions src/Models/Exceptions/IncorrectRosDistroNameException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Middleware.Models.Exceptions;

[Serializable]
public class IncorrectRosDistroNameException : Exception
{
public IncorrectRosDistroNameException() : base("Cannot identify ROS distribution with a given name.")
{
}
}
65 changes: 31 additions & 34 deletions src/Orchestrator/Controllers/HealthController.cs
Original file line number Diff line number Diff line change
@@ -1,46 +1,43 @@
using System.Net;
using Microsoft.AspNetCore.Mvc;

namespace Middleware.Orchestrator.Controllers
namespace Middleware.Orchestrator.Controllers;

[Route("api/[controller]")]
[ApiController]
public class HealthController : ControllerBase
{
[Route("api/[controller]")]
[ApiController]
public class HealthController : ControllerBase
{
private readonly HttpClient _client;
private readonly HttpClient _client;

public HealthController(IHttpClientFactory factory)
{
_client = factory.CreateClient("healthCheckClient");
}
public HealthController(IHttpClientFactory factory)
{
_client = factory.CreateClient("healthCheckClient");
}

[HttpGet(Name="OrchestratorHealthCheck")]
[ProducesResponseType((int)HttpStatusCode.OK)]
public IActionResult Get()
{
return Ok();
}
[HttpGet(Name = "OrchestratorHealthCheck")]
[ProducesResponseType((int)HttpStatusCode.OK)]
public IActionResult Get()
{
return Ok();
}

[HttpGet]
[Route("spec", Name = "GetOrchestratorSpec")]
[ProducesResponseType(typeof(string), (int)HttpStatusCode.OK)]
public async Task<IActionResult> GetSpec()
{
string path = string.Empty;
[HttpGet]
[Route("spec", Name = "GetOrchestratorSpec")]
[ProducesResponseType(typeof(string), (int)HttpStatusCode.OK)]
public async Task<IActionResult> GetSpec()
{
var path = string.Empty;
#if DEBUG
var addresses = Environment.GetEnvironmentVariable("ASPNETCORE_URLS")?.Split(";");
if (addresses == null && Uri.IsWellFormedUriString(addresses[0], UriKind.RelativeOrAbsolute))
{
return NotFound();
}
var addresses = Environment.GetEnvironmentVariable("ASPNETCORE_URLS")?.Split(";");
if (addresses == null && Uri.IsWellFormedUriString(addresses![0], UriKind.RelativeOrAbsolute))
return NotFound();

_client.BaseAddress = new Uri(addresses[0]);
_client.BaseAddress = new(addresses[0]);

var bytes = await _client.GetByteArrayAsync("/swagger/v1/swagger.json");
path = Path.Combine(Directory.GetCurrentDirectory(), "OrchestratorSpec.json");
await System.IO.File.WriteAllBytesAsync(path, bytes);
var bytes = await _client.GetByteArrayAsync("/swagger/v1/swagger.json");
path = Path.Combine(Directory.GetCurrentDirectory(), "OrchestratorSpec.json");
await System.IO.File.WriteAllBytesAsync(path, bytes);
#endif
return Ok(path);
}
return Ok(path);
}
}
}
12 changes: 6 additions & 6 deletions src/Orchestrator/Controllers/OrchestrateController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,10 @@ public async Task<ActionResult<ActionPlanModel>> GetActionsByPlanId(Guid id)
[HttpPatch]
[Route("plan", Name = "UpdatePlan")]
[ProducesResponseType(typeof(TaskModel), (int)HttpStatusCode.OK)]
public async Task<IActionResult> UpdatePlan([FromBody] TaskModel task)
public Task<IActionResult> UpdatePlan([FromBody] TaskModel task)
{
//TODO: redeploy services for new plan
return Ok(task);
return Task.FromResult<IActionResult>(Ok(task));
}

/// <summary>
Expand All @@ -120,10 +120,10 @@ public async Task<IActionResult> UpdatePlan([FromBody] TaskModel task)
[Route("action/{id}", Name = "DeleteActionById")]
[ProducesResponseType((int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
public async Task<IActionResult> DeleteActionById(Guid id)
public Task<IActionResult> DeleteActionById(Guid id)
{
// TODO: Delete action with specified Id
return Ok();
return Task.FromResult<IActionResult>(Ok());
}

/// <summary>
Expand Down Expand Up @@ -234,10 +234,10 @@ public async Task<ActionResult> DeletePlanById(Guid id)
[HttpPost]
[Route("execute")]
[ProducesResponseType(typeof(List<InstanceModel>), (int)HttpStatusCode.OK)]
public async Task<IActionResult> InstantiateResources([FromBody] List<ActionModel> actions)
public Task<IActionResult> InstantiateResources([FromBody] List<ActionModel> actions)
{
//TODO: instantiate services for action
return Ok(new List<InstanceModel>());
return Task.FromResult<IActionResult>(Ok(new List<InstanceModel>()));
}

public record OrchestratorResourceInput(TaskModel Task, RobotModel Robot);
Expand Down
Loading

0 comments on commit 59be9a0

Please sign in to comment.