update
This commit is contained in:
parent
e4e135e35f
commit
a51cfe80c8
|
|
@ -13,7 +13,7 @@
|
|||
<!-- Header Dashboard -->
|
||||
<MudPaper Class="pa-6 mb-4 d-flex align-center justify-space-between" Elevation="3">
|
||||
<div>
|
||||
<MudText Typo="Typo.h3" Class="mb-2" >Robot Dashboard</MudText>
|
||||
<MudText Typo="Typo.h3" Class="mb-2">Robot Dashboard</MudText>
|
||||
@if (CurrentState != null)
|
||||
{
|
||||
<MudText Typo="Typo.subtitle1">
|
||||
|
|
@ -373,45 +373,34 @@
|
|||
|
||||
private StateMsg? CurrentState;
|
||||
private bool IsConnected;
|
||||
private readonly string RobotSerial = "T800-002";
|
||||
private List<MessageRow> MessageRows = new();
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
if (!firstRender) return;
|
||||
RobotStateClient.OnStateReceived += OnRobotStateReceived;
|
||||
RobotStateClient.OnRobotConnectionChanged += OnRobotConnectionChanged;
|
||||
|
||||
if (RobotStateClient.ConnectionState == RobotClientState.Disconnected)
|
||||
{
|
||||
await RobotStateClient.StartAsync();
|
||||
}
|
||||
|
||||
await RobotStateClient.SubscribeRobotAsync(RobotSerial);
|
||||
|
||||
CurrentState = RobotStateClient.GetLatestState(RobotSerial);
|
||||
CurrentState = RobotStateClient.GetLatestState();
|
||||
IsConnected = RobotStateClient.IsRobotConnected;
|
||||
|
||||
UpdateMessageRows();
|
||||
}
|
||||
|
||||
private void OnRobotConnectionChanged(bool connected)
|
||||
{
|
||||
InvokeAsync(() =>
|
||||
{
|
||||
IsConnected = connected;
|
||||
StateHasChanged();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void OnRobotStateReceived(string serialNumber, StateMsg state)
|
||||
{
|
||||
if (serialNumber != RobotSerial) return;
|
||||
InvokeAsync(() =>
|
||||
{
|
||||
CurrentState = state;
|
||||
UpdateMessageRows();
|
||||
StateHasChanged();
|
||||
});
|
||||
}
|
||||
|
||||
private void UpdateMessageRows()
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
if (firstRender)
|
||||
{
|
||||
MonitorService.OnDataReceived += OnMonitorDataReceived;
|
||||
|
|
@ -28,7 +29,7 @@
|
|||
{
|
||||
_monitorData = data;
|
||||
RobotMonitorViewRef?.UpdatePath();
|
||||
InvokeAsync(StateHasChanged);
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
|
|
@ -41,3 +42,7 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ public sealed class RobotStateClient : IAsyncDisposable
|
|||
// ================= SIGNALR HANDLERS =================
|
||||
|
||||
// VDA5050 State
|
||||
_connection.On<string>("ReceiveState", HandleState);
|
||||
_connection.On<StateMsg>("ReceiveState", HandleState);
|
||||
|
||||
// Robot connection (bool only)
|
||||
_connection.On<bool>("ReceiveRobotConnection", HandleRobotConnection);
|
||||
|
|
@ -125,21 +125,21 @@ public sealed class RobotStateClient : IAsyncDisposable
|
|||
}
|
||||
|
||||
// ================= HANDLE STATE =================
|
||||
private void HandleState(string stateJson)
|
||||
private void HandleState(StateMsg state)
|
||||
{
|
||||
StateMsg? state;
|
||||
//StateMsg? state;
|
||||
|
||||
try
|
||||
{
|
||||
state = JsonSerializer.Deserialize<StateMsg>(
|
||||
stateJson,
|
||||
JsonOptionExtends.Read
|
||||
);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return;
|
||||
}
|
||||
//try
|
||||
//{
|
||||
// state = JsonSerializer.Deserialize<StateMsg>(
|
||||
// stateJson,
|
||||
// JsonOptionExtends.Read
|
||||
// );
|
||||
//}
|
||||
//catch
|
||||
//{
|
||||
// return;
|
||||
//}
|
||||
|
||||
if (state?.SerialNumber == null)
|
||||
return;
|
||||
|
|
@ -189,10 +189,10 @@ public sealed class RobotStateClient : IAsyncDisposable
|
|||
}
|
||||
|
||||
// ================= GET CACHE =================
|
||||
public StateMsg? GetLatestState(string serialNumber)
|
||||
public StateMsg? GetLatestState()
|
||||
{
|
||||
LatestStates.TryGetValue(serialNumber, out var state);
|
||||
return state;
|
||||
if (!LatestStates.IsEmpty) return LatestStates.First().Value;
|
||||
return null;
|
||||
}
|
||||
|
||||
// ================= DISPOSE =================
|
||||
|
|
|
|||
|
|
@ -60,3 +60,7 @@ window.robotMonitor = {
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ public class OrderController(IOrder robotOrderController, IInstantActions instan
|
|||
{
|
||||
robotOrderController.StopOrder();
|
||||
instantActions.StopOrderAction();
|
||||
|
||||
return Ok(new
|
||||
{
|
||||
success = true,
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ namespace RobotApp.Hubs
|
|||
// Phương thức này sẽ được gọi từ service để broadcast
|
||||
public async Task SendState(string serialNumber, StateMsg state)
|
||||
{
|
||||
var json = JsonSerializer.Serialize(state, JsonOptionExtends.Write);
|
||||
await Clients.Group(serialNumber).SendAsync("ReceiveState", json);
|
||||
//var json = JsonSerializer.Serialize(state, JsonOptionExtends.Write);
|
||||
await Clients.Group(serialNumber).SendAsync("ReceiveState", state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12,3 +12,7 @@ public class RobotMonitorHub : Hub
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ builder.Services.AddRobot();
|
|||
builder.Services.AddSingleton<RobotApp.Services.RobotMonitorService>();
|
||||
builder.Services.AddHostedService(sp => sp.GetRequiredService<RobotApp.Services.RobotMonitorService>());
|
||||
|
||||
builder.Services.AddScoped<RobotStateClient>();
|
||||
//builder.Services.AddScoped<RobotStateClient>();
|
||||
builder.Services.AddHostedService<RobotStatePublisher>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
|
|
|||
|
|
@ -105,7 +105,8 @@ public class RobotErrors : IError
|
|||
=> 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 Error1019()
|
||||
=> CreateError(ErrorType.INITIALIZE_ORDER, "Vui lòng kiểm tra lại Order", ErrorLevel.WARNING, "Order có node đầu tiên quá xa robot");
|
||||
|
||||
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)");
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using RobotApp.VDA5050.Order;
|
|||
using RobotApp.VDA5050.State;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Data;
|
||||
using System.Xml.Linq;
|
||||
using Action = RobotApp.VDA5050.InstantAction.Action;
|
||||
|
||||
namespace RobotApp.Services.Robot;
|
||||
|
|
@ -247,11 +248,6 @@ public class RobotOrderController(INavigation NavigationManager,
|
|||
UpdateState();
|
||||
}
|
||||
|
||||
private bool IsNewPath()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ClearLastNode()
|
||||
{
|
||||
if (LastNode is null) return;
|
||||
|
|
@ -292,6 +288,7 @@ public class RobotOrderController(INavigation NavigationManager,
|
|||
|
||||
private void HandleOrder()
|
||||
{
|
||||
if (Nodes.Length <= 0) return;
|
||||
if (IsCancelOrder)
|
||||
{
|
||||
NavigationManager.CancelMovement();
|
||||
|
|
@ -309,8 +306,12 @@ public class RobotOrderController(INavigation NavigationManager,
|
|||
{
|
||||
var action = FinalAction[0];
|
||||
var robotAction = ActionManager[action.ActionId];
|
||||
if (robotAction is null) return;
|
||||
if (robotAction.IsCompleted) FinalAction.Remove(action);
|
||||
if (robotAction is null)
|
||||
{
|
||||
FinalAction.Remove(action);
|
||||
return;
|
||||
}
|
||||
if (robotAction.IsCompleted)
|
||||
if (robotAction.Status == ActionStatus.WAITING) ActionManager.StartOrderAction(action.ActionId);
|
||||
}
|
||||
else
|
||||
|
|
@ -398,6 +399,10 @@ public class RobotOrderController(INavigation NavigationManager,
|
|||
if (NodeStates.Length != 0 || EdgeStates.Length != 0) HandleUpdateOrder(NewOrderHandler);
|
||||
else
|
||||
{
|
||||
Node startNode = NewOrderHandler.Nodes[0];
|
||||
var nodeDeviation = startNode.NodePosition.AllowedDeviationXY == 0.0 ? NewOrderHandler.Nodes.Length == 1 ? 0.3 : 0.5 : startNode.NodePosition.AllowedDeviationXY;
|
||||
var distance = Localization.DistanceTo(startNode.NodePosition.X, startNode.NodePosition.Y);
|
||||
if (distance > nodeDeviation) throw new OrderException(RobotErrors.Error1019());
|
||||
HandleNewOrder(NewOrderHandler);
|
||||
}
|
||||
}
|
||||
|
|
@ -409,6 +414,7 @@ public class RobotOrderController(INavigation NavigationManager,
|
|||
{
|
||||
ErrorManager.AddError(orEx.Error, TimeSpan.FromSeconds(10));
|
||||
Logger.Warning($"Lỗi khi xử lí Order: {orEx.Error.ErrorDescription}");
|
||||
HandleOrderStop();
|
||||
}
|
||||
else Logger.Warning($"Lỗi khi xử lí Order: {orEx.Message}");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,148 +12,27 @@ using System.Text.Json;
|
|||
|
||||
namespace RobotApp.Services.Robot;
|
||||
|
||||
public class RobotStatePublisher : BackgroundService
|
||||
public class RobotStatePublisher(
|
||||
IHubContext<RobotHub> _hubContext,
|
||||
RobotStates _robotState,
|
||||
RobotConnection _robotConnection) : BackgroundService
|
||||
{
|
||||
private readonly IHubContext<RobotHub> _hubContext;
|
||||
private readonly RobotConfiguration _robotConfig;
|
||||
private readonly IOrder _orderManager;
|
||||
private readonly IInstantActions _actionManager;
|
||||
private readonly IPeripheral _peripheralManager;
|
||||
private readonly IInfomation _infoManager;
|
||||
private readonly IError _errorManager;
|
||||
private readonly ILocalization _localizationManager;
|
||||
private readonly IBattery _batteryManager;
|
||||
private readonly ILoad _loadManager;
|
||||
private readonly INavigation _navigationManager;
|
||||
private readonly RobotStateMachine _stateManager;
|
||||
private readonly RobotConnection _robotConnection;
|
||||
private bool? _lastRobotConnectionState;
|
||||
|
||||
private uint _headerId = 0;
|
||||
private readonly PeriodicTimer _timer = new(TimeSpan.FromMilliseconds(1000)); // 1 giây/lần
|
||||
|
||||
public RobotStatePublisher(
|
||||
IHubContext<RobotHub> hubContext,
|
||||
RobotConfiguration robotConfig,
|
||||
IOrder orderManager,
|
||||
IInstantActions actionManager,
|
||||
IPeripheral peripheralManager,
|
||||
IInfomation infoManager,
|
||||
IError errorManager,
|
||||
ILocalization localizationManager,
|
||||
IBattery batteryManager,
|
||||
ILoad loadManager,
|
||||
INavigation navigationManager,
|
||||
RobotStateMachine stateManager,
|
||||
RobotConnection robotConnection)
|
||||
{
|
||||
_hubContext = hubContext;
|
||||
_robotConfig = robotConfig;
|
||||
_orderManager = orderManager;
|
||||
_actionManager = actionManager;
|
||||
_peripheralManager = peripheralManager;
|
||||
_infoManager = infoManager;
|
||||
_errorManager = errorManager;
|
||||
_localizationManager = localizationManager;
|
||||
_batteryManager = batteryManager;
|
||||
_loadManager = loadManager;
|
||||
_navigationManager = navigationManager;
|
||||
_stateManager = stateManager;
|
||||
_robotConnection = robotConnection;
|
||||
}
|
||||
|
||||
private StateMsg GetStateMsg()
|
||||
{
|
||||
return new StateMsg
|
||||
{
|
||||
HeaderId = _headerId++,
|
||||
Timestamp = DateTime.UtcNow.ToString("o"), // ISO 8601
|
||||
Manufacturer = _robotConfig.VDA5050Setting.Manufacturer,
|
||||
Version = _robotConfig.VDA5050Setting.Version,
|
||||
SerialNumber = _robotConfig.SerialNumber,
|
||||
Maps = [],
|
||||
OrderId = _orderManager.OrderId,
|
||||
OrderUpdateId = _orderManager.OrderUpdateId,
|
||||
ZoneSetId = "",
|
||||
LastNodeId = _orderManager.LastNodeId,
|
||||
LastNodeSequenceId = _orderManager.LastNodeSequenceId,
|
||||
Driving = Math.Abs(_navigationManager.VelocityX) > 0.01 || Math.Abs(_navigationManager.Omega) > 0.01,
|
||||
Paused = false,
|
||||
NewBaseRequest = true,
|
||||
DistanceSinceLastNode = 0,
|
||||
OperatingMode = _peripheralManager.PeripheralMode.ToString(),
|
||||
NodeStates = _orderManager.NodeStates,
|
||||
EdgeStates = _orderManager.EdgeStates,
|
||||
ActionStates = _actionManager.ActionStates,
|
||||
Information = [General, .. _infoManager.InformationState],
|
||||
Errors = _errorManager.ErrorsState,
|
||||
AgvPosition = new AgvPosition
|
||||
{
|
||||
X = _localizationManager.X,
|
||||
Y = _localizationManager.Y,
|
||||
Theta = _localizationManager.Theta,
|
||||
LocalizationScore = _localizationManager.MatchingScore,
|
||||
MapId = _localizationManager.CurrentActiveMap,
|
||||
DeviationRange = _localizationManager.Reliability,
|
||||
PositionInitialized = _localizationManager.IsReady,
|
||||
},
|
||||
BatteryState = new BatteryState
|
||||
{
|
||||
Charging = _batteryManager.IsCharging,
|
||||
BatteryHealth = _batteryManager.SOH,
|
||||
Reach = 0,
|
||||
BatteryVoltage = _batteryManager.Voltage,
|
||||
BatteryCharge = _batteryManager.SOC,
|
||||
},
|
||||
Loads = _loadManager.Load,
|
||||
Velocity = new Velocity
|
||||
{
|
||||
Vx = _navigationManager.VelocityX,
|
||||
Vy = _navigationManager.VelocityY,
|
||||
Omega = _navigationManager.Omega,
|
||||
},
|
||||
SafetyState = new SafetyState
|
||||
{
|
||||
FieldViolation = _peripheralManager.LidarBackProtectField ||
|
||||
_peripheralManager.LidarFrontProtectField ||
|
||||
_peripheralManager.LidarFrontTimProtectField,
|
||||
EStop = (_peripheralManager.Emergency || _peripheralManager.Bumper)
|
||||
? EStop.AUTOACK.ToString()
|
||||
: EStop.NONE.ToString(),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Information General => new()
|
||||
{
|
||||
InfoType = InformationType.robot_general.ToString(),
|
||||
InfoDescription = "Thông tin chung của robot",
|
||||
InfoLevel = InfoLevel.INFO.ToString(),
|
||||
InfoReferences =
|
||||
[
|
||||
new InfomationReferences
|
||||
{
|
||||
ReferenceKey = InformationReferencesKey.robot_state.ToString(),
|
||||
ReferenceValue = _stateManager.CurrentStateName,
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
while (await _timer.WaitForNextTickAsync(stoppingToken))
|
||||
{
|
||||
try
|
||||
{
|
||||
var serialNumber = _robotConfig.SerialNumber;
|
||||
|
||||
// ===== SEND STATE =====
|
||||
var state = GetStateMsg();
|
||||
var json = JsonSerializer.Serialize(state, JsonOptionExtends.Write);
|
||||
var state = _robotState.GetStateMsg();
|
||||
//var json = JsonSerializer.Serialize(state, JsonOptionExtends.Write);
|
||||
|
||||
await _hubContext.Clients
|
||||
.Group(serialNumber)
|
||||
.SendAsync("ReceiveState", json, stoppingToken);
|
||||
await _hubContext.Clients.All
|
||||
.SendAsync("ReceiveState", state, stoppingToken);
|
||||
|
||||
// ===== SEND ROBOT CONNECTION (ONLY WHEN CHANGED) =====
|
||||
var isConnected = _robotConnection.IsConnected;
|
||||
|
|
@ -162,8 +41,7 @@ public class RobotStatePublisher : BackgroundService
|
|||
{
|
||||
_lastRobotConnectionState = isConnected;
|
||||
|
||||
await _hubContext.Clients
|
||||
.Group(serialNumber) // routing only
|
||||
await _hubContext.Clients.All
|
||||
.SendAsync(
|
||||
"ReceiveRobotConnection",
|
||||
isConnected, // payload only bool
|
||||
|
|
@ -177,10 +55,10 @@ public class RobotStatePublisher : BackgroundService
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public override void Dispose()
|
||||
public override Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_timer?.Dispose();
|
||||
base.Dispose();
|
||||
return base.StopAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
@ -36,7 +36,7 @@ public class RobotStates(RobotConfiguration RobotConfiguration,
|
|||
catch { }
|
||||
}
|
||||
|
||||
private StateMsg GetStateMsg()
|
||||
public StateMsg GetStateMsg()
|
||||
{
|
||||
return new StateMsg
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user