Skip to content

4.7 Trajectory Control

4.7.1 Setting the Offline Trajectory File

Method NameTrajectory.SetOffLineTrajectoryFile(string path )
DescriptionSets the offline trajectory file to be executed.
Request Parameterspath : string Offline trajectory file path, such as example file A.trajectory
A.trajectory trajectory file format is a text file, described as follows:
- Line 1: 6 represents 6 axes, 0.001 represents 1ms interval between two points, 8093 represents a total of 8093 trajectory points
- Line 2: Represents the initial positions of the 6 axes
- Lines 3-8095: Represent trajectory points, including positions, velocities, accelerations, torque feedforward, do ports, and values of do ports for the 6 axes
- do_port represents the used do port (range 1-24)
- do_port is -1, indicating no IO signal will be triggered at this position
- do_port is 1, do_state is 1, indicating do1 port will trigger ON signal at this position
- do_port is 1, do_state is 0, indicating do1 port will trigger OFF signal at this position
Users upload the offline file to the robot controller root directory using FileManager.upload, then execute the trajectory using instructions 4.7.2 and 4.7.3
Return ValueStatusCode: Set operation execution result
Compatible robot software versionCollaborative (Copper): v7.5.0.0+
Industrial (Bronze): v7.5.0.0+

4.7.2 Moving the Robot to the Start Point of the Offline Trajectory

Method NameTrajectory.PrepareOfflineTrajectory()
DescriptionMoves the robot to the start point of the offline trajectory at a safe speed.
Request ParametersNone
Return ValueStatusCode: Prepare operation execution result
Compatible robot software versionCollaborative (Copper): v7.5.0.0+
Industrial (Bronze): v7.5.0.0+

4.7.3 Starting Execution of the Offline Trajectory File

Method NameTrajectory.ExecuteOfflineTrajectory()
DescriptionStarts the execution of the offline trajectory file.
Request ParametersNone
Return ValueStatusCode: Execute operation execution result
Compatible robot software versionCollaborative (Copper): v7.5.0.0+
Industrial (Bronze): v7.5.0.0+

4.7.4 Convert CSV Trajectory File to Trajectory Format

MethodTrajectory.TransformCsvToTrajectory(string fileName )
DescriptionConverts a trajectory CSV file into the trajectory format and saves it to the controller's trajectory file directory.
Request ParameterfileName : string – name of the CSV trajectory file.
Return Valuestring: path of the converted trajectory file.
StatusCode: result of the conversion operation.
Compatible Robot Software VersionsCollaborative (Copper): v7.5.0.0+
Industrial (Bronze): v7.5.0.0+

4.7.5 Query Trajectory Conversion Status

MethodTrajectory.CheckTransformStatus(string fileName )
DescriptionQueries the working status of the TransformCsvToTrajectory process.
Request ParameterfileName : string – result returned by the TransformCsvToTrajectory interface.
Return ValueTransformState: conversion state.
StatusCode: result of the query operation.
Compatible Robot Software VersionsCollaborative (Copper): v7.5.0.0+
Industrial (Bronze): v7.5.0.0+

Example Code

Trajectory/OfflineTrajectory.cs
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;
    }
}