✨ feat(fanuc): 添加直角坐标点动功能与相关接口
* 新增 `MovePose` 方法,支持以直角坐标执行点到点移动。 * 引入 `LegacyCartesianPoseRequest` 类,处理直角位姿请求体的解析与验证。 * 更新 `LegacyHttpApiController`,实现 `/move_pose/` 路由以支持新功能。 * 增强状态快照元数据,提供机器人初始化状态与已上传轨迹信息。 * 更新前端状态页面,增加直角坐标点动控制面板与步长设置选项。 * 相关文档与测试用例同步更新,确保新功能的完整性与稳定性。
This commit is contained in:
@@ -431,6 +431,32 @@ public sealed class LegacyHttpApiController : ControllerBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 以直角坐标 `[x,y,z,w,p,r]` 执行点到点移动。
|
||||
/// </summary>
|
||||
/// <param name="pose_data">直角位姿请求体。</param>
|
||||
/// <returns>旧 FastAPI 层风格的状态响应。</returns>
|
||||
[HttpPost("/move_pose/")]
|
||||
public IActionResult MovePose([FromBody] JsonElement pose_data)
|
||||
{
|
||||
try
|
||||
{
|
||||
var poseRequest = LegacyCartesianPoseRequest.FromJson(pose_data);
|
||||
var pose = poseRequest.ToPoseArray();
|
||||
_logger.LogInformation("MovePose 调用: x={X}, y={Y}, z={Z}, w={W}, p={P}, r={R}",
|
||||
poseRequest.x, poseRequest.y, poseRequest.z, poseRequest.w, poseRequest.p, poseRequest.r);
|
||||
|
||||
_compatService.MovePose(pose);
|
||||
_logger.LogInformation("MovePose 成功");
|
||||
return Ok(new { status = "robot moved" });
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.LogError(exception, "MovePose 失败");
|
||||
return LegacyBadRequest("MovePose failed");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 兼容旧 `GetNearestIK(pose, seed, ik)` 参数形状。
|
||||
/// </summary>
|
||||
@@ -874,6 +900,136 @@ public sealed class LegacyJointPositionRequest
|
||||
public List<double> joints { get; init; } = [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表示 `/move_pose/` 路由使用的直角位姿请求体。
|
||||
/// </summary>
|
||||
public sealed class LegacyCartesianPoseRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// MovePose 第一版入口硬限制:TCP X/Y 最大绝对值,单位 mm。
|
||||
/// </summary>
|
||||
private const double MaxHorizontalMillimeters = 1000.0;
|
||||
|
||||
/// <summary>
|
||||
/// MovePose 第一版入口硬限制:TCP Z 最小值,单位 mm。
|
||||
/// </summary>
|
||||
private const double MinZMillimeters = 0.0;
|
||||
|
||||
/// <summary>
|
||||
/// MovePose 第一版入口硬限制:TCP Z 最大值,单位 mm。
|
||||
/// </summary>
|
||||
private const double MaxZMillimeters = 1200.0;
|
||||
|
||||
/// <summary>
|
||||
/// MovePose 第一版入口硬限制:W/R 姿态角最大绝对值,单位 deg。
|
||||
/// </summary>
|
||||
private const double MaxRollYawDegrees = 180.0;
|
||||
|
||||
/// <summary>
|
||||
/// MovePose 第一版入口硬限制:P 姿态角最大绝对值,单位 deg。
|
||||
/// </summary>
|
||||
private const double MaxPitchDegrees = 90.0;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置 TCP X,单位为 mm。
|
||||
/// </summary>
|
||||
public double x { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置 TCP Y,单位为 mm。
|
||||
/// </summary>
|
||||
public double y { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置 TCP Z,单位为 mm。
|
||||
/// </summary>
|
||||
public double z { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置姿态 W,单位为 deg。
|
||||
/// </summary>
|
||||
public double w { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置姿态 P,单位为 deg。
|
||||
/// </summary>
|
||||
public double p { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置姿态 R,单位为 deg。
|
||||
/// </summary>
|
||||
public double r { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 从原始 JSON 请求体解析直角位姿,并显式拒绝缺字段、null 和非有限数。
|
||||
/// </summary>
|
||||
/// <param name="json">原始 JSON 请求体。</param>
|
||||
/// <returns>解析后的直角位姿请求。</returns>
|
||||
public static LegacyCartesianPoseRequest FromJson(JsonElement json)
|
||||
{
|
||||
if (json.ValueKind != JsonValueKind.Object)
|
||||
{
|
||||
throw new ArgumentException("MovePose request body must be an object.");
|
||||
}
|
||||
|
||||
// 旧接口要求请求体必须完整提供 x/y/z/w/p/r,不能让模型绑定把缺字段静默补 0。
|
||||
return new LegacyCartesianPoseRequest
|
||||
{
|
||||
x = ReadRequiredFiniteDouble(json, "x", -MaxHorizontalMillimeters, MaxHorizontalMillimeters),
|
||||
y = ReadRequiredFiniteDouble(json, "y", -MaxHorizontalMillimeters, MaxHorizontalMillimeters),
|
||||
z = ReadRequiredFiniteDouble(json, "z", MinZMillimeters, MaxZMillimeters),
|
||||
w = ReadRequiredFiniteDouble(json, "w", -MaxRollYawDegrees, MaxRollYawDegrees),
|
||||
p = ReadRequiredFiniteDouble(json, "p", -MaxPitchDegrees, MaxPitchDegrees),
|
||||
r = ReadRequiredFiniteDouble(json, "r", -MaxRollYawDegrees, MaxRollYawDegrees)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为兼容层使用的六维位姿数组。
|
||||
/// </summary>
|
||||
/// <returns>[x,y,z,w,p,r] 数组。</returns>
|
||||
public IReadOnlyList<double> ToPoseArray()
|
||||
{
|
||||
return [x, y, z, w, p, r];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取必填有限数值字段。
|
||||
/// </summary>
|
||||
/// <param name="json">请求体 JSON 对象。</param>
|
||||
/// <param name="propertyName">字段名。</param>
|
||||
/// <param name="minInclusive">允许的最小值。</param>
|
||||
/// <param name="maxInclusive">允许的最大值。</param>
|
||||
/// <returns>字段对应的有限 double 数值。</returns>
|
||||
private static double ReadRequiredFiniteDouble(
|
||||
JsonElement json,
|
||||
string propertyName,
|
||||
double minInclusive,
|
||||
double maxInclusive)
|
||||
{
|
||||
if (!json.TryGetProperty(propertyName, out var property) || property.ValueKind != JsonValueKind.Number)
|
||||
{
|
||||
throw new ArgumentException($"MovePose request field '{propertyName}' is required and must be a number.");
|
||||
}
|
||||
|
||||
var value = property.GetDouble();
|
||||
if (double.IsNaN(value) || double.IsInfinity(value))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(propertyName, "MovePose request values must be finite.");
|
||||
}
|
||||
|
||||
if (value < minInclusive || value > maxInclusive)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(
|
||||
propertyName,
|
||||
value,
|
||||
$"MovePose request field '{propertyName}' must be between {minInclusive} and {maxInclusive}.");
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表示旧 `/upload_flyshot/` 路由使用的飞拍上传请求体。
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user