This commit is contained in:
Đăng Nguyễn 2025-12-20 15:16:59 +07:00
parent dd8c17cb6c
commit 6cd32f8c98
18 changed files with 298 additions and 251 deletions

View File

@ -70,7 +70,7 @@
public NavModel[] Navs = [
new(){Icon = "mdi-view-dashboard", Path="/", Label = "Dashboard", Match = NavLinkMatch.All},
new(){Icon = "mdi-map-legend", Path="/maps-manager", Label = "Mapping", Match = NavLinkMatch.All},
// new(){Icon = "mdi-map-legend", Path="/maps-manager", Label = "Mapping", Match = NavLinkMatch.All},
new(){Icon = "mdi-application-cog", Path="/robot-config", Label = "Config", Match = NavLinkMatch.All},
];

View File

@ -5,7 +5,7 @@
<DataAnnotationsValidator />
<div class="form-check mb-2">
<InputCheckbox class="form-check-input" @bind-Value="Model.EnableSimulation" />
<InputCheckbox class="form-check-input" Value="Model.EnableSimulation" />
<label class="form-check-label">Enable Simulation</label>
<ValidationMessage For="@(() => Model.EnableSimulation)" />
</div>

View File

@ -16,7 +16,7 @@
<label class="rcm-label" for="configType">Config Type</label>
<div class="rcm-select-wrapper">
<select id="configType" class="form-select rcm-select" value="@SelectedType" @onchange="OnTypeChanged">
@foreach (var type in Enum.GetValues<RobotConfigType>())
@foreach (var type in GetConfigType)
{
<option value="@type">@type</option>
}
@ -31,9 +31,9 @@
<div class="rcm-toolbar-right">
<div class="rcm-action-group">
<button type="button" class="btn rcm-icon-btn" data-tooltip="Add config" aria-label="Add" @onclick="OpenAddConfig">
@* <button type="button" class="btn rcm-icon-btn" data-tooltip="Add config" aria-label="Add" @onclick="OpenAddConfig">
<i class="mdi mdi-plus" aria-hidden="true"></i>
</button>
</button> *@
<button type="button" class="btn rcm-icon-btn" data-tooltip="Update config" aria-label="Update" @onclick="SaveConfig">
<i class="mdi mdi-content-save" aria-hidden="true"></i>
@ -43,9 +43,9 @@
<i class="mdi mdi-file-download" aria-hidden="true"></i>
</button>
<button type="button" class="btn rcm-icon-btn rcm-danger" data-tooltip="Delete config" aria-label="Delete" @onclick="DeleteConfig">
@* <button type="button" class="btn rcm-icon-btn rcm-danger" data-tooltip="Delete config" aria-label="Delete" @onclick="DeleteConfig">
<i class="mdi mdi-delete" aria-hidden="true"></i>
</button>
</button> *@
</div>
</div>
</div>
@ -227,6 +227,7 @@
private AddFormModel addForm = new();
private string SelectedTemplateIdString = string.Empty;
private IEnumerable<RobotConfigType> GetConfigType = [RobotConfigType.VDA5050, RobotConfigType.Simulation];
private IEnumerable<(Guid Id, string Name, bool Active)> GetTemplatesForSelectedType()
{

View File

@ -10,24 +10,24 @@ public enum ActionType
stateRequest,
factsheetRequest,
logReport,
//logReport,
pick,
drop,
detectObject,
finePositioning,
waitForTrigger,
//detectObject,
//finePositioning,
//waitForTrigger,
cancelOrder,
liftUp,
liftDown,
liftRotate,
rotate,
rotateKeepLift,
mutedBaseOn,
mutedBaseOff,
mutedLoadOn,
mutedLoadOff,
dockTo,
moveStraightToCoor,
moveStraightWithDistance,
//liftUp,
//liftDown,
//liftRotate,
//rotate,
//rotateKeepLift,
//mutedBaseOn,
//mutedBaseOff,
//mutedLoadOn,
//mutedLoadOff,
//dockTo,
//moveStraightToCoor,
//moveStraightWithDistance,
}

View File

@ -850,7 +850,8 @@ public class RobotConfigsController(Services.Logger<RobotConfigsController> Logg
{
try
{
//await RobotConfiguration.LoadVDA5050ConfigAsync();
await RobotConfiguration.LoadVDA5050ConfigAsync();
await RobotConfiguration.LoadRobotSimulationConfigAsync();
return new(true, "Robot configuration loaded successfully.");
}
catch (Exception ex)

View File

@ -4,6 +4,8 @@ public class RobotDockToAction(IServiceProvider ServiceProvider) : RobotAction(S
{
protected override Task StartAction()
{
Status = VDA5050.State.ActionStatus.FINISHED;
ResultDescription = AgvAction is null ? ResultDescription : AgvAction.ResultDescription;
return base.StartAction();
}

View File

@ -10,6 +10,7 @@ public class RobotFactsheetRequestAction(IServiceProvider ServiceProvider) : Rob
var RobotFactsheet = Scope.ServiceProvider.GetRequiredService<RobotFactsheet>();
await RobotFactsheet.PubFactsheet();
Status = VDA5050.State.ActionStatus.FINISHED;
ResultDescription = AgvAction is null ? ResultDescription : AgvAction.ResultDescription;
}
protected override Task ExecuteAction()

View File

@ -4,6 +4,8 @@ public class RobotMoveStraightToCoorAction(IServiceProvider ServiceProvider) : R
{
protected override Task StartAction()
{
Status = VDA5050.State.ActionStatus.FINISHED;
ResultDescription = AgvAction is null ? ResultDescription : AgvAction.ResultDescription;
return base.StartAction();
}

View File

@ -4,6 +4,8 @@ public class RobotMoveStraightWithDistanceAction(IServiceProvider ServiceProvide
{
protected override Task StartAction()
{
Status = VDA5050.State.ActionStatus.FINISHED;
ResultDescription = AgvAction is null ? ResultDescription : AgvAction.ResultDescription;
return base.StartAction();
}

View File

@ -16,20 +16,20 @@ public class RobotActionStorage(IServiceProvider ServiceProvider)
ActionType.stateRequest => new RobotStateRequestAction(ServiceProvider),
ActionType.factsheetRequest => new RobotFactsheetRequestAction(ServiceProvider),
ActionType.cancelOrder => new RobotCancelOrderAction(ServiceProvider),
ActionType.liftUp => new RobotLiftUpAction(ServiceProvider),
ActionType.liftDown => new RobotLiftDownAction(ServiceProvider),
//ActionType.liftUp => new RobotLiftUpAction(ServiceProvider),
//ActionType.liftDown => new RobotLiftDownAction(ServiceProvider),
ActionType.drop => new RobotDropAction(ServiceProvider),
ActionType.pick => new RobotPickAction(ServiceProvider),
ActionType.liftRotate => new RobotLiftRotateAction(ServiceProvider),
ActionType.rotate => new RobotRotateAction(ServiceProvider),
ActionType.rotateKeepLift => new RobotRotateKeepLift(ServiceProvider),
ActionType.mutedBaseOn => new RobotMutedBaseOnAction(ServiceProvider),
ActionType.mutedBaseOff => new RobotMutedBaseOffAction(ServiceProvider),
ActionType.mutedLoadOn => new RobotMutedLoadOnAction(ServiceProvider),
ActionType.mutedLoadOff => new RobotMutedLoadOffAction(ServiceProvider),
ActionType.dockTo => new RobotDockToAction(ServiceProvider),
ActionType.moveStraightToCoor => new RobotMoveStraightToCoorAction(ServiceProvider),
ActionType.moveStraightWithDistance => new RobotMoveStraightWithDistanceAction(ServiceProvider),
//ActionType.liftRotate => new RobotLiftRotateAction(ServiceProvider),
//ActionType.rotate => new RobotRotateAction(ServiceProvider),
//ActionType.rotateKeepLift => new RobotRotateKeepLift(ServiceProvider),
//ActionType.mutedBaseOn => new RobotMutedBaseOnAction(ServiceProvider),
//ActionType.mutedBaseOff => new RobotMutedBaseOffAction(ServiceProvider),
//ActionType.mutedLoadOn => new RobotMutedLoadOnAction(ServiceProvider),
//ActionType.mutedLoadOff => new RobotMutedLoadOffAction(ServiceProvider),
//ActionType.dockTo => new RobotDockToAction(ServiceProvider),
//ActionType.moveStraightToCoor => new RobotMoveStraightToCoorAction(ServiceProvider),
//ActionType.moveStraightWithDistance => new RobotMoveStraightWithDistanceAction(ServiceProvider),
_ => null,
};
}

View File

@ -54,6 +54,12 @@ public class RobotConfiguration(IServiceProvider ServiceProvider, Logger<RobotCo
VDA5050Setting.CerFile = config.VDA5050Cer;
VDA5050Setting.KeyFile = config.VDA5050Key;
SerialNumber = config.SerialNumber;
if (IsReady)
{
var robotConnection = scope.ServiceProvider.GetRequiredService<RobotConnection>();
await robotConnection.StopConnection();
_ = Task.Run(async () => await robotConnection.StartConnection(CancellationToken.None));
}
}
else throw new Exception("Chưa có cấu hình VDA5050.");
}

View File

@ -65,6 +65,10 @@ public class RobotConnection(RobotConfiguration RobotConfiguration,
public async Task StopConnection()
{
if (MqttClient is not null) await MqttClient.DisposeAsync();
if (MqttClient is not null)
{
await MqttClient.DisposeAsync();
MqttClient = null;
}
}
}

View File

@ -40,13 +40,6 @@ public partial class RobotController(IOrder OrderManager,
try
{
if (StateManager.RootStateName != RootStateType.Auto.ToString()) throw new OrderException(RobotErrors.Error1013(StateManager.RootStateName));
//if (OrderManager.NodeStates.Length > 0)
//{
// if (ActionManager.HasActionRunning) throw new OrderException(RobotErrors.Error1007());
// if (ErrorManager.HasFatalError) throw new OrderException(RobotErrors.Error1008());
// if (NavigationManager.Driving) throw new OrderException(RobotErrors.Error1009());
//}
//else if (order.OrderId != OrderManager.OrderId) throw new OrderException(RobotErrors.Error1001(OrderManager.OrderId, order.OrderId));
OrderManager.UpdateOrder(order);
}
catch (RobotExeption orEx)

View File

@ -99,6 +99,13 @@ public class RobotErrors : IError
=> CreateError(ErrorType.INITIALIZE_ORDER, "1014", ErrorLevel.WARNING, $"Edge {edgeId} chứa StartNodeId {nodeId} không tồn tại trong Nodes");
public static Error Error1015(string edgeId, string nodeId)
=> CreateError(ErrorType.INITIALIZE_ORDER, "1015", ErrorLevel.WARNING, $"Edge {edgeId} chứa {nodeId} không tồn tại trong Nodes");
public static Error Error1016(string lastNodeId, string newStartNodeId)
=> CreateError(ErrorType.INITIALIZE_ORDER, "Vui lòng kiểm tra lại order", ErrorLevel.WARNING, $"Order mới nhận được không phải là nối tiếp của order khi lastNodeId: {lastNodeId} mà node đầu tiên của order mới là: {newStartNodeId}");
public static Error Error1017(int lastNodeSequenceId, int newStartNodeSequenceId)
=> CreateError(ErrorType.INITIALIZE_ORDER, "Vui lòng kiểm tra lại order", ErrorLevel.WARNING, $"Order mới nhận được không phải là nối tiếp của order khi LastNodeSequenceId: {lastNodeSequenceId} mà node đầu tiên của order mới có sequence: {newStartNodeSequenceId}");
public static Error Error1018(int oldOrderUpdateId, int newOrderUpdateId)
=> CreateError(ErrorType.INITIALIZE_ORDER, "Vui lòng kiểm tra lại OrderUpdateId", ErrorLevel.WARNING, $"OrderUpdateId {newOrderUpdateId} nhận được nhỏ hơn OrderUpdateId hiện tại là {oldOrderUpdateId}");
public static Error Error2001()
=> CreateError(ErrorType.READ_PERIPHERAL_FAILURE, "2001", ErrorLevel.FATAL, "Có lỗi xảy ra trong quá trình đọc tín hiệu từ hệ thống ngoại vi(PLC)");

View File

@ -20,20 +20,20 @@ public class RobotFactsheet(RobotConnection RobotConnection, RobotConfiguration
{ ActionType.stateRequest, StateRequest},
{ ActionType.factsheetRequest, FactsheetRequest},
{ ActionType.cancelOrder, CancelOrder},
{ ActionType.liftUp, LiftUp},
{ ActionType.liftDown, LiftDown},
//{ ActionType.liftUp, LiftUp},
//{ ActionType.liftDown, LiftDown},
{ ActionType.pick, Pick},
{ ActionType.drop, Drop},
{ ActionType.liftRotate, LiftRotate},
{ ActionType.rotate, Rotate},
{ ActionType.rotateKeepLift, RotateKeepLift},
{ ActionType.mutedBaseOn, MutedBaseOn},
{ ActionType.mutedBaseOff, MutedBaseOff},
{ ActionType.mutedLoadOn, MutedLoadOn},
{ ActionType.mutedLoadOff, MutedLoadOff},
{ ActionType.dockTo, DockTo},
{ ActionType.moveStraightToCoor, MoveStraightToCoor},
{ ActionType.moveStraightWithDistance, MoveStraightWithDistance},
//{ ActionType.liftRotate, LiftRotate},
//{ ActionType.rotate, Rotate},
//{ ActionType.rotateKeepLift, RotateKeepLift},
//{ ActionType.mutedBaseOn, MutedBaseOn},
//{ ActionType.mutedBaseOff, MutedBaseOff},
//{ ActionType.mutedLoadOn, MutedLoadOn},
//{ ActionType.mutedLoadOff, MutedLoadOff},
//{ ActionType.dockTo, DockTo},
//{ ActionType.moveStraightToCoor, MoveStraightToCoor},
//{ ActionType.moveStraightWithDistance, MoveStraightWithDistance},
};
public AgvAction? GetAction(ActionType actionType) => AgvActions.TryGetValue(actionType, out AgvAction? value) && value is not null ? value : null;
@ -167,25 +167,25 @@ public class RobotFactsheet(RobotConnection RobotConnection, RobotConfiguration
BlockingTypes = [BlockingType.NONE.ToString()],
};
public readonly static AgvAction LiftUp = new()
{
ActionType = ActionType.liftUp.ToString(),
ActionDescription = "Nâng cao bàn nâng của robot.",
ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
ActionParameters = [],
ResultDescription = "Robot đã nâng cao bàn nâng.",
BlockingTypes = [BlockingType.HARD.ToString()],
};
//public readonly static AgvAction LiftUp = new()
//{
// ActionType = ActionType.liftUp.ToString(),
// ActionDescription = "Nâng cao bàn nâng của robot.",
// ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
// ActionParameters = [],
// ResultDescription = "Robot đã nâng cao bàn nâng.",
// BlockingTypes = [BlockingType.HARD.ToString()],
//};
public readonly static AgvAction LiftDown = new()
{
ActionType = ActionType.liftDown.ToString(),
ActionDescription = "Hạ thấp bàn nâng của robot.",
ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
ActionParameters = [],
ResultDescription = "Robot đã hạ thấp bàn nâng.",
BlockingTypes = [BlockingType.HARD.ToString()],
};
//public readonly static AgvAction LiftDown = new()
//{
// ActionType = ActionType.liftDown.ToString(),
// ActionDescription = "Hạ thấp bàn nâng của robot.",
// ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
// ActionParameters = [],
// ResultDescription = "Robot đã hạ thấp bàn nâng.",
// BlockingTypes = [BlockingType.HARD.ToString()],
//};
public readonly static AgvAction Pick = new()
{
@ -207,166 +207,166 @@ public class RobotFactsheet(RobotConnection RobotConnection, RobotConfiguration
BlockingTypes = [BlockingType.HARD.ToString()],
};
public readonly static AgvAction LiftRotate = new()
{
ActionType = ActionType.liftRotate.ToString(),
ActionDescription = "Xoay bàn nâng của robot.",
ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
ActionParameters = [
new()
{
Key = "angle",
Description = "Góc xoay của bàn nâng. (rad)",
ValueDataType = ValueDataType.FLOAT.ToString(),
IsOptional = false,
}],
ResultDescription = "Robot đã xoay bàn nâng.",
BlockingTypes = [BlockingType.HARD.ToString()],
};
//public readonly static AgvAction LiftRotate = new()
//{
// ActionType = ActionType.liftRotate.ToString(),
// ActionDescription = "Xoay bàn nâng của robot.",
// ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
// ActionParameters = [
// new()
// {
// Key = "angle",
// Description = "Góc xoay của bàn nâng. (rad)",
// ValueDataType = ValueDataType.FLOAT.ToString(),
// IsOptional = false,
// }],
// ResultDescription = "Robot đã xoay bàn nâng.",
// BlockingTypes = [BlockingType.HARD.ToString()],
//};
public readonly static AgvAction Rotate = new()
{
ActionType = ActionType.rotate.ToString(),
ActionDescription = "Xoay robot tại chỗ.",
ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
ActionParameters = [
new()
{
Key = "angle",
Description = "Góc xoay của robot. (rad)",
ValueDataType = ValueDataType.FLOAT.ToString(),
IsOptional = false,
}],
ResultDescription = "Robot đã xoay tại chỗ.",
BlockingTypes = [BlockingType.HARD.ToString()],
};
//public readonly static AgvAction Rotate = new()
//{
// ActionType = ActionType.rotate.ToString(),
// ActionDescription = "Xoay robot tại chỗ.",
// ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
// ActionParameters = [
// new()
// {
// Key = "angle",
// Description = "Góc xoay của robot. (rad)",
// ValueDataType = ValueDataType.FLOAT.ToString(),
// IsOptional = false,
// }],
// ResultDescription = "Robot đã xoay tại chỗ.",
// BlockingTypes = [BlockingType.HARD.ToString()],
//};
public readonly static AgvAction RotateKeepLift = new()
{
ActionType = ActionType.rotateKeepLift.ToString(),
ActionDescription = "Xoay robot tại chỗ giữ nguyên trạng thái bàn nâng.",
ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
ActionParameters = [
new()
{
Key = "angle",
Description = "Góc xoay của robot. (rad)",
ValueDataType = ValueDataType.FLOAT.ToString(),
IsOptional = false,
}],
ResultDescription = "Robot đã xoay tại chỗ giữ nguyên trạng thái bàn nâng.",
BlockingTypes = [BlockingType.HARD.ToString()],
};
//public readonly static AgvAction RotateKeepLift = new()
//{
// ActionType = ActionType.rotateKeepLift.ToString(),
// ActionDescription = "Xoay robot tại chỗ giữ nguyên trạng thái bàn nâng.",
// ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
// ActionParameters = [
// new()
// {
// Key = "angle",
// Description = "Góc xoay của robot. (rad)",
// ValueDataType = ValueDataType.FLOAT.ToString(),
// IsOptional = false,
// }],
// ResultDescription = "Robot đã xoay tại chỗ giữ nguyên trạng thái bàn nâng.",
// BlockingTypes = [BlockingType.HARD.ToString()],
//};
public readonly static AgvAction MutedBaseOn = new()
{
ActionType = ActionType.mutedBaseOn.ToString(),
ActionDescription = "Bật chế độ muted base robot.",
ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
ActionParameters = [],
ResultDescription = "Robot đã bật chế độ muted base.",
BlockingTypes = [BlockingType.NONE.ToString(), BlockingType.SOFT.ToString(), BlockingType.HARD.ToString()],
};
//public readonly static AgvAction MutedBaseOn = new()
//{
// ActionType = ActionType.mutedBaseOn.ToString(),
// ActionDescription = "Bật chế độ muted base robot.",
// ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
// ActionParameters = [],
// ResultDescription = "Robot đã bật chế độ muted base.",
// BlockingTypes = [BlockingType.NONE.ToString(), BlockingType.SOFT.ToString(), BlockingType.HARD.ToString()],
//};
public readonly static AgvAction MutedBaseOff = new()
{
ActionType = ActionType.mutedBaseOff.ToString(),
ActionDescription = "Tắt chế độ muted base robot.",
ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
ActionParameters = [],
ResultDescription = "Robot đã tắt chế độ muted base.",
BlockingTypes = [BlockingType.NONE.ToString(), BlockingType.SOFT.ToString(), BlockingType.HARD.ToString()],
};
//public readonly static AgvAction MutedBaseOff = new()
//{
// ActionType = ActionType.mutedBaseOff.ToString(),
// ActionDescription = "Tắt chế độ muted base robot.",
// ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
// ActionParameters = [],
// ResultDescription = "Robot đã tắt chế độ muted base.",
// BlockingTypes = [BlockingType.NONE.ToString(), BlockingType.SOFT.ToString(), BlockingType.HARD.ToString()],
//};
public readonly static AgvAction MutedLoadOn = new()
{
ActionType = ActionType.mutedLoadOn.ToString(),
ActionDescription = "Bật chế độ muted load robot.",
ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
ActionParameters = [],
ResultDescription = "Robot đã bật chế độ muted load.",
BlockingTypes = [BlockingType.NONE.ToString(), BlockingType.SOFT.ToString(), BlockingType.HARD.ToString()],
};
//public readonly static AgvAction MutedLoadOn = new()
//{
// ActionType = ActionType.mutedLoadOn.ToString(),
// ActionDescription = "Bật chế độ muted load robot.",
// ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
// ActionParameters = [],
// ResultDescription = "Robot đã bật chế độ muted load.",
// BlockingTypes = [BlockingType.NONE.ToString(), BlockingType.SOFT.ToString(), BlockingType.HARD.ToString()],
//};
public readonly static AgvAction MutedLoadOff = new()
{
ActionType = ActionType.mutedLoadOff.ToString(),
ActionDescription = "Tắt chế độ muted load robot.",
ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
ActionParameters = [],
ResultDescription = "Robot đã tắt chế độ muted load.",
BlockingTypes = [BlockingType.NONE.ToString(), BlockingType.SOFT.ToString(), BlockingType.HARD.ToString()],
};
//public readonly static AgvAction MutedLoadOff = new()
//{
// ActionType = ActionType.mutedLoadOff.ToString(),
// ActionDescription = "Tắt chế độ muted load robot.",
// ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
// ActionParameters = [],
// ResultDescription = "Robot đã tắt chế độ muted load.",
// BlockingTypes = [BlockingType.NONE.ToString(), BlockingType.SOFT.ToString(), BlockingType.HARD.ToString()],
//};
public readonly static AgvAction DockTo = new()
{
ActionType = ActionType.dockTo.ToString(),
ActionDescription = "Robot di chuyển vào vị trí đặc biết",
ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
ActionParameters = [
new()
{
Key = "dockId",
Description = "ID của vị trí dock.",
ValueDataType = ValueDataType.STRING.ToString(),
IsOptional = false,
}],
ResultDescription = "Robot đã dock đến vị trí sạc hoặc bến đỗ.",
BlockingTypes = [BlockingType.HARD.ToString()],
};
//public readonly static AgvAction DockTo = new()
//{
// ActionType = ActionType.dockTo.ToString(),
// ActionDescription = "Robot di chuyển vào vị trí đặc biết",
// ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
// ActionParameters = [
// new()
// {
// Key = "dockId",
// Description = "ID của vị trí dock.",
// ValueDataType = ValueDataType.STRING.ToString(),
// IsOptional = false,
// }],
// ResultDescription = "Robot đã dock đến vị trí sạc hoặc bến đỗ.",
// BlockingTypes = [BlockingType.HARD.ToString()],
//};
public readonly static AgvAction MoveStraightToCoor = new()
{
ActionType = ActionType.moveStraightToCoor.ToString(),
ActionDescription = "Di chuyển thẳng đến tọa độ xác định.",
ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
ActionParameters = [
new()
{
Key = "x",
Description = "Tọa độ X đích đến.",
ValueDataType = ValueDataType.FLOAT.ToString(),
IsOptional = false,
},
new()
{
Key = "y",
Description = "Tọa độ Y đích đến.",
ValueDataType = ValueDataType.FLOAT.ToString(),
IsOptional = false,
}],
ResultDescription = "Robot đã di chuyển thẳng đến tọa độ xác định.",
BlockingTypes = [BlockingType.HARD.ToString()],
};
//public readonly static AgvAction MoveStraightToCoor = new()
//{
// ActionType = ActionType.moveStraightToCoor.ToString(),
// ActionDescription = "Di chuyển thẳng đến tọa độ xác định.",
// ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
// ActionParameters = [
// new()
// {
// Key = "x",
// Description = "Tọa độ X đích đến.",
// ValueDataType = ValueDataType.FLOAT.ToString(),
// IsOptional = false,
// },
// new()
// {
// Key = "y",
// Description = "Tọa độ Y đích đến.",
// ValueDataType = ValueDataType.FLOAT.ToString(),
// IsOptional = false,
// }],
// ResultDescription = "Robot đã di chuyển thẳng đến tọa độ xác định.",
// BlockingTypes = [BlockingType.HARD.ToString()],
//};
public readonly static AgvAction MoveStraightWithDistance = new()
{
ActionType = ActionType.moveStraightWithDistance.ToString(),
ActionDescription = "Di chuyển thẳng với khoảng cách xác định.",
ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
ActionParameters = [
new()
{
Key = "distance",
Description = "Khoảng cách di chuyển. (m)",
ValueDataType = ValueDataType.FLOAT.ToString(),
IsOptional = false,
},
new()
{
Key = "direction",
Description = "Hướng di chuyển: 1 - tiến, -1 - lùi.",
ValueDataType = ValueDataType.INTEGER.ToString(),
IsOptional = false,
},
new()
{
Key = "angle",
Description = "Góc di chuyển so với hướng hiện tại của robot. (rad)",
ValueDataType = ValueDataType.FLOAT.ToString(),
IsOptional = true,
}],
ResultDescription = "Robot đã di chuyển thẳng với khoảng cách xác định.",
BlockingTypes = [BlockingType.HARD.ToString()],
};
//public readonly static AgvAction MoveStraightWithDistance = new()
//{
// ActionType = ActionType.moveStraightWithDistance.ToString(),
// ActionDescription = "Di chuyển thẳng với khoảng cách xác định.",
// ActionScopes = [ActionScopes.INSTANT.ToString(), ActionScopes.NODE.ToString()],
// ActionParameters = [
// new()
// {
// Key = "distance",
// Description = "Khoảng cách di chuyển. (m)",
// ValueDataType = ValueDataType.FLOAT.ToString(),
// IsOptional = false,
// },
// new()
// {
// Key = "direction",
// Description = "Hướng di chuyển: 1 - tiến, -1 - lùi.",
// ValueDataType = ValueDataType.INTEGER.ToString(),
// IsOptional = false,
// },
// new()
// {
// Key = "angle",
// Description = "Góc di chuyển so với hướng hiện tại của robot. (rad)",
// ValueDataType = ValueDataType.FLOAT.ToString(),
// IsOptional = true,
// }],
// ResultDescription = "Robot đã di chuyển thẳng với khoảng cách xác định.",
// BlockingTypes = [BlockingType.HARD.ToString()],
//};
}

View File

@ -84,8 +84,6 @@ public class RobotOrderController(INavigation NavigationManager,
{
OrderTimer?.Dispose();
OrderTimer = null;
//OrderId = string.Empty;
//OrderUpdateId = 0;
OrderActions.Clear();
ActionWaitingRunning.Clear();
CurrentBaseNode = null;
@ -157,12 +155,29 @@ public class RobotOrderController(INavigation NavigationManager,
private void HandleNewOrder(OrderMsg order)
{
//if (NavigationManager.State != NavigationState.Idle) throw new OrderException(RobotErrors.Error1012(NavigationManager.State));
if (order.OrderId == OrderId)
{
if (order.OrderUpdateId < OrderUpdateId) throw new OrderException(RobotErrors.Error1018(OrderUpdateId, order.OrderUpdateId));
if (order.OrderUpdateId == OrderUpdateId) return;
if (order.Nodes[0].NodeId != LastNodeId)
{
throw new OrderException(RobotErrors.Error1016(LastNodeId, order.Nodes[0].NodeId));
}
if (order.Nodes[0].SequenceId != LastNodeSequenceId)
{
throw new OrderException(RobotErrors.Error1017(LastNodeSequenceId, order.Nodes[0].SequenceId));
}
}
OrderActions.Clear();
ActionManager.ClearInstantActions();
LastNode = null;
FinalAction = [];
IsNavigationFinished = false;
IsCancelOrder = false;
IsActionRunning = false;
IsWaitingPaused = false;
ActionHard = null;
for (int i = 0; i < order.Edges.Length; i++)
{
@ -203,8 +218,6 @@ public class RobotOrderController(INavigation NavigationManager,
}
else OrderActions.Add(order.Nodes[i].NodeId, order.Edges[i].Actions);
}
//if (i > 0 && order.Nodes[i].SequenceId <= order.Nodes[i - 1].SequenceId) throw new OrderException(RobotErrors.Error1010(order.Nodes[i].NodeId, order.Nodes[i].SequenceId, i));
//if (i < order.Nodes.Length - 1 && order.Edges[i].SequenceId != i) throw new OrderException(RobotErrors.Error1011(order.Edges[i].EdgeId, order.Edges[i].SequenceId, i));
if (order.Nodes[i].Released) CurrentBaseNode = order.Nodes[i];
}
SafetyManager.OnSafetySpeedChanged += OnSafetySpeedChanged;
@ -250,6 +263,15 @@ public class RobotOrderController(INavigation NavigationManager,
if (order.OrderId != OrderId) throw new OrderException(RobotErrors.Error1001(OrderId, order.OrderId));
if (order.OrderUpdateId <= OrderUpdateId) return;
if (CurrentBaseNode is not null && order.Nodes[0].NodeId != CurrentBaseNode.NodeId)
{
throw new OrderException(RobotErrors.Error1016(LastNodeId, order.Nodes[0].NodeId));
}
if (CurrentBaseNode is not null && order.Nodes[0].SequenceId != CurrentBaseNode.SequenceId)
{
throw new OrderException(RobotErrors.Error1017(LastNodeSequenceId, order.Nodes[0].SequenceId));
}
var lastBastNode = order.Nodes.Last(n => n.Released);
if (lastBastNode is not null && lastBastNode.NodeId != CurrentBaseNode?.NodeId)
{
@ -266,14 +288,17 @@ public class RobotOrderController(INavigation NavigationManager,
{
if (IsCancelOrder)
{
IsCancelOrder = false;
NavigationManager.CancelMovement();
NavigationFinished();
return;
}
if (IsNavigationFinished || IsOneceNode)
{
if (IsCancelOrder && !ActionManager.HasActionRunning)
{
HandleOrderStop();
return;
}
if (FinalAction.Count > 0)
{
var action = FinalAction[0];
@ -338,13 +363,13 @@ public class RobotOrderController(INavigation NavigationManager,
}
else
{
if (IsWaitingPaused) IsWaitingPaused = false;
}
}
if (ActionHard == null && ActionWaitingRunning.IsEmpty)
if (IsWaitingPaused)
{
IsWaitingPaused = false;
NavigationManager.Resume();
if (CurrentBaseNode is not null && CurrentBaseNode.NodeId != Nodes[0].NodeId && Nodes.Length > 1) NavigationManager.UpdateOrder(CurrentBaseNode.NodeId);
}
}
}
}
@ -361,12 +386,14 @@ public class RobotOrderController(INavigation NavigationManager,
NewOrder = null;
}
if (NewOrderHandler.Nodes.Length < 2) throw new OrderException(RobotErrors.Error1002(NewOrderHandler.Nodes.Length));
//if (NewOrderHandler.Edges.Length < 1) throw new OrderException(RobotErrors.Error1003(NewOrderHandler.Edges.Length));
//if (NewOrderHandler.Edges.Length != NewOrderHandler.Nodes.Length - 1) throw new OrderException(RobotErrors.Error1004(NewOrderHandler.Nodes.Length, NewOrderHandler.Edges.Length));
if (NewOrderHandler.Nodes.Length < 1) throw new OrderException(RobotErrors.Error1002(NewOrderHandler.Nodes.Length));
if (NewOrderHandler.Edges.Length != NewOrderHandler.Nodes.Length - 1) throw new OrderException(RobotErrors.Error1004(NewOrderHandler.Nodes.Length, NewOrderHandler.Edges.Length));
if (NodeStates.Length == 0) HandleNewOrder(NewOrderHandler);
else HandleUpdateOrder(NewOrderHandler);
if (NodeStates.Length != 0 || EdgeStates.Length != 0) HandleUpdateOrder(NewOrderHandler);
else
{
HandleNewOrder(NewOrderHandler);
}
}
HandleOrder();
}

View File

@ -47,8 +47,8 @@ public class RobotStates(RobotConfiguration RobotConfiguration,
Maps = [],
OrderId = OrderManager.OrderId,
OrderUpdateId = OrderManager.OrderUpdateId,
ZoneSetId = "9879E7A9-CF5F-4ABD-924E-08DE1C3D25FE",
LastNodeId = string.IsNullOrEmpty(OrderManager.LastNodeId) ? "EE9959EC-B670-4D22-8BD2-08DE1C3D71FC" : OrderManager.LastNodeId,
ZoneSetId = "",
LastNodeId = OrderManager.LastNodeId,
LastNodeSequenceId = OrderManager.LastNodeSequenceId,
Driving = NavigationManager.VelocityX > 0 || NavigationManager.Omega > 0,
Paused = false,

View File

@ -22,7 +22,7 @@ public class SimulationNavigation : INavigation, IDisposable
protected bool NavDriving = false;
protected const int CycleHandlerMilliseconds = 50;
private const double Scale = 2;
private const double Scale = 1;
//private WatchTimer<SimulationNavigation>? NavigationTimer;
private HighPrecisionTimer<SimulationNavigation>? NavigationTimer;
@ -45,7 +45,7 @@ public class SimulationNavigation : INavigation, IDisposable
protected NavigationNode[] NavigationPath = [];
protected NavigationNode? CurrentBaseNode;
protected NavigationState ResumeState = NavigationState.None;
protected NavigationState ResumeState = NavigationState.Idle;
private readonly Logger<SimulationNavigation> Logger;
@ -158,14 +158,15 @@ public class SimulationNavigation : INavigation, IDisposable
public void Pause()
{
Console.WriteLine($"Nav Pause");
ResumeState = State;
NavState = NavigationState.Paused;
}
public void Resume()
{
Console.WriteLine($"Nav Resume");
NavState = ResumeState;
ResumeState = NavigationState.None;
}
public void Rotate(double angle)