Initial commit

This commit is contained in:
2026-07-13 09:25:40 +07:00
parent c08ff54676
commit bccfb156d7
1938 changed files with 641646 additions and 0 deletions

View File

@@ -0,0 +1,170 @@
namespace RobotNet10.FleetManager.Script;
/// <summary>
/// Service interface for managing map layouts, nodes, and stations.
/// Provides methods to retrieve map elements (nodes, stations) and actions from the layout database.
/// </summary>
public interface ILayoutManager
{
/// <summary>
/// Retrieves a station from the specified map by its name.
/// </summary>
/// <param name="layout">The identifier of the map/layout. Cannot be null or empty.</param>
/// <param name="version">The version of the map. Cannot be null or empty.</param>
/// <param name="level">The level identifier within the map. Cannot be null or empty.</param>
/// <param name="name">The name of the station to retrieve. Cannot be null or empty.</param>
/// <returns>
/// A task that represents the asynchronous operation.
/// The task result contains the <see cref="IStation"/> matching the specified name within the given map,
/// or throws an exception if no such station exists.
/// </returns>
Task<IStation> GetStation(string layout, string version, string level, string name);
/// <summary>
/// Retrieves a node from the specified map by its name.
/// </summary>
/// <remarks>
/// This method performs an asynchronous operation to locate a node within the specified map.
/// Ensure that the map and name parameters are valid and non-empty before calling this method.
/// </remarks>
/// <param name="layout">The identifier of the map from which to retrieve the node. Cannot be null or empty.</param>
/// <param name="version">The version of the map. Cannot be null or empty.</param>
/// <param name="level">The level identifier within the map. Cannot be null or empty.</param>
/// <param name="name">The name of the node to retrieve. Cannot be null or empty.</param>
/// <returns>
/// A task that represents the asynchronous operation.
/// The task result contains the <see cref="INode"/> matching the specified name within the given map,
/// or throws an exception if no such node exists.
/// </returns>
Task<INode> GetNode(string layout, string version, string level, string name);
/// <summary>
/// Retrieves a VDA5050 action configuration for a specific element (node or station) in the map.
/// </summary>
/// <param name="layout">The identifier of the map/layout. Cannot be null or empty.</param>
/// <param name="version">The version of the map. Cannot be null or empty.</param>
/// <param name="level">The level identifier within the map. Cannot be null or empty.</param>
/// <param name="name">The name of the element (node or station) for which to retrieve the action. Cannot be null or empty.</param>
/// <param name="robotId">The identifier of the robot that will execute the action. Used for robot-specific action configuration. Cannot be null or empty.</param>
/// <returns>
/// A task that represents the asynchronous operation.
/// The task result contains the VDA5050 <see cref="RobotNet.VDA5050.InstantAction.Action"/> configured for the specified element and robot,
/// or throws an exception if no such action exists.
/// </returns>
Task<RobotNet.VDA5050.InstantAction.Action> GetAction(string layout, string version, string level, string name, string robotId);
}
/// <summary>
/// Represents a node (waypoint) in the map layout.
/// Nodes define points where robots can navigate to or pass through.
/// Conforms to VDMA LIF (Logistics Interface Format) standard.
/// </summary>
public interface INode
{
/// <summary>
/// Gets or sets the unique identifier of the node.
/// </summary>
public Guid Id { get; set; }
/// <summary>
/// Gets or sets the parent map identifier that contains this node.
/// </summary>
public Guid MapId { get; set; }
/// <summary>
/// Gets or sets the node identifier (VDMA LIF: nodeId).
/// This is a required field and must be unique within the level.
/// </summary>
public string NodeId { get; set; }
/// <summary>
/// Gets or sets the node name (VDMA LIF: nodeName).
/// This is an optional human-readable name for the node.
/// </summary>
public string? NodeName { get; set; }
/// <summary>
/// Gets or sets the node description (VDMA LIF: nodeDescription).
/// This is an optional description providing additional information about the node.
/// </summary>
public string? NodeDescription { get; set; }
/// <summary>
/// Gets or sets the X coordinate of the node position in meters (VDMA LIF: nodePosition.x).
/// This is a required field.
/// </summary>
public double X { get; set; }
/// <summary>
/// Gets or sets the Y coordinate of the node position in meters (VDMA LIF: nodePosition.y).
/// This is a required field.
/// </summary>
public double Y { get; set; }
}
/// <summary>
/// Represents a station (workstation or loading/unloading point) in the map layout.
/// Stations are locations where robots can perform pick or drop operations.
/// Conforms to VDMA LIF (Logistics Interface Format) standard.
/// </summary>
public interface IStation
{
/// <summary>
/// Gets the unique identifier of the station.
/// </summary>
Guid Id { get; }
/// <summary>
/// Gets the identifier of the map that contains this station.
/// </summary>
Guid MapId { get; }
/// <summary>
/// Gets the identifiers of the nodes that this station is linked to.
/// A station can be associated with one or more nodes for navigation purposes.
/// </summary>
Guid[] NodeId { get; }
/// <summary>
/// Gets the station identifier (VDMA LIF: stationId).
/// This is a required field and must be unique within the level.
/// </summary>
public string StationId { get; }
/// <summary>
/// Gets the station name (VDMA LIF: stationName).
/// This is an optional human-readable name for the station.
/// </summary>
public string? StationName { get; }
/// <summary>
/// Gets the station description (VDMA LIF: stationDescription).
/// This is an optional description providing additional information about the station.
/// </summary>
public string? StationDescription { get; }
/// <summary>
/// Gets the station height in meters (VDMA LIF: stationHeight).
/// This is an optional field indicating the height of the station platform.
/// </summary>
public double? StationHeight { get; }
/// <summary>
/// Gets the X coordinate of the station position in meters (VDMA LIF: stationPosition.x).
/// This is a required field.
/// </summary>
public double X { get; }
/// <summary>
/// Gets the Y coordinate of the station position in meters (VDMA LIF: stationPosition.y).
/// This is a required field.
/// </summary>
public double Y { get; }
/// <summary>
/// Gets the theta orientation angle in radians (VDMA LIF: stationPosition.theta).
/// This is an optional field indicating the orientation of the station.
/// Range: [-Pi ... Pi]
/// </summary>
public double? Theta { get; }
}

View File

@@ -0,0 +1,109 @@
namespace RobotNet10.FleetManager.Script;
/// <summary>
/// Defines the action types that can be performed at a station.
/// </summary>
public enum StationAction
{
/// <summary>
/// Pick up a load from the station.
/// </summary>
Pick,
/// <summary>
/// Drop off a load at the station.
/// </summary>
Drop,
/// <summary>
/// No action - robot moves to station without performing any load operation.
/// </summary>
None
}
/// <summary>
/// Interface for controlling an Autonomous Mobile Robot (AMR).
/// Provides methods to move the robot, execute actions, and query its current state.
/// </summary>
public interface IRobot
{
/// <summary>
/// Gets the unique identifier of the robot (serial number or unique identifier).
/// </summary>
string RobotId { get; }
/// <summary>
/// Gets the display name of the robot.
/// </summary>
string Name { get; }
/// <summary>
/// Gets the robot model identifier.
/// </summary>
Guid ModelId { get; }
/// <summary>
/// Gets the map identifier where the robot is currently operating, or <see langword="null"/> if not assigned to a map.
/// </summary>
Guid? MapId { get; }
/// <summary>
/// Gets the current state of the robot, including position, battery, loads, and operational status.
/// </summary>
RobotState State { get; }
/// <summary>
/// Moves the robot to a target node on the map without performing any end action.
/// </summary>
/// <param name="nodeName">The name of the target node. Cannot be null or empty.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>
/// A task that represents the asynchronous operation.
/// The task result contains a <see cref="RobotResult"/> indicating success or failure of the movement command.
/// </returns>
Task<RobotResult> MoveToNode(string nodeName, CancellationToken cancellationToken);
/// <summary>
/// Moves the robot to a target node with a specific orientation at the endpoint.
/// </summary>
/// <param name="nodeName">The name of the target node. Cannot be null or empty.</param>
/// <param name="lastAngle">The required orientation angle in radians at the endpoint. Range: [-Pi ... Pi].</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>
/// A task that represents the asynchronous operation.
/// The task result contains a <see cref="RobotResult"/> indicating success or failure of the movement command.
/// </returns>
Task<RobotResult> MoveToNode(string nodeName, double lastAngle, CancellationToken cancellationToken);
/// <summary>
/// Moves the robot to a target station node and executes the specified action (pick, drop, or none).
/// </summary>
/// <param name="nodeName">The name of the target station node. Cannot be null or empty.</param>
/// <param name="action">The action to perform at the station: <see cref="StationAction.Pick"/>, <see cref="StationAction.Drop"/>, or <see cref="StationAction.None"/>.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>
/// A task that represents the asynchronous operation.
/// The task result contains a <see cref="RobotResult"/> indicating success or failure of the movement and action execution.
/// </returns>
Task<RobotResult> MoveToStation(string nodeName, StationAction action, CancellationToken cancellationToken);
/// <summary>
/// Aborts or cancels the ongoing robot movement action, if one exists.
/// </summary>
/// <returns>
/// A task that represents the asynchronous operation.
/// </returns>
Task AbortMovement();
/// <summary>
/// Immediately executes an instant action on the robot, bypassing any waiting period.
/// Instant actions are executed immediately without requiring the robot to be at a specific location.
/// </summary>
/// <param name="action">The VDA5050 instant action to execute. Cannot be null.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>
/// A task that represents the asynchronous operation.
/// The task result contains a <see cref="RobotResult"/> indicating success or failure of the action execution.
/// </returns>
Task<RobotResult> Execute(RobotNet.VDA5050.InstantAction.Action action, CancellationToken cancellationToken);
}

View File

@@ -0,0 +1,73 @@
using System.Linq.Expressions;
namespace RobotNet10.FleetManager.Script;
/// <summary>
/// Robot management service interface for FleetManager scripts.
/// Provides methods to retrieve, query, and manage robots in the fleet.
/// </summary>
public interface IRobotManager
{
/// <summary>
/// Retrieves a robot controller by its unique identifier.
/// </summary>
/// <param name="robotId">The unique identifier of the robot. Cannot be null or empty.</param>
/// <returns>
/// A task that represents the asynchronous operation.
/// The task result contains the <see cref="IRobot"/> instance if found, or <see langword="null"/> if the robot does not exist or is not available.
/// </returns>
Task<IRobot?> GetRobotById(string robotId);
/// <summary>
/// Gets the current state of a robot by its identifier.
/// </summary>
/// <param name="robotId">The unique identifier of the robot. Cannot be null or empty.</param>
/// <returns>
/// A task that represents the asynchronous operation.
/// The task result contains the <see cref="RobotState"/> if the robot is found and connected, or <see langword="null"/> otherwise.
/// </returns>
Task<RobotState?> GetRobotState(string robotId);
/// <summary>
/// Searches for robots on a specific map by layout, version, level, and model.
/// </summary>
/// <param name="layout">The identifier of the map/layout. Cannot be null or empty.</param>
/// <param name="version">The version of the map. Cannot be null or empty.</param>
/// <param name="level">The level identifier within the map. Cannot be null or empty.</param>
/// <param name="model">The robot model identifier to filter by. Cannot be null or empty.</param>
/// <returns>
/// A task that represents the asynchronous operation.
/// The task result contains a collection of robot IDs that match the specified criteria.
/// </returns>
Task<IEnumerable<string>> SearchRobots(string layout, string version, string level, string model);
/// <summary>
/// Searches for robots on a specific map with additional state-based filtering conditions.
/// </summary>
/// <param name="layout">The identifier of the map/layout. Cannot be null or empty.</param>
/// <param name="version">The version of the map. Cannot be null or empty.</param>
/// <param name="level">The level identifier within the map. Cannot be null or empty.</param>
/// <param name="model">The robot model identifier to filter by. Cannot be null or empty.</param>
/// <param name="expr">A lambda expression that defines additional filtering conditions based on <see cref="RobotState"/>.</param>
/// <returns>
/// A task that represents the asynchronous operation.
/// The task result contains a collection of robot IDs that match all specified criteria including the state filter.
/// </returns>
/// <example>
/// <code>
/// // Find all ready robots with battery voltage above 24V
/// var robots = await RobotManager.SearchRobots("layout1", "v1", "level1", "model1", tate => state.IsReady, state.Voltage > 24.0);
/// </code>
/// </example>
Task<IEnumerable<string>> SearchRobots(string layout, string version, string level, string model, Expression<Func<RobotState, bool>> expr);
/// <summary>
/// Gets the current order status of a robot.
/// </summary>
/// <param name="robotId">The unique identifier of the robot. Cannot be null or empty.</param>
/// <returns>
/// A task that represents the asynchronous operation.
/// The task result contains the <see cref="RobotOrderStatus"/> indicating the current order processing state of the robot.
/// </returns>
Task<RobotOrderStatus> GetRobotOrderStatus(string robotId);
}

View File

@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\RobotNet.VDA5050\RobotNet.VDA5050.csproj" />
<ProjectReference Include="..\..\Shared\RobotNet10.Shared\RobotNet10.Shared.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,32 @@
namespace RobotNet10.FleetManager.Script;
/// <summary>
/// Represents the current order processing status of a robot.
/// </summary>
public enum RobotOrderStatus
{
/// <summary>
/// The robot's current order has encountered an error and cannot be completed.
/// </summary>
IsError,
/// <summary>
/// The robot's current order has been successfully completed.
/// </summary>
IsCompleted,
/// <summary>
/// The robot is currently processing an order.
/// </summary>
IsProccessing,
/// <summary>
/// The robot's current order has been canceled.
/// </summary>
IsCanceled,
/// <summary>
/// The robot has no active order (order queue is empty).
/// </summary>
Empty
}

View File

@@ -0,0 +1,9 @@
namespace RobotNet10.FleetManager.Script;
/// <summary>
/// Represents the result of a robot operation, including success status and a descriptive message.
/// </summary>
/// <param name="IsSuccess">Indicates whether the operation completed successfully. <see langword="true"/> if successful; otherwise, <see langword="false"/>.</param>
/// <param name="Message">A descriptive message providing details about the operation result. May contain error information if the operation failed.</param>
public record RobotResult(bool IsSuccess, string Message);

View File

@@ -0,0 +1,15 @@
using RobotNet.VDA5050.State;
namespace RobotNet10.FleetManager.Script;
/// <summary>
/// Represents the current state of a robot, including position, operational status, battery information, and load status.
/// </summary>
/// <param name="IsReady">Indicates whether the robot is ready to accept new commands. <see langword="true"/> if ready; otherwise, <see langword="false"/>.</param>
/// <param name="Voltage">The current battery voltage in volts.</param>
/// <param name="Loads">An array of loads currently carried by the robot. Empty array if no loads are present.</param>
/// <param name="IsCharging">Indicates whether the robot is currently charging. <see langword="true"/> if charging; otherwise, <see langword="false"/>.</param>
/// <param name="X">The X coordinate of the robot's current position in meters.</param>
/// <param name="Y">The Y coordinate of the robot's current position in meters.</param>
/// <param name="Theta">The orientation angle of the robot in radians. Range: [-Pi ... Pi].</param>
public record RobotState(bool IsReady, double Voltage, Load[] Loads, bool IsCharging, double X, double Y, double Theta);