Skip to main content

AR models

2.3 Using AR arms

2.3.1 Prerequisites

  • AR models include cross-wrist and SR types, in left and right configurations (L / R). Customers usually choose side mount.

AR models

  • Version requirements

Controller: 3.0.1.6.AR1124

SDK: librokae-v0.5.1.ar_9 and xcoresdk_python-v0.5.1.ar_9

AR controller version

  • Installation

    Left/right arms are often side-mounted (left arm base does not coincide with the world frame). Left and right side-mount parameters differ. Below: left arm.

    Left arm side mount

2.3.2 Demo usage

Most AR use cases are teleoperation, dexterous hands, and grasping, with strict real-time needs — often Cartesian and joint control. Trajectory planning is critical: prioritize smooth motion and real-time performance (e.g. spline interpolation or trapezoidal velocity profiles). Respect AR IK characteristics so each target stays in workspace and avoids singularities. For teleop delay, tune packet-loss / network tolerance; for slow response, adjust timeout as described in Other usage and real-time topics.

2.3.2.1 Real-time mode — Cartesian position control

See demo: cartesian_impedance_control.cpp.

Notes
  • Remove the following block:
// Force-control frame: tool relative to flange
std::array<double, 16> toolToFlange = {0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 1};
rtCon->setFcCoor(toolToFlange, FrameType::tool, ec);
// Cartesian impedance gains
rtCon->setCartesianImpedance({1200, 1200, 0, 100, 100, 0}, ec);
// 3 N desired force along X and Z
rtCon->setCartesianImpedanceDesiredTorque({3, 0, 3, 0, 0, 0}, ec);
  • The shipped demo uses a 6-axis robot class; it will not run on 7-axis AR. Use:
rokae::xMateErProRobot robot(ip, "192.168.2.190");

The callback updates Cartesian pose in real time (you can inject pose from outside). Do not block: no sockets, heavy logging, or file I/O — only light computation that finishes within ~1 ms.

std::function<CartesianPosition(void)> callback = [&, rtCon]() -> CartesianPosition {
time += 0.001;
output.pos = init_position;
output.pos[7] += delta_z;
// ...
if (time > 0.01) {
std::cout << "Motion end: " << delta_z << std::endl;
output.setFinished();
stopManually.store(false);
return output;
}
return output;
};
Flow
  • Construct:
rokae::xMateErProRobot
  • Set automatic mode, real-time mode, then power on (automatic first):
robot.setOperateMode(rokae::OperateMode::automatic, ec);
robot.setMotionControlMode(MotionControlMode::RtCommand, ec);
robot.setPowerState(true, ec);
  • If a tool/workobject is mounted, set the tool/workobject frame (see setToolset() API).
Toolset toolset1;
// ... configure toolset1 from teach pendant or code ...
robot.setToolset(toolset1, ec);
  • Optional: move to a drag pose (adjust joint targets for AR):
std::array<double, 7> q_drag_xm7p = {0, M_PI / 6, 0, M_PI / 3, 0, 0, 0};
rtCon->MoveJ(0.5, robot.jointPos(ec), q_drag_xm7p);
  • If packet loss is high, set network tolerance (often 20–30):
robot.setRtNetworkTolerance(50, ec);
  • Callback: keep it minimal — no delays, blocking, or heavy work, or scheduling suffers (slow motion, noise, lag).

The commanded Cartesian pose is a 4×4 matrix in the base frame; use helpers in utility.h for conversions.

std::function<CartesianPosition(void)> callback = [&, rtCon]() -> CartesianPosition {
time += 0.001;
constexpr double kRadius = 0.1;
double angle = M_PI / 4 * (1 - std::cos(M_PI / 2 * time));
double delta_z = kRadius * (std::cos(angle) - 1);
CartesianPosition output{};
output.pos = init_position;
output.pos[7] += delta_z;
if (time > 0.01) {
std::cout << "Motion end: " << delta_z << std::endl;
output.setFinished();
stopManually.store(false);
}
return output;
};
  • Start real-time control:
rtCon->setControlLoop(callback, 0, true);
rtCon->startMove(RtControllerMode::cartesianPosition);
rtCon->startLoop(true);

2.3.2.2 Real-time mode — joint control

See demo: joint_position_control.cpp.

Notes
  • See item 2 under Notes in 2.3.2.1 (7-axis class).
Flow
  • First five bullets same as 2.3.2.1.
  • Callback outputs joint angles in radians. If you plan in Cartesian space, convert with utility.h.
std::function<JointPosition()> callback = [&, rtCon]() {
time += 0.001;
double delta_angle = M_PI / 20.0 * (1 - std::cos(M_PI / 2.5 * time));
JointPosition cmd = {{jntPos[0] + delta_angle, jntPos[1] + delta_angle, jntPos[2] - delta_angle,
jntPos[3] + delta_angle, jntPos[4] - delta_angle, jntPos[5] + delta_angle,
jntPos[6] - delta_angle}};
if (time > 60) {
cmd.setFinished();
}
return cmd;
};
  • Start:
rtCon->setControlLoop(callback);
jntPos = robot.jointPos(ec);
rtCon->startMove(RtControllerMode::jointPosition);
rtCon->startLoop(true);

2.3.2.3 Forward / inverse kinematics

To avoid IK/FK failures at singularities, teach test points on the HMI first. If MOVL / MoveJ on the HMI reaches them, the SDK calls should work.

  • Connect
    • Do not swap or mistype IPs.
    • Use xMateErProRobot for 7-axis.
xMateErProRobot robot("192.168.2.160", "192.168.2.110");
  • Automatic mode and power on
robot.setOperateMode(OperateMode::automatic, ec);
if (ec) {
std::cout << "Set automatic mode failed: " << ec.message() << std::endl;
return -1;
}
robot.setPowerState(true, ec);
if (ec) {
std::cout << "Power on failed: " << ec.message() << std::endl;
return -1;
}
  • Tool/workobject frame
Toolset toolset1 = robot.toolset(ec);
print(std::cout, "Tool/workobject from controller:", toolset1);
  • Joint angles (for FK)
auto current_joints = robot.jointPos(ec);
if (ec) {
std::cout << "Read joints failed: " << ec.message() << std::endl;
return -1;
}
  • End pose (for IK)

Usually includes tool; without tool, this is the flange pose.

auto current_cartesian_from_robot = robot.cartPosture(CoordinateType::endInRef, ec);
if (ec) {
std::cout << "Read end pose failed: " << ec.message() << std::endl;
return -1;
}
  • Disable axis-configuration option for IK

Default is off; if you bypass the HMI, set explicitly:

robot.setDefaultConfOpt(false, ec);
  • Forward kinematics
auto fk_cartesian = robot.model().calcFk(current_joints, toolset1, ec);
if (ec) {
std::cout << "FK failed: " << ec.message() << std::endl;
}

Compare printed values with the HMI.

  • Inverse kinematics
auto ik_joints_m1 = robot.model().calcIk(endPos, toolset1, ec);

If it fails, try the FK pose from the previous step. If it still fails, contact support.

  • calcIk_SearchElbow — arm-angle accuracy

Without arm-angle search / accuracy, solutions can be far off:

auto ik_joints_m1 = robot.model().calcIk_SearchElbow(endPos, toolset1, 5, ec);

2.3.2.4 Model-library FK / IK

Can speed up IK. Not all models/controllers support it; AR is supported on the matching AR controller build. Other models: use controller 3.1.2+ when available.

CMake model option

rokae::xMateErProRobot robot("192.168.0.160");
  • Initialize joints
std::array<double, 7> zeros = {0, 0, 0, 0, 0, 0, 0};
auto jointPos_in = Utils::degToRad(std::array<double, 7>({5, 46, -10, 91, 1, -105, 11}));
std::array<double, 7> jointVel_in = {0.3, 0.2, 0.5, 0.4, 0.1, 0.1, 0.1};
std::array<double, 7> jointAcc_in = {1.3, 3.1, 4.1, 1.5, 1.6, 4.1, 8.1};
auto jointInit = Utils::degToRad(std::array<double, 7>({6, 45, -9, 92, 0, -103, 10}));
std::array<double, 7> array1{}, array2{}, array3{}, array4{};
  • Forward kinematics
/**
* @brief Cartesian pose from joint angles
* @param[in] jntPos Joint angles
* @param[in] nr Frame (default flange)
* @return 4×4 pose, row-major
*/
std::array<double, 16> getCartPose(const std::array<double, DoF> &jntPos, SegmentFrame nr = SegmentFrame::flange);
auto pos = model.getCartPose(jointPos_in);
/**
* @brief Search psi in [-PI, PI] for closest IK solution
* @param[in] cartPos Flange Cartesian pose
* @param[in] psi_accuracy Arm-angle resolution in degrees (e.g. 1, 10, 20); finer = slower
* @param[in] elbow Reserved extension
* @param[in] jntInit Seed joints
* @param[out] jntPos Solution joints
* @return Result code — see SDK docs (-1..-8)
*/
int getJointPosSearchPsi(const std::array<double, 16> &cartPos, const double &psi_accuracy, double elbow,
const std::array<double, DoF> &q_init, std::array<double, DoF> &q);

Example:

double psi = Utils::degToRad(-7.177);
double psi2 = Utils::degToRad(0);
std::array<int, 8> confData = {0, 0, 0, 0, 0, 0, 0, 0};
// timeval start;
// gettimeofday(&start, NULL);
auto ret1 = model.getJointPos(pos, psi, jointInit, array1);
auto ret2 = model.getJointPosSearchPsi(pos, 1, psi2, jointInit, array1);

IK with automatic arm-angle search; elb_accuracy > 0.

  • General

    This path often needs > 42 ms per solve. See 2.3.2.4 demo.

/**
* @brief IK from pose; searches elbow in [-PI, PI]
* @param[in] posture End pose in external reference (via setToolset)
* @param[in] elb_accuracy > 0; smaller = finer search, slower. Often use > 10.
*/
std::array<double, DoF> calcIk_SearchElbow(CartesianPosition posture, double elb_accuracy, error_code &ec) noexcept;

std::array<double, DoF> calcIk_SearchElbow(CartesianPosition posture, const Toolset &tool_set, double elb_accuracy,
error_code &ec) noexcept;
  • Model library

int getJointPosSearchPsi(const std::array<double, 16> &cartPos, const double &psi_accuracy, double elbow,
const std::array<double, DoF> &q_init, std::array<double, DoF> &q);

2.4 AR real-time FAQs

2.4.1 Left/right arms move at different speeds

Same version and config but different motion — check this switch on the HMI:

Left/right speed mismatch

2.4.2 FK / IK failures

  • Confirm this HMI option is off:

    AR FK/IK failure HMI

  • Call API to disable conf-based IK:

robot.setDefaultConfOpt(false, ec);