发布时间: 2026-01-16
CS 机器人 C++ SDK 快速使用手册
CS 机器人 C++ SDK 快速使用手册
1. 简介
本手册着重于使用SDK的环境配置。
1.1 SDK 概述
此SDK是艾利特机器人CS系列机械臂的C++库,借助该库,开发者可以基于C++实现驱动程序,从而充分利用艾利特机器人CS系列机械臂的多功能性来开发外部应用程序。
1.1.1 支持的操作系统
此SDK支持Windows与Linux操作系统,具体使用参考后文。
1.1.2 支持的机器人软件版本
SDK版本与适配的机器人软件版本的对应关系如下:
SDK版本 | 机器人软件 |
|---|---|
v1.1.0 | >=2.10.x |
v1.2.0 | >= 2.13.4 或 >= 2.14.2 |
v1.3.0 | >= 2.15.0 |
如果在表中没有找到你的SDK版本,可以到github仓库选择你的SDK版本的tag,查阅README文件了解所需的机器人软件版本,如下图所示:
1.1.3 支持的C++标准
本SDK最低支持C++14标准。
注意:C++14标准下SDK在使用过程中依赖boost库(headonly),而C++17以上标准则不需要。
2. 环境准备
2.1 Ubuntu 安装SDK
对于不同的Ubuntu发行版,推荐采用以下安装方式:
2.1.1 使用apt安装
对于 Ubuntu 发行版:Ubuntu 20.04 至 Ubuntu 24.04 我们已将SDK上传至ppa源中,支持 x86_64 以及 arm64 架构,可以使用下面的指令直接安装:
sudo add-apt-repository ppa:elite-robots/cs-robot-series-sdk
sudo apt update
sudo apt install elite-cs-series-sdk如果需要卸载,推荐使用下面的指令:
sudo dpkg --remove elite-cs-series-sdk如果要升级SDK,建议先卸载,再执行
sudo apt install elite-cs-series-sdk重新安装。注意:此方法安装的SDK的C++编译标准为C++17。
2.1.2 Ubuntu 使用预编译包安装
对于 Ubuntu 发行版:Ubuntu 18.04 与 Ubuntu 16.04 我们提供了 X86_64 的预编译版本,在此处可以下载。下载完成后使用下面指令进行解压:
tar -zxvf <package.name.tar.gz>使用下面指令将库拷贝到系统路径中(建议逐条执行,注意替换解压后的路径):
cd <package.name.directory/>
sudo cp -r cmake/elite-cs-series-sdk /usr/local/lib/cmake/
sudo cp -r include/Elite /usr/local/include/
sudo cp lib/libelite-cs-series-sdk.* /usr/local/lib/
sudo mkdir /usr/local/share/Elite/
sudo cp resource/external_control.script /usr/local/share/Elite/
sudo ldconfig使用下面指令安装依赖库:
sudo apt install libboost-dev libssh-dev注意:此方法安装的SDK的C++编译标准为C++14。
可能遇到的问题:
- 在执行拷贝指令的过程中,如果出现
/usr/local/目录下的Not a directory类似的报错,直接创建一个对应的目录就行,例如:如果出现cp: cannot create regular file '/usr/local/lib/cmake/': Not a directory的报错,就直接创建目录:sudo mkdir /usr/local/lib/cmake/。
2.2 其余Linux发行版
对于其余的Linux发行版,目前还没有安装包或者预编译包的支持,需要用户编译安装。
2.3 Linux 上的编译安装
此处以 Ubuntu 为例,与其他Linux发行版的区别只存在于安装依赖、编译工具等的方式不同。
执行下面指令安装编译工具:
sudo apt update
sudo apt install build-essential cmake git执行下面指令安装依赖:
sudo apt install libboost-dev libssh-dev执行下面指令下载代码(建议逐条执行):
git clone https://github.com/Elite-Robots/Elite_Robots_CS_SDK.git
cd Elite_Robots_CS_SDK/
git checkout vX.Y.Z # 替换为你需要的版本例如 v1.2.0执行下面的指令编译并安装(建议逐条执行,执行过程中没有出现报错可视为成功):
mkdir build && cd build
cmake -DELITE_COMPILE_EXAMPLES=TRUE ..
make -j4
sudo make install可能遇到的问题:
- 执行
cmake -DELITE_COMPILE_EXAMPLES=TRUE ..出现类似下面的报错:CMake Error at CMakeLists.txt:1 (cmake_minimum_required): CMake 3.16 or higher is required. You are running version 3.xx此问题是cmake版本低于设置的版本,可以尝试下面步骤:- 执行
cmake --version获取你的cmake版本 - 修改SDK根目录下的“CMakeLists.txt”文件顶部
cmake_minimum_required(VERSION 3.16)语句,将版本号修改为你的cmake版本号 - 再次执行
cmake -DELITE_COMPILE_EXAMPLES=TRUE ..
如果出现了其他错误,则需要将SDK根目录下的“CMakeLists.txt”文件复原,然后升级你的cmake版本大于等于3.16。
- 执行
make -j4出现下面的报错:error: ‘variant’ in namespace ‘std’ does not name a template type此问题是你的编译器不支持C++17标准或支持得不完善,建议升级支持完整C++17标准的编译器。如果无法升级,则可以使用下面指令编译安装:cmake -DELITE_COMPILE_EXAMPLES=TRUE -DCMAKE_CXX_STANDARD=14 .. make -j4 sudo make install注意: C++14标准下使用SDK需要依赖boost库(headonly)。
2.4 Linux 中使用 SDK
复制下面代码,使用你习惯的文本编辑器,粘贴到
dashboard_example.cpp中:#include <iostream>
#include <memory>
#include <string>
#include <Elite/DashboardClient.hpp>
using namespace ELITE;
int main(int argc, char* argv[]) {
if (argc < 2) {
std::cout << "Must provide robot IP. Example: ./dashboard_example aaa.bbb.ccc.ddd" << std::endl;
return 1;
}
std::string robot_ip = argv[1];
std::unique_ptr<DashboardClient> my_dashboard;
my_dashboard.reset(new DashboardClient());
if (!my_dashboard->connect(robot_ip)) {
std::cout << "Could not connect to robot" << std::endl;
return 1;
} else {
std::cout << "Connect to robot" << std::endl;
}
// Power on
if (!my_dashboard->powerOn()) {
std::cout << "Could not send Power on command" << std::endl;
return 1;
} else {
std::cout << "Power on" << std::endl;
}
// Brake release
if (!my_dashboard->brakeRelease()) {
std::cout << "Could not send BrakeRelease command" << std::endl;
return 1;
} else {
std::cout << "Brake release" << std::endl;
}
my_dashboard->disconnect();
return 0;
}使用下面指令编译此代码,注意如果你的编译器不支持C++17,需要修改下面指令中C++标准:
g++ dashboard_example.cpp -o dashboard_example -lelite-cs-series-sdk --std=c++17如果没有报错,则表示编译成功了。要执行编译出来的程序,请跳转机器人配置章节继续阅读。
2.5 Windows 使用预编译包
对于 Windows 我们提供了 X86_64 的预编译版本,在此处可以下载。下载完成后解压得到如下的文件,后文配置SDK到Visual Studio工程会使用到这些文件:
- include
- Elite: SDK 的头文件
- lib
- Debug:debug版本的库文件(dll、lib)
- Release:release版本的库文件(dll、lib)
- resource
- external_control.script :控制脚本。
导入 Visual Studio 的步骤可参考后文。
2.6 Windows 下编译SDK
2.6.1 安装工具
2.6.2 安装依赖
使用 vcpkg 来作为Windows平台下的包管理器,在Windows的终端中运行下面指令下载vcpkg:
git clone https://github.com/microsoft/vcpkg.git
cd vcpkg
.\bootstrap-vcpkg.bat如果没有输出 error 则代表成功安装了vcpkg,成功的输出大致如下:
Downloading https://github.com/microsoft/vcpkg-tool/releases/download/2025-07-21/vcpkg.exe -> C:\Users\cc\vcpkg\vcpkg.exe (using IE proxy: 127.0.0.1:7890)... done.
Validating signature... done.
vcpkg package management program version 2025-07-21-d4b65a2b83ae6c3526acd1c6f3b51aff2a884533
See LICENSE.txt for license information.
Telemetry
---------
vcpkg collects usage data in order to help us improve your experience.
The data collected by Microsoft is anonymous.
You can opt-out of telemetry by re-running the bootstrap-vcpkg script with -disableMetrics,
passing --disable-metrics to vcpkg on the command line,
or by setting the VCPKG_DISABLE_METRICS environment variable.
Read more about vcpkg telemetry at docs/about/privacy.md使用下面指令安装依赖库:
.\vcpkg install boost-asio
.\vcpkg install boost-program-options
.\vcpkg install libssh如果安装成功会输出:
All requested installations completed successfully in: 4.26 ms执行下面指令配置到 Visual Studio:
.\vcpkg integrate install配置成功将会输出:
CMake projects should use: "-DCMAKE_TOOLCHAIN_FILE=C:/Users/cc/vcpkg/scripts/buildsystems/vcpkg.cmake"
All MSBuild C++ projects can now #include any installed libraries. Linking will be handled automatically. Installing new libraries will make them instantly available.此处提示
CMake projects should use,复制你的输出里“=”号后面的路径,以上面的输出为例是:C:/Users/cc/vcpkg/scripts/buildsystems/vcpkg.cmake2.6.3 下载代码并编译
执行下面指令下载代码(建议逐条执行):
git clone https://github.com/Elite-Robots/Elite_Robots_CS_SDK.git
cd Elite_Robots_CS_SDK/
git checkout vX.Y.Z # 替换为你需要的版本例如 v1.2.0执行下面的指令,注意将/your/path替换成刚刚复制的路径:
mkdir build
cd build
cmake -DCMAKE_TOOLCHAIN_FILE=/your/path -DELITE_COMPILE_EXAMPLES=TRUE ..
cmake --build . --config Release # 编译 release 版本
cmake --build . --config Debug # 编译 debug 版本如果没有error输出,则代表成功。成功后需要留意以下文件,后文配置sdk到visual-studio工程会使用到这些文件:
- ./Debug:debug版本的库文件(dll、lib)
- ./Release:release版本的库文件(dll、lib)
- ./include/Elite:SDK 的头文件
- ../source/resources/external_control.script:控制脚本。
2.7 配置SDK到Visual Studio工程
- 打开Visual Studio,选择创建新项目。
- 选择语言为C++,选择控制台应用,最后点击下一步。
- 设置项目名称、保存路径等,点击创建
- 拷贝库到项目里
- 在项目目录中新建一个文件夹
elite-cs-sdk
- 对于下载预编译包的用户:
- 拷贝
lib中的Debug和Release文件夹到elite-cs-sdk中 - 拷贝
resource到elite-cs-sdk中 - 拷贝
include中的Elite文件夹到elite-cs-sdk中
- 对于手动编译的用户(
Elite_Robots_CS_SDK根目录):- 拷贝
build/Debug和build/Release文件夹到elite-cs-sdk中 - 拷贝
source/resource到elite-cs-sdk中 - 拷贝
build/include/Elite文件夹到elite-cs-sdk中
- 拷贝完成后,
elite-cs-sdk文件夹的结构如下:. ├── Debug ├── Elite ├── Release └── resources
- 菜单栏选择“项目” --> “属性”
- 选择“配置”:“所有配置”,选择“常规”,设置C++标准为C++17
- 选择“VC++ 目录” --> 外部包含目录 --> 编辑
- 设置路径为第四步中的
elite-cs-sdk文件夹 - 调整配置为“Debug”,选择“VC++ 目录”,选择“库目录”
- 设置路径为第四步中的
elite-cs-sdk/Debug文件夹 - 调整配置为“Release”,选择“VC++ 目录”,选择“库目录”
- 设置路径为第四步中的
elite-cs-sdk/Release文件夹 - 调整配置为“所有配置”,选择“链接器” --> “输入” --> “附加依赖项目”
- 填入
elite-cs-series-sdk.lib - 复制下面代码,粘贴到VS中:
#include <iostream> #include <memory> #include <string> #include <Elite/DashboardClient.hpp> using namespace ELITE; int main(int argc, char* argv[]) { if (argc < 2) { std::cout << "Must provide robot IP. Example: ./dashboard_example aaa.bbb.ccc.ddd" << std::endl; return 1; } std::string robot_ip = argv[1]; std::unique_ptr<DashboardClient> my_dashboard; my_dashboard.reset(new DashboardClient()); if (!my_dashboard->connect(robot_ip)) { std::cout << "Could not connect to robot" << std::endl; return 1; } else { std::cout << "Connect to robot" << std::endl; } // Power on if (!my_dashboard->powerOn()) { std::cout << "Could not send Power on command" << std::endl; return 1; } else { std::cout << "Power on" << std::endl; } // Brake release if (!my_dashboard->brakeRelease()) { std::cout << "Could not send BrakeRelease command" << std::endl; return 1; } else { std::cout << "Brake release" << std::endl; } my_dashboard->disconnect(); return 0; } - 菜单栏选择“生成”-->“生成解决方案”,编译成功将不会报错。编译完成后,在解决方案的目录下会出现
x64的文件夹。
如果你的编译模式是 Release 则路径中的 Debug 要换为 Release
3. 机器人配置
3.1 网络配置
3.1.1 CS 控制柜
对于 CS 标准系列控制柜需要将FB1、FB2两个网口接入到局域网中,并设置好IP。
可能存在的疑问:
- 为什么要连接两个网口?因为此系列控制柜使用了双处理器的分布式架构,FB1和FB2各对应一个处理器,与SDK进行通讯的控制软件运行在FB2处理器上,而机器人的 dashboard 功能运行在FB1处理器上,因此需要连接两个网口。不过在 2.14.3 版本后,使用 SDK 的 headless 模式(此模式后文介绍)可以只连接FB2网口。
3.1.2 CS_X 控制柜
对于 CS_X 系列控制柜,只有一个网口,因此只要连接着一个网口就可以。
3.2 设置远程控制模式
点击示教器右上角的汉堡菜单,选择设置:

启用/禁用远程控制模式,然后点击左下角退出按钮:

如果选择了启用远程控制模式,此时的界面的右侧栏会出现“本地控制”的选项,切换到“远程控制”。

tips:CS 系列机器人如果远程控制模式是禁用状态,则会处于“混合模式”,即既可以接收外部的控制,也可以接收示教器本地的控制,因此在上面步骤中,远程控制模式可以设为禁用。
3.3 测试网络连接
此处提供了两种可以测试SDK是否能和机器人通讯的方式:
推荐使用第一种方法,如果方法1能跑通,那机器人的配置基本就没有问题了。
3.3.1 使用机器人脚本(推荐)
- 在要运行SDK的操作系统中执行下面指令:
- Linux
ifconfig - Windows:
ipconfig记录下与机器人相连网口的IP,记为 Local IP。
可能遇到的问题:- Linux中执行
ifconfig时可能会出现找不到命令的提示,此时需要安装一下此指令,例如在Ubuntu中使用sudo apt install net-tools指令安装。
- 点击示教器左侧栏的“任务”。
- 点击“占位节点”,点击“高级”-->“脚本”。
- 点击左侧下拉框,选择“文件”,点击“编辑”
- 将下面内容写入文本编辑器中,注意,替换IP地址为刚刚记下的 Local IP:
socket_open("Your.Robot.IP.Addr", 50001) socket_send_string("Hello SDK\n") sleep(1) - 点击保存,并设置文件名
- 可以用你习惯的方式,在要运行SDK的操作系统中创建一个端口为50001的TCP服务。这里提供了一个python脚本,你可以把它复制到“sdk_connection_test.py”的文件中,然后执行
python3 sdk_connection_test.py执行运行此脚本。
import socket
def start_tcp_server(host='localhost', port=50001):
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
# 设置accept超时(1秒)
server_socket.settimeout(1.0)
server_socket.bind((host, port))
server_socket.listen(5)
print(f"TCP服务器启动在 {host}:{port},等待客户端连接...")
while True:
try:
# 接受客户端连接(现在会超时,让出控制权)
client_socket, client_address = server_socket.accept()
print(f"客户端 {client_address} 已连接")
try:
while True:
data = client_socket.recv(1024)
if not data:
print(f"客户端 {client_address} 已断开连接")
break
received_string = data.decode('utf-8')
print(f"来自 {client_address} 的数据: {received_string}")
except ConnectionResetError:
print(f"客户端 {client_address} 异常断开连接")
except Exception as e:
print(f"处理客户端 {client_address} 时发生错误: {e}")
finally:
client_socket.close()
except socket.timeout:
# 超时是正常的,继续循环
continue
except KeyboardInterrupt:
print("\n服务器被用户中断")
except Exception as e:
print(f"服务器发生错误: {e}")
finally:
server_socket.close()
print("服务器已关闭")
if __name__ == "__main__":
start_tcp_server()- 点击示教器上的任务运行按钮,如果一切正常,会看到TCP服务器接收到“Hello SDK”的一行字符串。
可能遇到的问题:
- 如果在创建TCP服务时失败,可能是你的系统中有其他程序占用了“50001”端口,如需换成别的端口,机器人脚本中的端口也要替换。
- 示教器提示:“socket_send_string”:未连接服务端“socket_0”。出现这个异常的原因是,机器人无法连接SDK的TCP服务端口。可能有下面的原因:
- 如果你使用了虚拟机,需要你把虚拟机的网卡设置为桥接,并桥接到与机器人相连的网卡上,然后设置好IP。
- 如果是CS 控制柜的用户,可能是没有连接FB2网口。
- 你的局域网将连接关闭了,建议将机器人与运行SDK的电脑直接连接,如果是CS控制柜用户,可以使用一个交换机将运行SDK的电脑、控制柜FB1、控制柜FB2接到一起。
- IP设置不正确,运行SDK的电脑的IP,与控制柜网口的IP没有在同一网段。
- 你的电脑开启了 VPN,建议关闭。
- 服务器没有启动成功,你的系统里的某些应用将50001端口占用,可以换一个端口,注意,不光服务器端口要改,机器人脚本的
socket_open指令里的端口号也要改。 - 服务器被关闭,有可能在你接收到“Hello SDK”的一行字符串后,你关闭了服务器,但此时机器人还在循环执行脚本。
- 如果上述情况确保没问题,但还是连不上,可以重启一下控制柜再尝试。
3.3.2 使用bash指令
在要运行SDK的操作系统中输入下面指令:
- Linux
ifconfig - Windows:
ipconfig
记录下与机器人相连网口的IP,记为 Local IP。
可能遇到的问题:
- Linux中执行
ifconfig时可能会出现找不到命令的提示,此时需要安装一下此指令,例如在Ubuntu中使用sudo apt install net-tools指令安装。
在要运行SDK的操作系统中运行下面指令,使用ssh登录到机器人的操作系统里,注意替换
aaa.bbb.ccc.ddd为机器人IP(如果是CS系列控制,则为FB2的IP),密码为elibot:ssh root@aaa.bbb.ccc.ddd登录上去之后输入下面指令,注意替换
aaa.bbb.ccc.ddd为刚刚记录下的Local IP,此操作可简单检查机器人是否能连接上SDK。ping aaa.bbb.ccc.ddd如果能ping通,则会有类似下面的输出:
PING 192.168.1.110 (192.168.1.110): 56 data bytes
64 bytes from 192.168.1.110: seq=0 ttl=64 time=0.373 ms
64 bytes from 192.168.1.110: seq=1 ttl=64 time=0.409 ms
64 bytes from 192.168.1.110: seq=2 ttl=64 time=0.397 ms
64 bytes from 192.168.1.110: seq=3 ttl=64 time=0.432 ms如果无法ping通,则需要检查网络设置,例如:IP地址是否冲突,SDK所在系统、机器人是否在同一个网段里,所在的局域网环境。
输入
exit退出登录,回到要运行SDK的操作系统中,执行下面指令,简单检查SDK是否能连接上机器人,注意替换aaa.bbb.ccc.ddd为机器人IP(如果是CS 标准系列控制柜,需要ping通FB1和FB2)。ping aaa.bbb.ccc.ddd4. SDK 使用
4.1 执行先前的编译结果
在“环境准备”章节中我们编译了一个简单的代码,现在我们来运行那个程序。为了更好的展示运行效果,建议将机械臂下电:
4.1.1 Linux
在前面的步骤中,已经将
dashboard_example.cpp编译为dashboard_example可执行程序,使用下面指令运行这个程序,注意替换机器人IP地址:./dashboard_example Your.Robot.IP.Addr如果执行成功,会看到机器人上电并释放抱闸。
4.1.2 Windows
- 在前面的步骤中,已经编译好了程序,在Visual Studio界面中,右键点击右侧栏你的项目名称,选择属性:
- 选择“配置属性”-->“调试”-->“命令参数”,设置参数为机器人IP,点击确定:
- 点击“本地 Windows 调试器”运行此程序:
- 程序成功运行后将会给机器人上电并释放抱闸。
4.1.3 简单说明
艾利特CS系列机器人提供了一个名为 Dashboard 的接口,提供了大量的界面操作接口,例如上下电,加载任务等。SDK封装了此功能。刚刚所运行的程序,就是调用了Dashboard的上电和释放抱闸两个接口。
4.2 使用SDK控制机器人运动
4.2.1 Linux
参考2.4章节,复制下面代码,使用你习惯的文本编辑器,粘贴到
move_example.cpp中:#include <Elite/DataType.hpp>
#include <Elite/EliteDriver.hpp>
#include <Elite/Log.hpp>
#include <Elite/DashboardClient.hpp>
#include <Elite/RtsiIOInterface.hpp>
#include <future>
#include <iostream>
#include <memory>
#include <thread>
using namespace ELITE;
class TrajectoryControl {
private:
std::unique_ptr<EliteDriver> driver_;
std::unique_ptr<DashboardClient> dashboard_;
EliteDriverConfig config_;
public:
TrajectoryControl(const EliteDriverConfig& config) {
config_ = config;
driver_ = std::make_unique<EliteDriver>(config);
dashboard_ = std::make_unique<DashboardClient>();
ELITE_LOG_INFO("Connecting to the dashboard");
if (!dashboard_->connect(config.robot_ip)) {
ELITE_LOG_FATAL("Failed to connect to the dashboard.");
throw std::runtime_error("Failed to connect to the dashboard.");
}
ELITE_LOG_INFO("Successfully connected to the dashboard");
}
~TrajectoryControl() {
if (dashboard_) {
dashboard_->disconnect();
}
driver_->stopControl();
}
bool startControl() {
ELITE_LOG_INFO("Start powering on...");
if (!dashboard_->powerOn()) {
ELITE_LOG_FATAL("Power-on failed");
return false;
}
ELITE_LOG_INFO("Power-on succeeded");
ELITE_LOG_INFO("Start releasing brake...");
if (!dashboard_->brakeRelease()) {
ELITE_LOG_FATAL("Brake release failed");
return false;
}
ELITE_LOG_INFO("Brake released");
if (config_.headless_mode) {
if (!driver_->isRobotConnected()) {
if (!driver_->sendExternalControlScript()) {
ELITE_LOG_FATAL("Fail to send external control script");
return false;
}
}
} else {
ELITE_LOG_FATAL("Must use headless mode");
return false;
}
ELITE_LOG_INFO("Wait external control script run...");
while (!driver_->isRobotConnected()) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
ELITE_LOG_INFO("External control script is running");
return true;
}
bool moveTrajectory(const std::vector<vector6d_t>& target_points, float point_time, float blend_radius, bool is_cartesian) {
std::promise<TrajectoryMotionResult> move_done_promise;
driver_->setTrajectoryResultCallback([&](TrajectoryMotionResult result) { move_done_promise.set_value(result); });
ELITE_LOG_INFO("Trajectory motion start");
if(!driver_->writeTrajectoryControlAction(ELITE::TrajectoryControlAction::START, target_points.size(), 200)) {
ELITE_LOG_ERROR("Failed to start trajectory motion");
return false;
}
for (const auto& joints : target_points) {
if (!driver_->writeTrajectoryPoint(joints, point_time, blend_radius, is_cartesian)) {
ELITE_LOG_ERROR("Failed to write trajectory point");
return false;
}
// Send NOOP command to avoid timeout.
if(!driver_->writeTrajectoryControlAction(ELITE::TrajectoryControlAction::NOOP, 0, 200)) {
ELITE_LOG_ERROR("Failed to send NOOP command");
return false;
}
}
std::future<TrajectoryMotionResult> move_done_future = move_done_promise.get_future();
while (move_done_future.wait_for(std::chrono::milliseconds(50)) != std::future_status::ready) {
// Wait for the trajectory motion to complete, and send NOOP command to avoid timeout.
if(!driver_->writeTrajectoryControlAction(ELITE::TrajectoryControlAction::NOOP, 0, 200)) {
ELITE_LOG_ERROR("Failed to send NOOP command");
return false;
}
}
auto result = move_done_future.get();
ELITE_LOG_INFO("Trajectory motion completed with result: %d", result);
if(!driver_->writeIdle(0)) {
ELITE_LOG_ERROR("Failed to write idle command");
return false;
}
return result == TrajectoryMotionResult::SUCCESS;
}
bool moveTo(const vector6d_t& point, float time, bool is_cartesian) {
return moveTrajectory({point}, time, 0, is_cartesian);
}
};
int main(int argc, const char** argv) {
EliteDriverConfig config;
if (argc == 2) {
config.robot_ip = argv[1];
} else if (argc == 3) {
config.robot_ip = argv[1];
config.local_ip = argv[2];
} else {
std::cout << "Must provide robot IP. Example: ./trajectory_example aaa.bbb.ccc.ddd <eee.fff.ggg.hhh>" << std::endl;
return 1;
}
config.headless_mode = true;
config.script_file_path = "external_control.script";
std::unique_ptr<TrajectoryControl> trajectory_control = std::make_unique<TrajectoryControl>(config);
std::unique_ptr<RtsiIOInterface> rtsi_client = std::make_unique<RtsiIOInterface>("output_recipe.txt", "input_recipe.txt", 250);
ELITE_LOG_INFO("Connecting to the RTSI");
if (!rtsi_client->connect(config.robot_ip)) {
ELITE_LOG_FATAL("Fail to connect or config to the RTSI.");
throw std::runtime_error("Fail to connect or config to the RTSI");
}
ELITE_LOG_INFO("Successfully connected to the RTSI");
ELITE_LOG_INFO("Starting trajectory control...");
if(!trajectory_control->startControl()) {
ELITE_LOG_FATAL("Failed to start trajectory control.");
return 1;
}
ELITE_LOG_INFO("Trajectory control started");
vector6d_t actual_joints = rtsi_client->getActualJointPositions();
actual_joints[3] = -1.57;
ELITE_LOG_INFO("Moving joints to target: [%lf, %lf, %lf, %lf, %lf, %lf]",
actual_joints[0], actual_joints[1], actual_joints[2], actual_joints[3], actual_joints[4], actual_joints[5]);
if(!trajectory_control->moveTo(actual_joints, 3, false)) {
ELITE_LOG_FATAL("Failed to move joints to target.");
return 1;
}
ELITE_LOG_INFO("Joints moved to target");
vector6d_t actual_pose = rtsi_client->getAcutalTCPPose();
std::vector<vector6d_t> trajectory;
actual_pose[2] -= 0.2;
trajectory.push_back(actual_pose);
actual_pose[1] -= 0.2;
trajectory.push_back(actual_pose);
actual_pose[1] += 0.2;
actual_pose[2] += 0.2;
trajectory.push_back(actual_pose);
ELITE_LOG_INFO("Moving joints to target");
if(!trajectory_control->moveTrajectory(trajectory, 3, 0, true)) {
ELITE_LOG_FATAL("Failed to move trajectory.");
return 1;
}
ELITE_LOG_INFO("Joints moved to target");
return 0;
}
使用下面指令编译此代码,注意如果你的编译器不支持C++17,需要修改下面指令中C++标准:
g++ move_example.cpp -o move_example -lelite-cs-series-sdk --std=c++17编译完成后,会出现名为
move_example的可执行文件。复制下面文本,使用你习惯的文本编辑器,粘贴到
output_recipe.txt中:timestamp
payload_mass
payload_cog
script_control_line
target_joint_positions
target_joint_speeds
actual_joint_torques
actual_joint_positions
actual_joint_speeds
actual_joint_current
actual_TCP_pose
actual_TCP_speed
actual_TCP_force
target_TCP_pose
target_TCP_speed
actual_digital_input_bits
actual_digital_output_bits
joint_temperatures
robot_mode
joint_mode
safety_status
speed_scaling
target_speed_fraction
actual_robot_voltage
actual_robot_current
runtime_state
elbow_position
robot_status_bits
safety_status_bits
analog_io_types
standard_analog_input0
standard_analog_input1
standard_analog_output0
standard_analog_output1
io_current
tool_mode
tool_analog_input_types
tool_analog_output_types
tool_analog_input
tool_analog_output
tool_output_voltage
tool_output_current
tool_temperature
tool_digital_mode
tool_digital0_mode
tool_digital1_mode
tool_digital2_mode
tool_digital3_mode
output_bit_registers0_to_31
output_bit_registers32_to_63
input_bit_registers0_to_31
input_bit_registers32_to_63复制下面文本,使用你习惯的文本编辑器,粘贴到
input_recipe.txt中:speed_slider_mask
speed_slider_fraction
standard_digital_output_mask
standard_digital_output
configurable_digital_output_mask
configurable_digital_output
tool_digital_output_mask
tool_digital_output
standard_analog_output_mask
standard_analog_output_type
standard_analog_output_0
standard_analog_output_1
external_force_torque
input_bit_registers0_to_31
input_bit_registers32_to_63如果你使用系统的包管理工具安装SDK,如 Ubuntu 的 apt,那么通常你可以在
/usr/share/Elite/路径下找到external_control.script文件,拷贝这个文件到与move_example同一目录。如果使用预编译包安装或编译安装SDK,那么通常可以在
/usr/local/share/Elite/路径下找到external_control.script文件,拷贝这个文件到与move_example同一目录。执行
ifconfig指令,获取本机IP。执行下面指令来运行此程序,注意替换机器人IP和本机IP,以及确认机器人周围环境安全:
./move_example Your.Robot.IP.Addr Your.Local.IP.Addr运行成功,机器人将会以当前位姿为起点,运行一个三角形轨迹。
可能出现的异常:
- 机器人没有运动,示教器提示:“socket_read_binary_integer”:未连接服务端“reverse_socket”。出现这个异常的原因是,机器人无法连接SDK的TCP服务端口。可以参考 “3.3.1 测试网络连接——使用机器人脚本” 章节最后的可能遇到的问题部分的描述。
- 机器人运动结束,示教器提示:“socket_read_binary_integer”:未连接服务端“script_command_socket”。此现象是程序在退出时出现了意外的问题,可以尝试升级SDK。此现象可以不用过多关注。
- 机器人运动过程中中断,机器人示教器日志栏提示:“Socket timed out waiting for command on reverse_socket. The script will exit now.”,或者提示:“socket_read_binary_integer”:未连接服务端“xxx_socket”。此现象是触发了SDK控制机器人的超时机制。可能有如下原因:
- 运行SDK的电脑无法支撑与控制柜的数据传输速度。
- 网络传输出现异常,例如网线松脱。
- 如果程序抛出端口被占用的异常,可以用下面指令查看是哪个端口被占用,然后关闭对应进程:
netstat -ano |grep 50001 netstat -ano |grep 50002 netstat -ano |grep 50003 netstat -ano |grep 50004 - 示教器提示:目标位姿为奇异位姿,机器人不可达。出现此现象,可以使用示教器手动调整机器人位姿到一个合理的范围内。
4.2.2 Windows
参考2.7 配置SDK到Visual Studio工程章节,创建一个新的工程叫“MoveExample”,这里不多赘述。
拷贝下面代码到VS中:
#include <Elite/DataType.hpp>
#include <Elite/EliteDriver.hpp>
#include <Elite/Log.hpp>
#include <Elite/DashboardClient.hpp>
#include <Elite/RtsiIOInterface.hpp>
#include <future>
#include <iostream>
#include <memory>
#include <thread>
using namespace ELITE;
class TrajectoryControl {
private:
std::unique_ptr<EliteDriver> driver_;
std::unique_ptr<DashboardClient> dashboard_;
EliteDriverConfig config_;
public:
TrajectoryControl(const EliteDriverConfig& config) {
config_ = config;
driver_ = std::make_unique<EliteDriver>(config);
dashboard_ = std::make_unique<DashboardClient>();
ELITE_LOG_INFO("Connecting to the dashboard");
if (!dashboard_->connect(config.robot_ip)) {
ELITE_LOG_FATAL("Failed to connect to the dashboard.");
throw std::runtime_error("Failed to connect to the dashboard.");
}
ELITE_LOG_INFO("Successfully connected to the dashboard");
}
~TrajectoryControl() {
if (dashboard_) {
dashboard_->disconnect();
}
driver_->stopControl();
}
bool startControl() {
ELITE_LOG_INFO("Start powering on...");
if (!dashboard_->powerOn()) {
ELITE_LOG_FATAL("Power-on failed");
return false;
}
ELITE_LOG_INFO("Power-on succeeded");
ELITE_LOG_INFO("Start releasing brake...");
if (!dashboard_->brakeRelease()) {
ELITE_LOG_FATAL("Brake release failed");
return false;
}
ELITE_LOG_INFO("Brake released");
if (config_.headless_mode) {
if (!driver_->isRobotConnected()) {
if (!driver_->sendExternalControlScript()) {
ELITE_LOG_FATAL("Fail to send external control script");
return false;
}
}
}
else {
if (!dashboard_->playProgram()) {
ELITE_LOG_FATAL("Fail to play program");
return false;
}
}
ELITE_LOG_INFO("Wait external control script run...");
while (!driver_->isRobotConnected()) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
ELITE_LOG_INFO("External control script is running");
return true;
}
bool moveTrajectory(const std::vector<vector6d_t>& target_points, float point_time, float blend_radius, bool is_cartesian) {
std::promise<TrajectoryMotionResult> move_done_promise;
driver_->setTrajectoryResultCallback([&](TrajectoryMotionResult result) { move_done_promise.set_value(result); });
ELITE_LOG_INFO("Trajectory motion start");
if (!driver_->writeTrajectoryControlAction(ELITE::TrajectoryControlAction::START, target_points.size(), 200)) {
ELITE_LOG_ERROR("Failed to start trajectory motion");
return false;
}
for (const auto& joints : target_points) {
if (!driver_->writeTrajectoryPoint(joints, point_time, blend_radius, is_cartesian)) {
ELITE_LOG_ERROR("Failed to write trajectory point");
return false;
}
// Send NOOP command to avoid timeout.
if (!driver_->writeTrajectoryControlAction(ELITE::TrajectoryControlAction::NOOP, 0, 200)) {
ELITE_LOG_ERROR("Failed to send NOOP command");
return false;
}
}
std::future<TrajectoryMotionResult> move_done_future = move_done_promise.get_future();
while (move_done_future.wait_for(std::chrono::milliseconds(50)) != std::future_status::ready) {
// Wait for the trajectory motion to complete, and send NOOP command to avoid timeout.
if (!driver_->writeTrajectoryControlAction(ELITE::TrajectoryControlAction::NOOP, 0, 200)) {
ELITE_LOG_ERROR("Failed to send NOOP command");
return false;
}
}
auto result = move_done_future.get();
ELITE_LOG_INFO("Trajectory motion completed with result: %d", result);
if (!driver_->writeIdle(0)) {
ELITE_LOG_ERROR("Failed to write idle command");
return false;
}
return result == TrajectoryMotionResult::SUCCESS;
}
bool moveTo(const vector6d_t& point, float time, bool is_cartesian) {
return moveTrajectory({ point }, time, 0, is_cartesian);
}
};
int main(int argc, const char** argv) {
EliteDriverConfig config;
if (argc == 2) {
config.robot_ip = argv[1];
}
else if (argc == 3) {
config.robot_ip = argv[1];
config.local_ip = argv[2];
}
else {
std::cout << "Must provide robot IP. Example: ./trajectory_example aaa.bbb.ccc.ddd <eee.fff.ggg.hhh>" << std::endl;
return 1;
}
config.headless_mode = true;
config.script_file_path = "external_control.script";
std::unique_ptr<TrajectoryControl> trajectory_control = std::make_unique<TrajectoryControl>(config);
std::unique_ptr<RtsiIOInterface> rtsi_client = std::make_unique<RtsiIOInterface>("output_recipe.txt", "input_recipe.txt", 250);
ELITE_LOG_INFO("Connecting to the RTSI");
if (!rtsi_client->connect(config.robot_ip)) {
ELITE_LOG_FATAL("Fail to connect or config to the RTSI.");
throw std::runtime_error("Fail to connect or config to the RTSI");
}
ELITE_LOG_INFO("Successfully connected to the RTSI");
ELITE_LOG_INFO("Starting trajectory control...");
if (!trajectory_control->startControl()) {
ELITE_LOG_FATAL("Failed to start trajectory control.");
return 1;
}
ELITE_LOG_INFO("Trajectory control started");
vector6d_t actual_joints = rtsi_client->getActualJointPositions();
actual_joints[3] = -1.57;
ELITE_LOG_INFO("Moving joints to target: [%lf, %lf, %lf, %lf, %lf, %lf]",
actual_joints[0], actual_joints[1], actual_joints[2], actual_joints[3], actual_joints[4], actual_joints[5]);
if (!trajectory_control->moveTo(actual_joints, 3, false)) {
ELITE_LOG_FATAL("Failed to move joints to target.");
return 1;
}
ELITE_LOG_INFO("Joints moved to target");
vector6d_t actual_pose = rtsi_client->getAcutalTCPPose();
std::vector<vector6d_t> trajectory;
actual_pose[2] -= 0.2;
trajectory.push_back(actual_pose);
actual_pose[1] -= 0.2;
trajectory.push_back(actual_pose);
actual_pose[1] += 0.2;
actual_pose[2] += 0.2;
trajectory.push_back(actual_pose);
ELITE_LOG_INFO("Moving joints to target");
if (!trajectory_control->moveTrajectory(trajectory, 3, 0, true)) {
ELITE_LOG_FATAL("Failed to move trajectory.");
return 1;
}
ELITE_LOG_INFO("Joints moved to target");
return 0;
}
参考2.7 配置SDK到Visual Studio工程章节,编译项目,并拷贝相关库文件。
拷贝
external_control.script编译结果“MoveExample.exe”的目录下。external_control.script文件在源代码的source/resources路径下。如果使用预编译包,此文件在resources目录下。在编译结果“MoveExample.exe”目录下,创建
output_recipe.txt文件,拷贝下面文本内容到文件中:timestamp
payload_mass
payload_cog
script_control_line
target_joint_positions
target_joint_speeds
actual_joint_torques
actual_joint_positions
actual_joint_speeds
actual_joint_current
actual_TCP_pose
actual_TCP_speed
actual_TCP_force
target_TCP_pose
target_TCP_speed
actual_digital_input_bits
actual_digital_output_bits
joint_temperatures
robot_mode
joint_mode
safety_status
speed_scaling
target_speed_fraction
actual_robot_voltage
actual_robot_current
runtime_state
elbow_position
robot_status_bits
safety_status_bits
analog_io_types
standard_analog_input0
standard_analog_input1
standard_analog_output0
standard_analog_output1
io_current
tool_mode
tool_analog_input_types
tool_analog_output_types
tool_analog_input
tool_analog_output
tool_output_voltage
tool_output_current
tool_temperature
tool_digital_mode
tool_digital0_mode
tool_digital1_mode
tool_digital2_mode
tool_digital3_mode
output_bit_registers0_to_31
output_bit_registers32_to_63
input_bit_registers0_to_31
input_bit_registers32_to_63创建
input_recipe.txt文件,拷贝下面文本内容到文件中:speed_slider_mask
speed_slider_fraction
standard_digital_output_mask
standard_digital_output
configurable_digital_output_mask
configurable_digital_output
tool_digital_output_mask
tool_digital_output
standard_analog_output_mask
standard_analog_output_type
standard_analog_output_0
standard_analog_output_1
external_force_torque
input_bit_registers0_to_31
input_bit_registers32_to_63在Windows终端中执行下面指令运行结果,注意替换机器人IP和本机IP,以及确认机器人周围环境安全:
.\MoveExample.exe Your.Robot.IP.Addr Your.Local.IP.Addr运行成功,机器人将会以当前位姿为起点,运行一个三角形轨迹。
可能出现的异常:
- 机器人没有运动,示教器提示:“socket_read_binary_integer”:未连接服务端“reverse_socket”。出现这个异常的原因是,机器人无法连接SDK的TCP服务端口。可以参考 “3.3.1 测试网络连接——使用机器人脚本” 章节最后的可能遇到的问题部分的描述。
- 机器人运动结束,示教器提示:“socket_read_binary_integer”:未连接服务端“script_command_socket”。此现象是程序在退出时出现了意外的问题,可以尝试升级SDK。此现象可以不用过多关注。
- 机器人运动过程中中断,机器人示教器日志栏提示:“Socket timed out waiting for command on reverse_socket. The script will exit now.”,或者提示:“socket_read_binary_integer”:未连接服务端“xxx_socket”。此现象是触发了SDK控制机器人的超时机制。可能有如下原因:
- 运行SDK的电脑无法支撑与控制柜的数据传输速度。
- 网络传输出现异常,例如网线松脱。
- 如果出现弹窗报告异常,可能有下面原因:
MoveExample.exe同一目录下,是否正确拷贝了output_recipe.txt、input_recipe.txt、external_control.script三个文件。- 分别使用下面指令查看端口是否被占用(注意,是TCP的端口):
netstat -ano | findstr :50001 netstat -ano | findstr :50002 netstat -ano | findstr :50003 netstat -ano | findstr :50004如果被占用了,需要结束掉占用的进程。
- 示教器提示:目标位姿为奇异位姿,机器人不可达。出现此现象,可以使用示教器手动调整机器人位姿到一个合理的范围内。
5. SDK示例
此SDK提供了主要功能的使用示例,可以通过连接获取到这些示例。
注意:这里的例子编译与运行依赖 boost 库的 program_options。
下面将对这些示例做简单的说明。
- 功能:测试机器人与SDK是否可以连接。如果正常,将输出“Success, robot connected to PC”。
- 运行:
./connect_robot_test <--robot-ip=ip> [--local-ip=""] - 参数:
--robot-ip arg:机器人IP--local-ip arg:运行SDK电脑的IP(可选)
- 例子:
./connect_robot_test --robot-ip=192.168.1.200 --local-ip=192.168.1.100
- 功能:连接机器人的dashboard端口后进行如下操作:验证dashboard响应,机械臂下电、上电、释放抱闸,加载“test”任务,运行任务,暂停任务,停止任务,输出任务是否被保存。
- 运行:
./dashboard_example <--robot-ip=ip> - 参数:
--robot-ip arg:机器人IP
- 例子:
./dashboard_example --robot-ip=192.168.1.200
- 功能:让机器人进入拖动模式。注意此示例需要手动将机器人上电与释放抱闸。
- 运行:
./freedrive_example <--robot-ip=ip> [--local-ip=""] [--use-headless-mode=true] - 参数:
--robot-ip arg:机器人IP--local-ip arg:运行SDK电脑的IP(可选)--use-headless-mode=true:是否使用headless模式。(关于headless模式见5.1 常见问题)
- 例子:
freedrive_example --robot-ip=192.168.1.200 --local-ip=192.168.1.100 --use-headless-mode
- 功能:从机器人的主端口(30001)获取机器人的运动学参数并打印。向机器人发送一个会触发运行时异常的脚本,捕获异常并打印。向机器人发送一个能正常运行的脚本,脚本功能是在机器人示教器“日志”栏打印“hello world”。
- 运行:
./primary_example <--robot-ip=ip> - 参数:
--robot-ip arg:机器人IP
- 例子:
./primary_example --robot-ip=192.168.1.200
- 功能:连接机器人的RTSI服务,获取控制器版本信息并打印,设置标准数字IO 0为低电平,然后设置为高电平,并输出两次设置花费的时间。
- 运行:
./rtsi_example <--robot-ip=ip> - 参数:
--robot-ip arg:机器人IP
- 例子:
./rtsi_example --robot-ip=192.168.1.200
- 功能:给机器人上电,释放抱闸,使用机器人的伺服透传功能让机器人在z轴上,向下沿直线运动约10cm后又向上沿直线运动约9cm。
- 运行:
./servoj_cartesian_example <--robot-ip=ip> [--local-ip=""] [--use-headless-mode=true] - 参数:
--robot-ip arg:机器人IP--local-ip arg:运行SDK电脑的IP(可选)--use-headless-mode=true:是否使用headless模式。(关于headless模式见5.1 常见问题)
- 例子:
./servoj_cartesian_example --robot-ip=192.168.1.200 --local-ip=192.168.1.100 --use-headless-mode
- 功能:给机器人上电,释放抱闸,使用机器人的伺服透传功能让机器人的第六关节旋转到 3 rad 后再旋转到 -3 rad。
- 参数:
--robot-ip arg:机器人IP--local-ip arg:运行SDK电脑的IP(可选)--use-headless-mode=true:是否使用headless模式。(关于headless模式见5.1 常见问题)
- 例子:
./servoj_example --robot-ip=192.168.1.200 --local-ip=192.168.1.100 --use-headless-mode
- 功能:类似servoj_example.cpp,但旋转时增加了梯形波的速度规划。
- 参数:
--robot-ip arg:机器人IP--local-ip arg:运行SDK电脑的IP(可选)--use-headless-mode=true:是否使用headless模式。(关于headless模式见5.1 常见问题)
- 例子:
./servoj_plan_example --robot-ip=192.168.1.200 --local-ip=192.168.1.100 --use-headless-mode
- 功能:给机器人上电,释放抱闸,使用机器人的speedj功能让末端关节以 -0.1 rad/s 的速度旋转约5秒,再以 0.1 rad/s 的速度旋转约5秒。
- 参数:
---robot-ip arg:机器人IP
---local-ip arg:运行SDK电脑的IP(可选)
---use-headless-mode=true:是否使用headless模式。(关于headless模式见5.1 常见问题) - 例子:
./speedj_example --robot-ip=192.168.1.200 --local-ip=192.168.1.100 --use-headless-mode - 功能:给机器人上电,释放抱闸,使用机器人的speedl功能让机器人在z轴方向,以 -0.02 rad/s 的速度运动约5秒,再以 0.02 rad/s 的速度运动约5秒。
- 参数:
--robot-ip arg:机器人IP--local-ip arg:运行SDK电脑的IP(可选)--use-headless-mode=true:是否使用headless模式。(关于headless模式见5.1 常见问题)
- 例子:
./speedl_example --robot-ip=192.168.1.200 --local-ip=192.168.1.100 --use-headless-mode
- 功能:给机器人上电,释放抱闸,让机器人以当前位姿为起点,运行一个三角形轨迹
- 参数:
--robot-ip arg:机器人IP--local-ip arg:运行SDK电脑的IP(可选)--use-headless-mode=true:是否使用headless模式。(关于headless模式见5.1 常见问题)
- 例子:
./trajectory_example --robot-ip=192.168.1.200 --local-ip=192.168.1.100 --use-headless-mode
5.1 运行示例常见问题
- headless 模式,本意为无示教器模式,在这种模式下,不需要在机器人上运行“External Control”这个ELITECOs插件,程序会直接把EliteScript脚本发送给机器人执行。
- 如果示教器出现报错:“socket_read_binary_integer:未连接服务器”,可以参考3.3.1 使用机器人脚本小节最后的“可能遇到的问题”。
- 示教器出现“奇异点”的报警,大概率是运动开始时的位姿无法满足接下来要走的轨迹,可以手动将机器人移动到一个合适的位姿。
6. API 手册与用户指南
继续阅读下面的文档,可以帮助你详细了解CS机器人SDK的使用:
如果需要查看API的说明,可以查看下面的文档: