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 = [ public NavModel[] Navs = [
new(){Icon = "mdi-view-dashboard", Path="/", Label = "Dashboard", Match = NavLinkMatch.All}, 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}, new(){Icon = "mdi-application-cog", Path="/robot-config", Label = "Config", Match = NavLinkMatch.All},
]; ];

View File

@ -5,7 +5,7 @@
<DataAnnotationsValidator /> <DataAnnotationsValidator />
<div class="form-check mb-2"> <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> <label class="form-check-label">Enable Simulation</label>
<ValidationMessage For="@(() => Model.EnableSimulation)" /> <ValidationMessage For="@(() => Model.EnableSimulation)" />
</div> </div>

View File

@ -16,7 +16,7 @@
<label class="rcm-label" for="configType">Config Type</label> <label class="rcm-label" for="configType">Config Type</label>
<div class="rcm-select-wrapper"> <div class="rcm-select-wrapper">
<select id="configType" class="form-select rcm-select" value="@SelectedType" @onchange="OnTypeChanged"> <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> <option value="@type">@type</option>
} }
@ -31,9 +31,9 @@
<div class="rcm-toolbar-right"> <div class="rcm-toolbar-right">
<div class="rcm-action-group"> <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> <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"> <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> <i class="mdi mdi-content-save" aria-hidden="true"></i>
@ -43,9 +43,9 @@
<i class="mdi mdi-file-download" aria-hidden="true"></i> <i class="mdi mdi-file-download" aria-hidden="true"></i>
</button> </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> <i class="mdi mdi-delete" aria-hidden="true"></i>
</button> </button> *@
</div> </div>
</div> </div>
</div> </div>
@ -227,6 +227,7 @@
private AddFormModel addForm = new(); private AddFormModel addForm = new();
private string SelectedTemplateIdString = string.Empty; private string SelectedTemplateIdString = string.Empty;
private IEnumerable<RobotConfigType> GetConfigType = [RobotConfigType.VDA5050, RobotConfigType.Simulation];
private IEnumerable<(Guid Id, string Name, bool Active)> GetTemplatesForSelectedType() private IEnumerable<(Guid Id, string Name, bool Active)> GetTemplatesForSelectedType()
{ {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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