机械臂控制
一、简介
本文档介绍 RobotApi 中机械臂(手臂)相关接口的使用方法。这组接口提供了对机器人左臂、右臂、双臂的运动控制、位置查询、实时监控能力。
支持机型: 本文档涉及的所有手臂控制 API 仅支持豹小秘 Pro 机型。其他机型调用相关接口将无法正常执行。
能力概述:
- 运动控制
- 左臂 / 右臂的相对角度移动、绝对角度移动
- 双臂同步相对移动、绝对移动(保证左右臂同步执行)
- 重置左臂 / 右臂 / 双臂到默认位置(垂直于地面)
- 停止左臂 / 右臂 / 双臂运动
- 状态查询
- 查询左臂 / 右臂当前位置(角度、电机位置、速度)
- 查询手臂是否可移动(摆臂功能是否启用)
- 实时监控
- 注册 / 取消注册手臂位置实时监听器,持续接收位置变化数据
关键说明:
- 所有运动接口均通过
CommandListener异步回调返回执行结果result == Definition.RESULT_SUCCEED且message == Definition.SUCCEED视为成功- 其他情况均为失败,包含超时、硬件异常等
- 角度单位:度,正值向前,负值向后;
0°表示手臂垂直于地面 - 角度有效范围:
-30°~+130°(向后最大 30°,向前最大 130°);超出范围的目标角度会被限位裁剪 - 默认位置(重置接口的目标位置):
0°(垂直地面) - 速度参数取值范围:1 ~ 60;传
0时按默认值30运动;超出范围的取值不保证行为 - 资源占用:
armLeftXxx占用RESOURCE_ARM_LEFT,armRightXxx占用RESOURCE_ARM_RIGHT,双臂接口同时占用左右臂资源;同一资源若被前一个未结束的命令占用,新命令会返回资源冲突错误。如果业务侧能自行保证调用顺序不重叠,无需额外处理;若调用时机不可控(例如用户多次快速点击),建议在每次发起运动前先调用对应的停止接口(armLeftStop/armRightStop/armDualStop),可有效避免冲突。
二、运动控制 API
2.1 左臂相对角度移动
方法名称:armLeftRelMove
调用方式:
RobotApi.getInstance().armLeftRelMove(reqId, angle, speed, new CommandListener() {
@Override
public void onResult(int result, String message, String extraData) {
if (result == Definition.RESULT_SUCCEED && Definition.SUCCEED.equals(message)) {
// 成功
} else {
// 失败(包含超时、硬件异常等)
}
}
});
参数:
reqId:int 类型,命令 idangle:int 类型,相对角度(单位:度,正值向前,负值向后,如50表示向前移动 50°,-50表示向后移动 50°);目标位置(当前角度 +angle)必须落在-30° ~ +130°范围内,否则会被限位裁剪speed:int 类型,速度(取值 1~60,传 0 按默认 30 执行)listener:CommandListener回调,可为null
2.2 左臂绝对角度移动
方法名称:armLeftAbsMove
调用方式:
RobotApi.getInstance().armLeftAbsMove(reqId, angle, speed, new CommandListener() {
@Override
public void onResult(int result, String message, String extraData) {
if (result == Definition.RESULT_SUCCEED && Definition.SUCCEED.equals(message)) {
// 移动到目标角度成功
} else {
// 失败
}
}
});
参数:
reqId:int 类型,命令 idangle:int 类型,目标绝对角度(单位:度,有效范围-30° ~ +130°,超出会被裁剪);如45表示移动到 45°,-30表示移动到 -30°speed:int 类型,速度(取值 1~60,传 0 按默认 30 执行)listener:CommandListener回调,可为null
2.3 右臂相对角度移动
方法名称:armRightRelMove
调用方式:
RobotApi.getInstance().armRightRelMove(reqId, angle, speed, new CommandListener() {
@Override
public void onResult(int result, String message, String extraData) {
if (result == Definition.RESULT_SUCCEED && Definition.SUCCEED.equals(message)) {
// 成功
} else {
// 失败
}
}
});
参数:
reqId:int 类型,命令 idangle:int 类型,相对角度(单位:度,正值向前,负值向后;右臂自动镜像处理);目标位置必须落在-30° ~ +130°范围内,否则会被限位裁剪speed:int 类型,速度(取值 1~60,传 0 按默认 30 执行)listener:CommandListener回调,可为null
2.4 右臂绝对角度移动
方法名称:armRightAbsMove
调用方式:
RobotApi.getInstance().armRightAbsMove(reqId, angle, speed, new CommandListener() {
@Override
public void onResult(int result, String message, String extraData) {
if (result == Definition.RESULT_SUCCEED && Definition.SUCCEED.equals(message)) {
// 成功
} else {
// 失败
}
}
});
参数:
reqId:int 类型,命令 idangle:int 类型,目标绝对角度(单位:度,有效范围-30° ~ +130°,超出会被裁剪);右臂自动镜像处理speed:int 类型,速度(取值 1~60,传 0 按默认 30 执行)listener:CommandListener回调,可为null
2.5 双臂相对角度移动(同步)
方法名称:armDualRelMove
调用方式:
RobotApi.getInstance().armDualRelMove(reqId, leftAngle, rightAngle, speed, new CommandListener() {
@Override
public void onResult(int result, String message, String extraData) {
if (result == Definition.RESULT_SUCCEED && Definition.SUCCEED.equals(message)) {
// 成功
} else {
// 失败
}
}
});
参数:
reqId:int 类型,命令 idleftAngle:int 类型,左臂相对角度(正值向前,负值向后);目标位置必须落在-30° ~ +130°rightAngle:int 类型,右臂相对角度(正值向前,负值向后);目标位置必须落在-30° ~ +130°speed:int 类型,速度(取值 1~60,传 0 按默认 30 执行)listener:CommandListener回调,可为null
说明: 该接口保证左右臂同步执行,比单独调用左右臂接口更可靠。
2.6 双臂绝对角度移动(同步)
方法名称:armDualAbsMove
调用方式:
RobotApi.getInstance().armDualAbsMove(reqId, leftAngle, rightAngle, speed, new CommandListener() {
@Override
public void onResult(int result, String message, String extraData) {
if (result == Definition.RESULT_SUCCEED && Definition.SUCCEED.equals(message)) {
// 成功
} else {
// 失败
}
}
});
参数:
reqId:int 类型,命令 idleftAngle:int 类型,左臂目标绝对角度(有效范围-30° ~ +130°)rightAngle:int 类型,右臂目标绝对角度(有效范围-30° ~ +130°)speed:int 类型,速度(取值 1~60,传 0 按默认 30 执行)listener:CommandListener回调,可为null
2.7 重置左臂到默认位置
方法名称:resetLeftArmToDefault
调用方式:
RobotApi.getInstance().resetLeftArmToDefault(reqId, new CommandListener() {
@Override
public void onResult(int result, String message, String extraData) {
if (result == Definition.RESULT_SUCCEED && Definition.SUCCEED.equals(message)) {
// 重置成功
} else {
// 失败
}
}
});
参数:
reqId:int 类型,命令 idlistener:CommandListener回调
说明: 默认位置为左臂垂直于地面的姿态(即 0°)。
2.8 重置右臂到默认位置
方法名称:resetRightArmToDefault
调用方式:
RobotApi.getInstance().resetRightArmToDefault(reqId, new CommandListener() {
@Override
public void onResult(int result, String message, String extraData) {
if (result == Definition.RESULT_SUCCEED && Definition.SUCCEED.equals(message)) {
// 重置成功
} else {
// 失败
}
}
});
参数:
reqId:int 类型,命令 idlistener:CommandListener回调
说明: 默认位置为右臂垂直于地面的姿态(即 0°)。
2.9 重置双臂到默认位置(同步)
方法名称:resetBothArmsToDefault
调用方式:
RobotApi.getInstance().resetBothArmsToDefault(reqId, new CommandListener() {
@Override
public void onResult(int result, String message, String extraData) {
if (result == Definition.RESULT_SUCCEED && Definition.SUCCEED.equals(message)) {
// 重置成功
} else {
// 失败
}
}
});
参数:
reqId:int 类型,命令 idlistener:CommandListener回调
说明: 同时将左右臂重置到默认位置。相比分别调用 resetLeftArmToDefault 与 resetRightArmToDefault,该接口可以保证两臂同步执行。
三、停止控制 API
3.1 停止左臂运动
方法名称:armLeftStop
调用方式:
RobotApi.getInstance().armLeftStop(reqId);
参数:
reqId:int 类型,命令 id
说明: 该接口会同时释放 RESOURCE_ARM_LEFT 资源,无回调。
3.2 停止右臂运动
方法名称:armRightStop
调用方式:
RobotApi.getInstance().armRightStop(reqId);
参数:
reqId:int 类型,命令 id
说明: 该接口会同时释放 RESOURCE_ARM_RIGHT 资源,无回调。
3.3 停止双臂运动
方法名称:armDualStop
调用方式:
RobotApi.getInstance().armDualStop(reqId);
参数:
reqId:int 类型,命令 id
说明: 同时停止左右臂运动并释放对应资源,无回调。
四、状态查询 API
4.1 查询左臂位置
方法名称:getLeftArmPosition
调用方式:
RobotApi.getInstance().getLeftArmPosition(reqId, new CommandListener() {
@Override
public void onResult(int result, String message, String extraData) {
if (result == Definition.RESULT_SUCCEED && Definition.SUCCEED.equals(message)) {
try {
JSONObject json = new JSONObject(extraData);
String arm = json.optString(Definition.JSON_ARM); // Definition.ARM_LEFT
int angle = json.optInt(Definition.JSON_ARM_ANGLE); // 角度(单位:度)
int speed = json.optInt(Definition.JSON_ARM_SPEED); // 当前速度
} catch (JSONException e) {
e.printStackTrace();
}
}
}
});
参数:
reqId:int 类型,命令 idlistener:CommandListener回调,通过extraData返回 JSON 字符串:arm:手臂标识,左臂固定为"left"(Definition.ARM_LEFT)angle:当前角度(度)speed:当前速度
4.2 查询右臂位置
方法名称:getRightArmPosition
调用方式:
RobotApi.getInstance().getRightArmPosition(reqId, new CommandListener() {
@Override
public void onResult(int result, String message, String extraData) {
if (result == Definition.RESULT_SUCCEED && Definition.SUCCEED.equals(message)) {
try {
JSONObject json = new JSONObject(extraData);
String arm = json.optString(Definition.JSON_ARM); // Definition.ARM_RIGHT
int angle = json.optInt(Definition.JSON_ARM_ANGLE);
int speed = json.optInt(Definition.JSON_ARM_SPEED);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
});
参数:
reqId:int 类型,命令 idlistener:CommandListener回调,通过extraData返回 JSON 字符串,格式同左臂查询,arm固定为"right"(Definition.ARM_RIGHT)
4.3 查询手臂是否可移动
方法名称:isArmMovable
调用方式:
RobotApi.getInstance().isArmMovable(reqId, new CommandListener() {
@Override
public void onResult(int result, String message, String extraData) {
if (result == Definition.RESULT_SUCCEED && Definition.SUCCEED.equals(message)) {
try {
JSONObject json = new JSONObject(extraData);
boolean movable = json.optBoolean(Definition.JSON_ARM_MOVABLE);
// movable == true 表示摆臂功能当前已启用,可以执行手臂运动
} catch (JSONException e) {
e.printStackTrace();
}
}
}
});
参数:
reqId:int 类型,命令 idlistener:CommandListener回调,通过extraData返回 JSON:{"movable": true/false}
说明:
- 对于支持机械臂的机型,若同时接入了胸前大屏等外设,系统会根据当前状态动态决定是否允许摆臂;该开关仅可在系统设置页面修改,提供三种模式:
- 智能检测(默认):自动识别屏幕连接状态。接入屏幕时手臂不摆动,未接入时正常摆动。
- 关闭摆动:手臂始终不摆动,适合外接屏幕时使用,避免手臂与屏幕碰撞。
- 开启摆动:手臂持续可摆动,适合领位、跳舞等互动场景,建议在未外接屏幕时使用。
- 该接口返回的是「当前是否真正可摆臂」的最终结果,已综合考虑系统设置与外接屏状态。
- 当
movable == false时,调用手臂运动接口不会真正执行,仅返回失败结果,不会引发其他副作用。 - 业务如需提示用户当前手臂不可用,可在进入相关页面时调用一次该接口;中途无需反复检查。
五、实时监控 API
5.1 注册手臂位置监听器
方法名称:registerArmPositionListener
调用方式:
StatusListener listener = new StatusListener() {
@Override
public void onStatusUpdate(String type, String data) {
try {
JSONObject json = new JSONObject(data);
String arm = json.optString(Definition.JSON_ARM); // Definition.ARM_LEFT 或 Definition.ARM_RIGHT
int angle = json.optInt(Definition.JSON_ARM_ANGLE);
int speed = json.optInt(Definition.JSON_ARM_SPEED);
if (Definition.ARM_LEFT.equals(arm)) {
// 左臂位置更新
} else if (Definition.ARM_RIGHT.equals(arm)) {
// 右臂位置更新
}
} catch (JSONException e) {
e.printStackTrace();
}
}
};
RobotApi.getInstance().registerArmPositionListener(listener);
参数:
listener:StatusListener状态监听器onStatusUpdate(String type, String data)中data为 JSON 字符串,字段同getLeftArmPosition/getRightArmPosition:arm、angle、speed
说明:
- 注册成功后将持续接收左右臂位置变化数据,直到调用
unregisterArmPositionListener取消 - 取消注册时只需传入同一个
listener实例即可,无需保存返回值
5.2 取消注册手臂位置监听器
方法名称:unregisterArmPositionListener
调用方式:
RobotApi.getInstance().unregisterArmPositionListener(listener);
参数:
listener:注册时使用的同一个StatusListener实例
注意: 在 Activity / Fragment 销毁时务必取消注册,避免内存泄漏。
六、附录
6.1 回调结果判断模板
所有运动控制接口均推荐使用以下方式判断结果:
new CommandListener() {
@Override
public void onResult(int result, String message, String extraData) {
if (result == Definition.RESULT_SUCCEED && Definition.SUCCEED.equals(message)) {
// 成功
} else {
// 失败:result 可能为超时、硬件异常等错误码
// message 描述具体失败原因
}
}
}
6.2 资源占用说明
| 接口 | 占用资源 |
armLeftRelMove / armLeftAbsMove / resetLeftArmToDefault / armLeftStop | RESOURCE_ARM_LEFT |
armRightRelMove / armRightAbsMove / resetRightArmToDefault / armRightStop | RESOURCE_ARM_RIGHT |
armDualRelMove / armDualAbsMove / resetBothArmsToDefault / armDualStop | RESOURCE_ARM_LEFT + RESOURCE_ARM_RIGHT |
当资源被占用时(如左臂正在执行另一动作),新的命令会返回资源冲突错误码,需要先停止冲突命令或等待执行完毕。
冲突规避建议:
- 业务自行保证调用顺序:若业务可以确保上一次手臂命令结束后才发起下一次(例如等待
CommandListener.onResult回调),则无需额外处理。 - 调用时机不可控时:例如用户连续点击、外部事件驱动等场景,可在每次发起运动前先调用对应的停止接口,再发起新动作,可有效规避资源冲突。
// 示例:发起左臂运动前,先停止左臂
RobotApi.getInstance().armLeftStop(0);
RobotApi.getInstance().armLeftAbsMove(0, 90, 30, new CommandListener() {
@Override
public void onResult(int result, String message, String extraData) {
// 处理结果
}
});
// 双臂同理
RobotApi.getInstance().armDualStop(0);
RobotApi.getInstance().armDualAbsMove(0, 0, 0, 30, listener);
6.3 完整示例
完整调用示例请参考 RobotSample 工程中的: com.ainirobot.robotos.fragment.ArmControlFragment
该示例覆盖了本文档列出的所有 API 调用方式。