4.7 轨迹控制
概述
Trajectory 模块提供离线轨迹执行、轨迹文件转换的接口,支持复杂轨迹的复现。
核心功能
- 支持设置和执行离线轨迹文件
- 支持以安全速度将机器人移动到离线轨迹起始点
- 支持 CSV 到 trajectory 格式的文件转换
- 支持查询轨迹文件转换状态
使用场景
- 实现复杂轨迹的精确复现
- 转换外部轨迹数据为机器人可执行格式
4.7.1 设置待执行的离线轨迹文件
| 方法名 | Trajectory.SetOffLineTrajectoryFile(string path ) |
|---|---|
| 描述 | 设置待执行的离线轨迹文件 |
| 请求参数 | path : string 离线轨迹文件程序名 (格式说明见下方备注) |
| 返回值 | StatusCode: 函数执行结果 |
| 备注 | A.trajectory 轨迹文件格式为文本文件: - 第 1 行:6 代表 6 个轴,0.001 代表两点间隔 1 ms,8093 代表轨迹点数。 - 第 2 行:6 个轴的起始位置。 - 第 3-8095 行:轨迹点数据,包含 6 轴的位置 / 速度 / 加速度 / 力矩前馈 /do 端口 /do 端口值。 - do_port 取值范围 1~24;do_port 为 -1 表示该位置不触发 IO;do_port 为 1 且 do_state 为 1 表示 do1 端口触发 ON;do_port 为 1 且 do_state 为 0 表示 do1 端口触发 OFF。 用户通过 FileManager.upload 将离线文件发送到机器人控制器根目录,用 4.7.2 和 4.7.3 指令执行轨迹。 |
| 兼容的机器人软件版本 | 协作 (Copper): v7.5.0.0+ 工业 (Bronze): v7.5.0.0+ |
4.7.2 让机器人以安全速度移动到离线轨迹中的起始点
| 方法名 | Trajectory.PrepareOfflineTrajectory() |
|---|---|
| 描述 | 让机器人以安全速度移动到离线轨迹中的起始点 |
| 请求参数 | 无参数 |
| 返回值 | StatusCode: 函数执行结果 |
| 兼容的机器人软件版本 | 协作 (Copper): v7.5.0.0+ 工业 (Bronze): v7.5.0.0+ |
4.7.3 让机器人开始执行离线轨迹文件
| 方法名 | Trajectory.ExecuteOfflineTrajectory() |
|---|---|
| 描述 | 让机器人开始执行离线轨迹程序 |
| 请求参数 | 无参数 |
| 返回值 | StatusCode: 函数执行结果 |
| 兼容的机器人软件版本 | 协作 (Copper): v7.5.0.0+ 工业 (Bronze): v7.5.0.0+ |
4.7.4 轨迹文件转换功能
| 方法名 | Trajectory.TransformCsvToTrajectory(string fileName ) |
|---|---|
| 描述 | 将轨迹 CSV 文件转换成 trajectory 格式的轨迹文件并存放在控制柜的轨迹文件目录上 |
| 请求参数 | fileName : string CSV 轨迹文件名 (无需 .csv 后缀) |
| 返回值 | string:转换后轨迹文件路径 StatusCode: 函数执行结果 |
| 兼容的机器人软件版本 | 协作 (Copper): v7.5.0.0+ 工业 (Bronze): v7.5.0.0+ |
4.7.5 查询轨迹文件转换状态
| 方法名 | Trajectory.CheckTransformStatus(string fileName ) |
|---|---|
| 描述 | 查询轨迹文件转换的当前状态 |
| 请求参数 | fileName : string 轨迹文件路径 ( TransformCsvToTrajectory 接口返回) |
| 返回值 | TransformState: 转换状态 StatusCode: 函数执行结果 |
| 兼容的机器人软件版本 | 协作 (Copper): v7.5.0.0+ 工业 (Bronze): v7.5.0.0+ |
示例代码
cs
using System.IO;
using Agilebot.IR;
using Agilebot.IR.Trajectory;
using Agilebot.IR.Types;
public class OfflineTrajectory
{
public static StatusCode Run(string controllerIP, bool useLocalProxy = true)
{
// [ZH] 初始化捷勃特机器人
// [EN] Initialize the Agilebot robot
Arm controller = new Arm(controllerIP, useLocalProxy);
// [ZH] 连接捷勃特机器人
// [EN] Connect to the Agilebot robot
StatusCode code = controller.ConnectSync();
Console.WriteLine(code != StatusCode.OK ? code.GetDescription() : "连接成功/Successfully connected.");
if (code != StatusCode.OK)
{
return code;
}
try
{
// [ZH] 获取机器人模式
// [EN] Get robot mode
(UserOpMode opMode, StatusCode opCode) = controller.GetOpMode();
if (opCode == StatusCode.OK)
{
Console.WriteLine($"当前机器人模式/Current robot mode: {opMode}");
if (opMode != UserOpMode.AUTO)
{
Console.WriteLine(
$"离线轨迹执行必须在机器人自动模式下/Offline trajectory execution must be in automatic mode"
);
return StatusCode.OtherReason;
}
}
else
{
Console.WriteLine($"获取机器人模式失败/Failed to get robot mode: {opCode.GetDescription()}");
}
// [ZH] 添加程序文件到机器人中
// [EN] Add program file to robot
string file_user_program = GetTestFilePath("test.csv");
StatusCode ret_code = controller.FileManager.Upload(file_user_program, FileType.TmpFile, true);
if (ret_code != StatusCode.OK)
{
Console.WriteLine($"上传文件失败/Upload file failed: {ret_code.GetDescription()}");
return ret_code;
}
Console.WriteLine("文件上传成功/File upload success");
// [ZH] 测试CSV转换为轨迹文件功能
// [EN] Test CSV to trajectory file conversion functionality
string csvFilename = "test.csv";
(string trajFileName, StatusCode transformCode) = controller.Trajectory.TransformCsvToTrajectory(
csvFilename
);
if (transformCode != StatusCode.OK)
{
Console.WriteLine($"CSV转换失败/CSV conversion failed: {transformCode.GetDescription()}");
return transformCode;
}
Console.WriteLine($"CSV转换成功/CSV conversion success, trajectory file: {trajFileName}");
// [ZH] 检查转换状态
// [EN] Check conversion status
var startTime = System.DateTime.Now;
TransformState state;
StatusCode statusCode;
do
{
(state, statusCode) = controller.Trajectory.CheckTransformStatus(
System.IO.Path.GetFileName(trajFileName)
);
if (statusCode != StatusCode.OK)
{
Console.WriteLine($"检查转换状态失败/Check transform status failed: {statusCode.GetDescription()}");
return statusCode;
}
Console.WriteLine($"转换状态/Transform state: {state}");
Thread.Sleep(2000); // 等待2秒
if (System.DateTime.Now - startTime > System.TimeSpan.FromSeconds(60))
{
Console.WriteLine("转换状态检查超时/Transform status check timeout");
break;
}
} while (state != TransformState.TRANSFORM_SUCCESS && state != TransformState.TRANSFORM_FAILED);
if (state == TransformState.TRANSFORM_FAILED)
{
Console.WriteLine("CSV转换失败/CSV conversion failed");
return StatusCode.OtherReason;
}
// [ZH] 转换任务成功并进行了结果查询后 服务端不会继续保存转换任务的状态
// [EN] After the conversion task is successful and the result is queried, the server will not continue to save the conversion task status
(TransformState finalState, StatusCode finalCode) = controller.Trajectory.CheckTransformStatus(
System.IO.Path.GetFileName(trajFileName)
);
if (finalCode != StatusCode.OK)
{
Console.WriteLine($"最终状态检查失败/Final status check failed: {finalCode.GetDescription()}");
return finalCode;
}
Console.WriteLine($"最终转换状态/Final transform state: {finalState}");
// [ZH] 设置轨迹文件
// [EN] Set trajectory file
code = controller.Trajectory.SetOffLineTrajectoryFile("test_torque.trajectory");
if (code != StatusCode.OK)
{
Console.WriteLine($"设置轨迹文件失败/Set trajectory file failed: {code.GetDescription()}");
return code;
}
Console.WriteLine("设置轨迹文件成功/Set trajectory file success");
// [ZH] 准备离线轨迹
// [EN] Prepare offline trajectory
code = controller.Trajectory.PrepareOfflineTrajectory();
if (code != StatusCode.OK)
{
Console.WriteLine($"准备离线轨迹失败/Prepare offline trajectory failed: {code.GetDescription()}");
return code;
}
Console.WriteLine("准备离线轨迹成功/Prepare offline trajectory success");
// [ZH] 等待机器人和伺服器空闲
// [EN] Wait for robot and servo to be idle
startTime = System.DateTime.Now;
RobotState robotStatus;
ServoState servoStatus;
StatusCode robotStatusCode;
StatusCode servoStatusCode;
do
{
(robotStatus, robotStatusCode) = controller.GetRobotState();
if (robotStatusCode != StatusCode.OK)
{
Console.WriteLine($"获取机器人状态失败/Get robot state failed: {robotStatusCode.GetDescription()}");
return robotStatusCode;
}
(servoStatus, servoStatusCode) = controller.GetServoState();
if (servoStatusCode != StatusCode.OK)
{
Console.WriteLine($"获取伺服状态失败/Get servo state failed: {servoStatusCode.GetDescription()}");
return servoStatusCode;
}
Console.WriteLine($"机器人状态/Robot state: {robotStatus}, 伺服状态/Servo state: {servoStatus}");
if (robotStatus == RobotState.ROBOT_IDLE && servoStatus == ServoState.SERVO_IDLE)
{
Console.WriteLine("机器人和伺服器已空闲/Robot and servo are idle");
break;
}
Thread.Sleep(2000); // 等待2秒
if (System.DateTime.Now - startTime > System.TimeSpan.FromSeconds(60))
{
Console.WriteLine("等待机器人和伺服器空闲超时/Waiting for robot and servo idle timeout");
break;
}
} while (true);
// [ZH] 执行离线轨迹
// [EN] Execute offline trajectory
code = controller.Trajectory.ExecuteOfflineTrajectory();
if (code == StatusCode.OK)
{
Console.WriteLine("执行离线轨迹成功/Execute offline trajectory success");
Console.WriteLine("机器人开始执行轨迹程序/Robot started executing trajectory program");
}
else
{
Console.WriteLine($"执行离线轨迹失败/Execute offline trajectory failed: {code.GetDescription()}");
}
}
catch (Exception ex)
{
Console.WriteLine(
$"执行过程中发生异常/Exception occurred during execution/Exception occurred during execution: {ex.Message}"
);
code = StatusCode.OtherReason;
}
finally
{
// [ZH] 关闭连接
// [EN] Close the connection
StatusCode disconnectCode = controller.Disconnect();
if (disconnectCode != StatusCode.OK)
{
Console.WriteLine(disconnectCode.GetDescription());
if (code == StatusCode.OK)
code = disconnectCode;
}
}
return code;
}
/// <summary>
/// 获取test_files文件夹中文件的路径示例方法
/// 展示如何获取当前程序目录下的test_files文件夹中的文件路径
/// </summary>
private static string GetTestFilePath(string fileName)
{
// 获取当前程序集的目录
string? codeFilePath = new System.Diagnostics.StackTrace(true).GetFrame(0)?.GetFileName();
if (string.IsNullOrEmpty(codeFilePath))
{
throw new InvalidOperationException("无法获取当前文件路径/Cannot get current file path");
}
string? codeDirectory = Path.GetDirectoryName(codeFilePath);
if (string.IsNullOrEmpty(codeDirectory))
{
throw new InvalidOperationException("无法获取当前目录路径/Cannot get current directory path");
}
// 构建test_files文件夹路径
string testFilesDirectory = Path.Combine(codeDirectory, "test_files");
// 构建文件完整路径
string filePath = Path.Combine(testFilesDirectory, fileName);
return filePath;
}
}