* 新增 J519 实发采样器,按 8ms 周期生成 timing/jerk 诊断行并完成 rad->deg 转换 * 兼容层产物导出补充 speedRatio,规划编排补齐 smoothStartStopTiming 与日志透传 * 配置与机型加载切换到运行目录 JSON 模型,并补齐 7L 展开模型与相关单元测试
227 lines
6.9 KiB
C#
227 lines
6.9 KiB
C#
using System.Text.Json.Serialization;
|
|
|
|
namespace Flyshot.Core.Domain;
|
|
|
|
/// <summary>
|
|
/// 描述规划与运行时编排共同使用的机器人模型契约。
|
|
/// </summary>
|
|
public sealed class RobotProfile
|
|
{
|
|
/// <summary>
|
|
/// 使用已校验的关节约束与耦合元数据初始化机器人画像。
|
|
/// </summary>
|
|
public RobotProfile(
|
|
string name,
|
|
string modelPath,
|
|
int degreesOfFreedom,
|
|
IEnumerable<JointLimit> jointLimits,
|
|
IEnumerable<JointCoupling> jointCouplings,
|
|
TimeSpan servoPeriod,
|
|
TimeSpan triggerPeriod)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(name))
|
|
{
|
|
throw new ArgumentException("Robot profile name is required.", nameof(name));
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(modelPath))
|
|
{
|
|
throw new ArgumentException("Robot profile model path is required.", nameof(modelPath));
|
|
}
|
|
|
|
if (degreesOfFreedom <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(degreesOfFreedom), "Degrees of freedom must be positive.");
|
|
}
|
|
|
|
if (servoPeriod <= TimeSpan.Zero)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(servoPeriod), "Servo period must be positive.");
|
|
}
|
|
|
|
if (triggerPeriod <= TimeSpan.Zero)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(triggerPeriod), "Trigger period must be positive.");
|
|
}
|
|
|
|
ArgumentNullException.ThrowIfNull(jointLimits);
|
|
ArgumentNullException.ThrowIfNull(jointCouplings);
|
|
|
|
// 先对集合做一次快照,避免下游直接原地修改领域状态。
|
|
var copiedJointLimits = jointLimits.ToArray();
|
|
var copiedJointCouplings = jointCouplings.ToArray();
|
|
|
|
if (copiedJointLimits.Length != degreesOfFreedom)
|
|
{
|
|
throw new ArgumentException("Joint limit count must match degrees of freedom.", nameof(jointLimits));
|
|
}
|
|
|
|
Name = name;
|
|
ModelPath = modelPath;
|
|
DegreesOfFreedom = degreesOfFreedom;
|
|
JointLimits = copiedJointLimits;
|
|
JointCouplings = copiedJointCouplings;
|
|
ServoPeriod = servoPeriod;
|
|
TriggerPeriod = triggerPeriod;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取对运行时其余模块暴露的机器人画像名称。
|
|
/// </summary>
|
|
[JsonPropertyName("name")]
|
|
public string Name { get; }
|
|
|
|
/// <summary>
|
|
/// 获取机器人模型文件的来源路径。
|
|
/// </summary>
|
|
[JsonPropertyName("modelPath")]
|
|
public string ModelPath { get; }
|
|
|
|
/// <summary>
|
|
/// 获取当前生效的旋转关节自由度数量。
|
|
/// </summary>
|
|
[JsonPropertyName("degreesOfFreedom")]
|
|
public int DegreesOfFreedom { get; }
|
|
|
|
/// <summary>
|
|
/// 获取按关节校验后的运动学约束。
|
|
/// </summary>
|
|
[JsonPropertyName("jointLimits")]
|
|
public IReadOnlyList<JointLimit> JointLimits { get; }
|
|
|
|
/// <summary>
|
|
/// 获取从机器人模型解析出的可选关节耦合元数据。
|
|
/// </summary>
|
|
[JsonPropertyName("jointCouplings")]
|
|
public IReadOnlyList<JointCoupling> JointCouplings { get; }
|
|
|
|
/// <summary>
|
|
/// 获取运行时使用的伺服调度周期。
|
|
/// </summary>
|
|
[JsonPropertyName("servoPeriod")]
|
|
public TimeSpan ServoPeriod { get; }
|
|
|
|
/// <summary>
|
|
/// 获取飞拍事件对齐使用的触发调度周期。
|
|
/// </summary>
|
|
[JsonPropertyName("triggerPeriod")]
|
|
public TimeSpan TriggerPeriod { get; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// 描述规划器所需的单个旋转关节约束集合。
|
|
/// </summary>
|
|
public sealed class JointLimit
|
|
{
|
|
/// <summary>
|
|
/// 初始化一个已校验的关节约束记录。
|
|
/// </summary>
|
|
public JointLimit(string jointName, double velocityLimit, double accelerationLimit, double jerkLimit)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(jointName))
|
|
{
|
|
throw new ArgumentException("Joint name is required.", nameof(jointName));
|
|
}
|
|
|
|
if (velocityLimit <= 0.0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(velocityLimit), "Velocity limit must be positive.");
|
|
}
|
|
|
|
if (accelerationLimit <= 0.0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(accelerationLimit), "Acceleration limit must be positive.");
|
|
}
|
|
|
|
if (jerkLimit <= 0.0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(jerkLimit), "Jerk limit must be positive.");
|
|
}
|
|
|
|
JointName = jointName;
|
|
VelocityLimit = velocityLimit;
|
|
AccelerationLimit = accelerationLimit;
|
|
JerkLimit = jerkLimit;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取该约束对应的关节名称。
|
|
/// </summary>
|
|
[JsonPropertyName("jointName")]
|
|
public string JointName { get; }
|
|
|
|
/// <summary>
|
|
/// 获取关节空间单位下的速度上限。
|
|
/// </summary>
|
|
[JsonPropertyName("velocityLimit")]
|
|
public double VelocityLimit { get; }
|
|
|
|
/// <summary>
|
|
/// 获取关节空间单位下的加速度上限。
|
|
/// </summary>
|
|
[JsonPropertyName("accelerationLimit")]
|
|
public double AccelerationLimit { get; }
|
|
|
|
/// <summary>
|
|
/// 获取关节空间单位下的跃度上限。
|
|
/// </summary>
|
|
[JsonPropertyName("jerkLimit")]
|
|
public double JerkLimit { get; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// 描述在运动学计算或轨迹规划前必须应用的关节耦合规则。
|
|
/// </summary>
|
|
public sealed class JointCoupling
|
|
{
|
|
/// <summary>
|
|
/// 初始化一个已校验的关节耦合描述。
|
|
/// </summary>
|
|
public JointCoupling(string slaveJointName, string masterJointName, double multiplier, double offset)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(slaveJointName))
|
|
{
|
|
throw new ArgumentException("Slave joint name is required.", nameof(slaveJointName));
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(masterJointName))
|
|
{
|
|
throw new ArgumentException("Master joint name is required.", nameof(masterJointName));
|
|
}
|
|
|
|
if (string.Equals(slaveJointName, masterJointName, StringComparison.Ordinal))
|
|
{
|
|
throw new ArgumentException("Slave and master joints must be different.");
|
|
}
|
|
|
|
SlaveJointName = slaveJointName;
|
|
MasterJointName = masterJointName;
|
|
Multiplier = multiplier;
|
|
Offset = offset;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取从属(被驱动)关节名称。
|
|
/// </summary>
|
|
[JsonPropertyName("slaveJointName")]
|
|
public string SlaveJointName { get; }
|
|
|
|
/// <summary>
|
|
/// 获取主导(驱动)关节名称。
|
|
/// </summary>
|
|
[JsonPropertyName("masterJointName")]
|
|
public string MasterJointName { get; }
|
|
|
|
/// <summary>
|
|
/// 获取作用在主导关节角度上的耦合倍率。
|
|
/// </summary>
|
|
[JsonPropertyName("multiplier")]
|
|
public double Multiplier { get; }
|
|
|
|
/// <summary>
|
|
/// 获取在耦合倍率之后叠加的偏移量。
|
|
/// </summary>
|
|
[JsonPropertyName("offset")]
|
|
public double Offset { get; }
|
|
}
|