Initial commit
This commit is contained in:
@@ -0,0 +1,262 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
using RobotNet10.RobotApp.Client.Shared.Motion;
|
||||
using RobotNet10.RobotApp.Client.Shared.Modules;
|
||||
|
||||
namespace RobotNet10.RobotApp.Client.Clients;
|
||||
|
||||
/// <summary>
|
||||
/// SignalR client thống nhất để kết nối với MotionHub
|
||||
/// Bao gồm: ManualControl, Odometry, LiftModule, RotationModule
|
||||
/// </summary>
|
||||
public class MotionHubClient : IAsyncDisposable
|
||||
{
|
||||
private readonly HubConnection _hubConnection;
|
||||
private bool _disposed;
|
||||
|
||||
public bool IsConnected => _hubConnection.State == HubConnectionState.Connected;
|
||||
public HubConnectionState ConnectionState => _hubConnection.State;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when odometry pose changes
|
||||
/// </summary>
|
||||
public event Action<OdometryDto>? PoseUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when connection state changes
|
||||
/// </summary>
|
||||
public event Action<HubConnectionState>? ConnectionStateChanged;
|
||||
|
||||
public MotionHubClient(NavigationManager navigationManager)
|
||||
{
|
||||
var hubUrl = navigationManager.ToAbsoluteUri("/hubs/motion");
|
||||
|
||||
_hubConnection = new HubConnectionBuilder()
|
||||
.WithUrl(hubUrl)
|
||||
.WithAutomaticReconnect()
|
||||
.Build();
|
||||
|
||||
// Subscribe to pose updates from server
|
||||
_hubConnection.On<OdometryDto>("PoseUpdated", dto => PoseUpdated?.Invoke(dto));
|
||||
|
||||
_hubConnection.Reconnecting += async (ex) =>
|
||||
{
|
||||
ConnectionStateChanged?.Invoke(_hubConnection.State);
|
||||
await Task.CompletedTask;
|
||||
};
|
||||
|
||||
_hubConnection.Reconnected += async (id) =>
|
||||
{
|
||||
ConnectionStateChanged?.Invoke(_hubConnection.State);
|
||||
await Task.CompletedTask;
|
||||
};
|
||||
|
||||
_hubConnection.Closed += async (ex) =>
|
||||
{
|
||||
ConnectionStateChanged?.Invoke(_hubConnection.State);
|
||||
await Task.CompletedTask;
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Connect to hub
|
||||
/// </summary>
|
||||
public async Task StartAsync()
|
||||
{
|
||||
if (_hubConnection.State == HubConnectionState.Disconnected)
|
||||
{
|
||||
await _hubConnection.StartAsync();
|
||||
ConnectionStateChanged?.Invoke(_hubConnection.State);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disconnect from hub
|
||||
/// </summary>
|
||||
public async Task StopAsync()
|
||||
{
|
||||
if (_hubConnection.State != HubConnectionState.Disconnected)
|
||||
{
|
||||
await _hubConnection.StopAsync();
|
||||
}
|
||||
}
|
||||
|
||||
#region Manual Control
|
||||
|
||||
/// <summary>
|
||||
/// Get current status
|
||||
/// </summary>
|
||||
public async Task<ManualControlStatusDto> GetStatusAsync()
|
||||
{
|
||||
return await _hubConnection.InvokeAsync<ManualControlStatusDto>("GetStatus");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable manual control
|
||||
/// </summary>
|
||||
public async Task EnableAsync()
|
||||
{
|
||||
await _hubConnection.InvokeAsync("Enable");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disable manual control
|
||||
/// </summary>
|
||||
public async Task DisableAsync()
|
||||
{
|
||||
await _hubConnection.InvokeAsync("Disable");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Odometry
|
||||
|
||||
/// <summary>
|
||||
/// Get current odometry pose
|
||||
/// </summary>
|
||||
public async Task<OdometryDto> GetCurrentPoseAsync()
|
||||
{
|
||||
return await _hubConnection.InvokeAsync<OdometryDto>("GetCurrentPose");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset odometry to initial position
|
||||
/// </summary>
|
||||
public async Task ResetOdometryAsync()
|
||||
{
|
||||
await _hubConnection.InvokeAsync("ResetOdometry");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset odometry to a specific pose
|
||||
/// </summary>
|
||||
public async Task ResetOdometryPoseAsync(OdometryDto dto)
|
||||
{
|
||||
await _hubConnection.InvokeAsync("ResetOdometryPose", dto);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Lift Module
|
||||
|
||||
/// <summary>
|
||||
/// Get lift module status
|
||||
/// </summary>
|
||||
public async Task<LiftModuleStatusDto> GetLiftStatusAsync()
|
||||
{
|
||||
return await _hubConnection.InvokeAsync<LiftModuleStatusDto>("GetLiftStatus");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get current lift position
|
||||
/// </summary>
|
||||
public async Task<int> GetLiftCurrentPositionAsync()
|
||||
{
|
||||
return await _hubConnection.InvokeAsync<int>("GetLiftCurrentPosition");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lift up
|
||||
/// </summary>
|
||||
public async Task LiftUpAsync()
|
||||
{
|
||||
await _hubConnection.InvokeAsync("LiftUp");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lift down
|
||||
/// </summary>
|
||||
public async Task LiftDownAsync()
|
||||
{
|
||||
await _hubConnection.InvokeAsync("LiftDown");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop lift movement (when moving up/down)
|
||||
/// </summary>
|
||||
public async Task LiftStopAsync()
|
||||
{
|
||||
await _hubConnection.InvokeAsync("LiftStop");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Move lift to position
|
||||
/// </summary>
|
||||
public async Task LiftToPositionAsync(int position)
|
||||
{
|
||||
await _hubConnection.InvokeAsync("LiftToPosition", position);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if lift module is homed
|
||||
/// </summary>
|
||||
public async Task<bool> IsLiftHomedAsync()
|
||||
{
|
||||
return await _hubConnection.InvokeAsync<bool>("IsLiftHomed");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manual homing for lift module
|
||||
/// </summary>
|
||||
public async Task LiftHomeAsync()
|
||||
{
|
||||
await _hubConnection.InvokeAsync("LiftHome");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rotation Module
|
||||
|
||||
/// <summary>
|
||||
/// Get rotation module status
|
||||
/// </summary>
|
||||
public async Task<RotationModuleStatusDto> GetRotationStatusAsync()
|
||||
{
|
||||
return await _hubConnection.InvokeAsync<RotationModuleStatusDto>("GetRotationStatus");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get current rotation angle
|
||||
/// </summary>
|
||||
public async Task<double> GetRotationCurrentAngleAsync()
|
||||
{
|
||||
return await _hubConnection.InvokeAsync<double>("GetRotationCurrentAngle");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rotate to absolute angle
|
||||
/// </summary>
|
||||
public async Task RotateToAngleAsync(double angleDegrees)
|
||||
{
|
||||
await _hubConnection.InvokeAsync("RotateToAngle", angleDegrees);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rotate relative offset
|
||||
/// </summary>
|
||||
public async Task RotateOffsetAsync(double angleOffsetDegrees)
|
||||
{
|
||||
await _hubConnection.InvokeAsync("RotateOffset", angleOffsetDegrees);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if rotation module is homed
|
||||
/// </summary>
|
||||
public async Task<bool> IsRotationHomedAsync()
|
||||
{
|
||||
return await _hubConnection.InvokeAsync<bool>("IsRotationHomed");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
|
||||
_disposed = true;
|
||||
|
||||
await StopAsync();
|
||||
await _hubConnection.DisposeAsync();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user