- ws://192.169.7.32:9999/websocket
- 远程以root用户通过vscode连接到机械臂的方法:
source bash-workspace/arm-shell-env.sh
- 使用remote插件,远程连接
demo_webserver.exe 帮助
- 参数:
--listen-address=0.0.0.0:9999
设置服务器监听地址,默认为0.0.0.0:9999
--abs-webroot-path=/home/user/zhangjunyi/arwen/webroot/dist/
设置服务器托管前端代码目录的绝对路径,默认为/home/user/zhangjunyi/arwen/webroot/dist/
公式
- 编码器增量 enc 转换 关节位置 rad (弧度)
rad = (double) (enc - offset) / (double) (gear_ratio * enc_size) * (2 * PI)
- 关节位置 rad (弧度) 转换 编码器增量 enc
enc = (int) (rad) / (2.0 * PI) * (gear_ratio * enc_size) + offset
- 弧度 rad 和 角度 deg 的变换
deg = rad * (180 / PI)
- 角度 deg 和 弧度 rad 的变换
rad = deg * (PI / 180)
日志代码位置
----status_word_:0x0,control_word:0x0---
- 输出的代码位置:
arwen/include/ecat/ecat_taike.h
39行
- 输出的代码位置:
Taike_POS: 5 , Taike_STATE: Fault
- 输出代码位置:
arwen/include/ecat/ecat_taike.h
100行
- 输出代码位置:
Domain: WC 7
319行- 输出代码位置:
arwen/src/Ecat/Ecat_Master.cpp
319行
- 输出代码位置:
I20230130 11:40:28.236125 5564 planning.cpp:504] No new point in buffer!
- 输出代码位置:
arwen/src/planning/planning.cpp
504行
- 输出代码位置:
Command joint position lower overrun
- 输出代码位置:
arwen/src/planning/security_module.cpp
32行
- 简介:指挥联合位置下超限
- 输出代码位置:
Joint num : 3 Command joint position upper overrun!
- 输出代码位置
arwen/src/planning/security_module.cpp
26行
- 原因:安全模块检测到了下发的指令超出了约束
- 解决办法:
- 在文件:
arwen/src/protocol/configuration/manipulator.cpp
中,把除以2的去掉就是关键可以转动正负180度
- 在文件:
- 输出代码位置
The velocity is a negtive value:0
- 输出代码位置:
arwen/src/planning/curves/double_s_stop.cpp
76行
- 简介:速度是一个负值:0
- 输出代码位置:
delta_pos.norm : 0.194793
- 输出代码位置:
arwen/src/planning/planner/move_line.cpp
74行
- 输出代码位置:
KDL error: The gradient of E towards the joints is to small
- 输出代码位置:
arwen/src/solver/ik_solver_pos_lma.cpp
55行
- 简介:E向关节方向的梯度太小
- 输出代码位置:
KDL error: The joint position increments are to small
- 输出代码位置:
arwen/src/dynamics/solver/ik_solver_pos_lma.cpp
55行
- 简介:关节位置增量太小
- 输出代码位置:
singular point! please choose another point!
- 输出代码位置:
arwen/src/planning/planning.cpp
682行
- 简介:奇异点!请选择另一个点!
- 输出代码位置:
Domain: State 0
- 输出代码位置:
arwen/src/ecat/ecat_master.cpp
313行
- 输出代码位置:
Taike_POS: 5 , Taike_STATE: Switch on Disabled
- 输出代码位置:
arwen/include/ecat/ecat_taike.h
100行
- 输出代码位置:
demo_webserver.cc 代码分析
读取从站信息
-
每个从站,使用一个类
EcatTaike
的对象描述,六个从站放到一个存放数据类型为类EcatTaike
类型的数组 -
planner 应该有获取机械臂当前状态信息的接口
Planning
- class Planning
- 成员函数:
Init()
ProcessFrame()
IsRunning()
MoveJ()
MoveL()
Stop()
SpeedJ()
SpeedL()
StopRelease()
getStopFlag()
SetVirtualWall()
const bool planner.IsRunning()
: 判断机械臂是否在运行,- 如果在运行,就返回 true,这个时候就不能执行其他指令;
- 如果不在运行,就返回 false,这个时候才可以执行其他指令
const bool planner.getStopFlag()
: 获取结束标志- 如果设置了结束标志,则返回 true,这个时候就表示机械臂已经停止工作,不能再执行其他指令
- 如果没有设置结束标志,则返回 false,这个时候就表示机械臂还在工作,可以执行其他指令
void setStopFlag(bool flag)
: 设置结束标志- 如果传入的flag为true,表示设置了结束标志
- 如果传入的flag为false,表示没有
FkSolverPosKdl
class arwen::dynamics::solver::FkSolverPosKdl
- 成员函数:
Init()
JntToCart()
- 计算 机械臂从关节空间坐标到笛卡尔空间坐标的正运动学
FkSolverPosRecursive
class arwen::dynamices::solver::FkSolverPosRecursive
-
简介:计算一般运动链(arwen::dynamics::chain:: chain)从关节空间到笛卡尔空间位置变换的递归正向位置运动学算法。
- 初始化solvers,示例:
1 2 3 4 5 6
std::shared_ptr<arwen::dynamics::chain::Chain> chain = std::make_shared<arwen::dynamics::chain::Chain>(Manipulator()); FkSolverPosRecursive fk_solver_pos; fk_solver_pos.Init(chain); IkSolverPosLma ik_solver_pos_lma; ik_solver_pos_lma.Init(chain);
Pose
class arwen::dynamics::common::Pose
-
简介:姿态是框架的另一种表达方式。旋转部分表示为矢量,方向与旋转轴对齐,范数为旋转角度。
-
Pose, 里面有 p 和 rot, 分别对应位置和姿态
- 示例代码:
1 2 3 4 5 6
Frame frame_init; Pose pose_init; fk_solver_pos.JntToCart(q_init, frmae_init); pose_init = frame_init.ToPose(); std::cout << "q: " << q_init.data.transpose() << std::endl; std::cout << "pose: " << Pose2Vec(pose_init).transpose() << std::endl;
Frame
class arwen::dynamics::common::Frame
- 该类表示相对于 {Ref} 的笛卡尔坐标 {Obj}。
- 换句话说,它表示从 {Ref} 到 {Obj} 的齐次转换。齐次矩阵形式的帧为 frame {Ref} {Obj} = [旋转 {Ref} {Obj}, p{Ref} {Obj};0, 1]
Rotation
class arwen::dynamics::common::Rotation
- 该类表示笛卡尔空间中的旋转。
- 旋转矩阵 rotate {Rel} {Obj} (我们称之为从 {Ref} 到 {Obj} 的旋转)表示 {Obj} 相对于 {Rel} 的方向。
- 换句话说,它表示从 {Obj} 到 {Ref} 的旋转。具有以下属性:
旋转{A}{B} =旋转逆{B}{A} =旋转转置{B}{A}旋转{A}{C} =旋转{A}{B}*旋转{B}{C} p{A} = 旋转{A}{B}*p{B}
Vector
class arwen::dynamics::common::Vector
- 简介:笛卡尔空间中常见的三维向量。
- 向量 p{Ref}{Obj} 表示指向 {Ref} 中 {Obj} 原点的向量。两个向量的叉乘可以表示为第一个向量和第二个向量的斜对称矩阵的点积。
ik_solver_pos_lma.h
CartToJnt()
- 简介:计算逆位置运动学,从直角坐标(笛卡尔空间坐标)到关节坐标。
- 声明:
bool CartToJnt(const JointVector &q_init, const Frame& p_in, JointVector& q_out) final;
- 参数:
q_init
– 关节坐标的初始猜测。p_in
– 输入的笛卡尔空间坐标q_out
– 输出的关节空间坐标引用
- 返回值:
- 成功 – true
- 失败 – false
ik_solver_vel_pinv_givens.h
- 简介:一种基于广义伪逆的速度逆运动学求解方法,用于计算一般链的速度从笛卡尔空间到关节空间的变换。它使用基于户主轮换的svd计算。
- 声明:
class IkSolverVelPinvGivens final : public IkSolverVel
ik_solver_vel_pinv_nso.h
- 简介:一种基于广义伪逆的速度逆运动学求解方法,用于计算一般链的速度从笛卡尔空间到关节空间的变换。它使用基于户主轮换的svd计算。
- 声明:
class IkSolverVelPinvNso final : public IkSolverVel
ik_solver_vel_pinv.h
- 简介:一种基于广义伪逆的速度逆运动学求解方法,用于计算一般链的速度从笛卡尔空间到关节空间的变换。它使用基于户主轮换的svd计算。
- 声明:
class IkSolverVelPinv final : public IkSolverVel
ik_solver_vel_wdls.h
- 简介:一种基于加权伪逆和阻尼最小二乘的速度逆运动学求解方法,用于计算一般链的速度从笛卡尔空间到关节空间的变换。它使用基于户主轮换的svd计算。
- 声明:
class IkSolverVelWdls final : public IkSolverVel
manipulator.h
- 简介:所有关于机器人硬件配置的协议
- 通过定义宏来分别操控不同的机械臂,目前有的宏定义为:
#define TAIKE_10KG
#define TAIKE_3KG
#define New_arm_10kg
- 函数:
Chain Manipulator();
- 10kg机械臂需要配置约束参数,也就是在每个关节下面增加如下一行代码:
joint_constraints = dynamics::components::Joint::Constraints(M_PI / 2.0, -M_PI / 2.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 2.0, -2.0);
- 如果不加,则安全模块会抛出异常:
Joint num : 0 Command joint position lower overrun!
WebServer
1.1 架构设计
-
功能 业务 -
分层 分模块 - 现在的设计思路:
- 事件处理函数,事件监听函数都封装在了一个类中
- 新的设计思路:
- 暂时不封装成类,而是将使用到的函数都分开在不同的源文件中实现,统一在demo中调用
- 启动服务,监听事件的发生
- 输入:
- 监听地址
- struct mg_mgr
- struct mg_connection
- 输入:
- 事件处理函数
- 处理的事件有:
- WebSocket连接建立时
- 创建一个实时线程
rt_task_create
,定时向客户端发送机械臂的状态信息
- 创建一个实时线程
- WebSocket连接断开时
- 销毁该连接建立时创建的实时线程
rt_task_delete
- 销毁该连接建立时创建的实时线程
- 接收到一个HTTP消息时
- 当请求是
/websocket
时,升级该HTTP连接到WebSocket连接 - 当请求是
/api/*
时,针对相应的接口,调用相应的函数处理请求
- 当请求是
- WebSocket连接建立时
- 处理的事件有:
1.2 前后端通信
- 前端发送一个ping
- 后端接收,判断消息为ping之后,发向前端发送 flag = true,表示可以发送机械臂信息
- 前端接收flag消息,如果为true,就发送一个目标点位置,
- 后端接收的消息如果为目标点位置,就执行如下动作
- 首先,启动一个线程,定时发送机械臂状态信息
- 其次,调用moveJ使机械臂运动到目标点位置
- 最后,如果运行完成,退出定时发送状态信息的线程,并发送flag = false
1.3 libjsoncpp 第三方库的使用
- 在test目录下的demo文件的使用方法:
- 首先,添加一行代码:
link_directories(/home/user/zhangjunyi/arwen/third_party/lib/jsoncpp)
- 然后,在for循环中,添加一行:
target_link_libraries($(example) jsoncpp)
- 首先,添加一行代码:
1.3 模块
1.3.1 手动控制(点动界面)
-
HTTP通信
- 接口:
/api/control/manual/jointPosition/movj
-
发送的数据为:
{"movj":[10, 20, 30, 40, 50, 60]}
- 接口:
/api/control/manual/tcpPosition/movj
- 发送的数据为:
{"movj":[0.5, 0.7, 0.9, 10, 10, 10]}
1.3.2 精确控制
- WebSocket通信,发送的数据为
{"jointSpace":[10, 20, 30, 40, 50, 60]} // {"jointSpace":[joint_rad1, joint_rad2, joint_rad3, joint_rad4, joint_rad5, joint_rad6]}
{"tcpSpace":[0.5, 0.9, 0.7, 10, 10, 10]} // {"tcpSpace":[x, y, z, Rx, Ry, Rz]}
1.3.3 定时同步
旧的WebSocket通信,发送的数据为{"JointInfo":[10.0, 20.0, 30.0, 40.0, 50.0, 60.0]}
- 新的数据格式:关节空间位置信息 + 笛卡尔空间位姿信息 + 机械臂工作状态
1 2 3 4 5 6
"Info": { "Running": True | False, "JointInfo":[joint1, joint2, joint3, joint4, joint5, joint6], "CartInfo":[x, y, z, Rx, Ry, Rz], }
1.3.4 编程模块
- 暂停:
{"pause":1}
- 重新执行:
{"restart":1}