最近OpenClaw实在是太火啦,所以花了一下午来实现了一个简单OpenClaw的项目

本文参考上述大大的文章实现使用openclaw控制机械臂运动,做一个我的技术的分享
首个用openclaw跑通七轴臂控制教学!_openclaw 机械臂-CSDN博客

实现效果如下:

演示

我的演示设备如下:

1. Ubutun 20.4的虚拟机
2. 6轴自由度的机械臂
3. 串口线

整个步骤如下:
一、OpenClaw配置

1. 进入OpenClaw — Personal AI Assistant网址
复制命令

关于Ubutun如何配置node.js,参考这个网址Ubuntu 20.04 下 OpenClaw(龙虾)本地化部署保姆级教程_ubuntu安装龙虾-CSDN博客

npm i -g openclaw

安装之后输入这个命令

openclaw onboard

Yes


QuickStart


Use existing values


这里选择模型的API,我这里使用的是Kimi,因为注册送10块钱
大家可以跟我一起去创建一个api,Kimi API 开放平台

得到你的API号,粘贴过来就行了

在这里输入你的API号码

选择现有模型

跳过选择

继续跳过

后面一连串都选择NO

继续跳过hooks

Restart

用网页端
这里有一个坑,就是Ubutun原生的火狐浏览器可能打不开,建议下载一个微软浏览器,粘贴网址过来即可。

进来时下述画面,openclaw就配置好了。

二、配置机械臂的SDK

这一部分根据你自己的机械臂的不同可以不同使用

我以我的丐版6轴机械臂为例
我的机械臂是以STM32单片机做一个控制,然后用使用串口线跟虚拟机做一个通信,串口线是USB转CH340。


所以需要在虚拟机上面先编写一个CH341的驱动,参考这篇帖子
CH340 CH341 Linux驱动最完整使用教程(永久解决/dev/ttyUSB0 permission denied问题,USB设备读写C++实现)_ttych341usb0: ch341 usb device-CSDN博客
驱动编译完了挂载之后,会发现驱动节点和设备节点,如下

接下来就是自己定义通信的舵机协议,可以参考我的C代码,fasong.c 如下:

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <string.h>
#include <stdlib.h>

// 角度转PWM值 (0-270度 -> 500-2500)
int angle_to_pwm(int angle) {
    // 确保角度在有效范围内
    if (angle < -135) angle = -135;
    if (angle > 135) angle = 135;
    
    // 线性映射:-135度->500,0度->1500,135度->2500
    float pwm = 1500 + (angle * (1000.0 / 135.0));
    return (int)(pwm + 0.5);  // 四舍五入到最接近的整数
}

// 生成所有舵机指令的复合字符串
char *generate_compound_command(int angles[], int servo_count, int move_time) {
    // 计算需要的缓冲区大小 (每个指令15字节 * 舵机数量 + 3{}+1)
    int buf_size = 15 * servo_count + 4;
    char *command = (char *)malloc(buf_size * sizeof(char));
    if (command == NULL) {
        perror("内存分配失败");
        exit(1);
    }
    
    // 添加起始大括号
    strcpy(command, "{");
    
    for (int i = 0; i < servo_count; i++) {
        int pwm = angle_to_pwm(angles[i]);
        // 确保PWM值在有效范围内
        if (pwm < 500) pwm = 500;
        if (pwm > 2500) pwm = 2500;
        
        // 追加单个舵机指令到复合字符串
        char temp[16];
        snprintf(temp, sizeof(temp), "#%03dP%04dT%04d!", i, pwm, move_time);
        strcat(command, temp);
    }
    
    // 添加结束大括号
    strcat(command, "}");
    
    return command;
}

int main(int argc, char *argv[]) {
    int fd;
    const char *device = "/dev/ttyCH341USB0";
    int angles[6];          // 存储6个舵机的角度值
    int move_time = 1000;   // 默认移动时间(ms)

    // 检查命令行参数数量
    if (argc < 7 || argc > 8) {
        printf("用法: %s <角度1> <角度2> <角度3> <角度4> <角度5> <角度6> [时间(ms)]\n", argv[0]);
        printf("例如: %s 90 45 0 45 90 135 1000\n", argv[0]);
        printf("注意: 角度范围0-270度, 时间范围0-9999ms\n");
        return 1;
    }

    // 将命令行参数转换为整数并存储到 angles 数组
    for (int i = 0; i < 6; i++) {
        angles[i] = atoi(argv[i + 1]);
        if (angles[i] < -135 || angles[i] > 135) {
            printf("错误: 角度值必须在 -135 到 135 之间\n");
            return 1;
        }
    }

    // 如果有时间参数,则使用
    if (argc == 8) {
        move_time = atoi(argv[7]);
        if (move_time < 0 || move_time > 9999) {
            printf("错误: 时间值必须在 0 到 9999 之间\n");
            return 1;
        }
    }

    // 生成复合指令字符串
    char *compound_command = generate_compound_command(angles, 6, move_time);
    printf("Generated compound command: %s\n", compound_command);

    // 打开串口设备
    fd = open(device, O_WRONLY | O_NOCTTY);
    if (fd < 0) {
        perror("无法打开设备");
        free(compound_command);
        return 1;
    }

    // 配置串口参数
    struct termios tty;
    if (tcgetattr(fd, &tty) != 0) {
        perror("无法获取串口属性");
        close(fd);
        free(compound_command);
        return 1;
    }

    // 设置波特率为115200
    cfsetospeed(&tty, B115200);
    cfsetispeed(&tty, B115200);

    // 8N1 (8数据位, 无奇偶校验, 1停止位)
    tty.c_cflag &= ~PARENB;
    tty.c_cflag &= ~CSTOPB;
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS8;

    // 禁用硬件流控制
    tty.c_cflag &= ~CRTSCTS;

    // 禁用软件流控制
    tty.c_iflag &= ~(IXON | IXOFF | IXANY);

    // 设置为原始模式
    tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    tty.c_oflag &= ~OPOST;

    // 应用配置
    if (tcsetattr(fd, TCSANOW, &tty) != 0) {
        perror("无法设置串口属性");
        close(fd);
        free(compound_command);
        return 1;
    }

    // 发送复合指令
    ssize_t written = write(fd, compound_command, strlen(compound_command));
    if (written < 0) {
        perror("写入数据失败");
    } else {
        printf("成功写入 %zd 字节指令: %s\n", written, compound_command);
    }

    // 释放内存
    free(compound_command);

    // 清空串口缓冲区
    if (tcflush(fd, TCIOFLUSH) == 0) {
        printf("串口缓冲区已清空\n");
    } else {
        perror("清空串口缓冲区失败");
    }

    // 关闭设备
    close(fd);
    return 0;
}

编写接口python  jiekou.py

import subprocess

def control_arm(angles):
    # 确保传入的角度列表长度为 6
    if len(angles) != 6:
        raise ValueError("角度列表必须包含 6 个值")

    # 将角度值转换为字符串列表
    angle_str = [str(angle) for angle in angles]

    # 调用 C 可执行文件
    try:
        result = subprocess.run(
            ["./fasong"] + angle_str,  # 可执行文件路径 + 参数
            check=True,  # 检查返回值
            text=True,  # 以文本模式捕获输出
            capture_output=True  # 捕获标准输出和标准错误
        )
        print(result.stdout)  # 打印 C 程序的输出
    except subprocess.CalledProcessError as e:
        print(f"程序执行失败: {e}")
        print(f"错误输出: {e.stderr}")

# 示例调用
#angles = [0, 0, 0, 0, 0, 0]

#control_arm(angles)

再往下就是机械臂的正逆运动学
理论可以参考这篇帖子:机器人学基础(1)-位置运动学-正运动学、逆运动学方程建立及其求解-CSDN博客

我这里图方便,就直接使用的python的roboticstoolbox的包,参考如下:
GitHub - petercorke/robotics-toolbox-python: Robotics Toolbox for Python · GitHub

定义好机械臂的DH矩阵(这个根据你自己的机械臂来),正逆运动学之后就可以定义一些基本的运动函数了
我的代码 dfbot_controller.py如下:

from roboticstoolbox import *
from spatialmath import *
import numpy as np
import time

from jiekou import control_arm


# =========================
# 1. 建立机械臂模型(前5轴参与运动学,最后一个是夹爪)
# =========================
DFbot = DHRobot(
    [
        RevoluteMDH(d=0.04145, qlim=np.array([-np.pi * 3 / 4, np.pi * 3 / 4])),  # J1 底座左右
        RevoluteMDH(alpha=np.pi / 2, qlim=np.array([-np.pi / 2, np.pi / 2])),    # J2 大臂
        RevoluteMDH(a=-0.08285, qlim=np.array([-np.pi * 3 / 4, np.pi * 3 / 4])), # J3 小臂
        RevoluteMDH(a=-0.08285, qlim=np.array([-np.pi * 3 / 4, np.pi * 3 / 4])), # J4 手肘/腕部
        RevoluteMDH(alpha=-np.pi / 2, d=0.11, qlim=np.array([0, np.pi])),        # J5 末端左右转
    ],
    name="DFbot",
)


# =========================
# 2. 角度转换
# =========================
def convert_deg(deg, gripper=0):
    d1 = deg[0]
    d2 = -90 - deg[1]
    d3 = deg[2]
    d4 = deg[3] - 90
    d5 = deg[4]
    return [d1, d2, d3, d4, d5, gripper]


def rad_to_deg(state):
    return [float(x) / np.pi * 180 for x in state]


def deg_to_rad(deg):
    return np.array([x / 180 * np.pi for x in deg], dtype=float)


# =========================
# 3. 关节限位处理
# =========================
def clip_to_joint_limits(q):
    q_new = np.array(q, dtype=float).copy()
    for i, link in enumerate(DFbot.links):
        if link.qlim is not None:
            qmin, qmax = link.qlim
            q_new[i] = np.clip(q_new[i], qmin, qmax)
    return q_new


def within_joint_limits(q):
    for i, link in enumerate(DFbot.links):
        if link.qlim is not None:
            qmin, qmax = link.qlim
            if q[i] < qmin or q[i] > qmax:
                return False
    return True


# =========================
# 4. 基础控制
# =========================
def move_joint_rad(state, delay=1, gripper=0):
    state = clip_to_joint_limits(state)
    deg = rad_to_deg(state)
    cmd = convert_deg(deg, gripper=gripper)

    print("关节角(弧度):", state)
    print("关节角(角度):", deg)
    print("发送给机械臂:", cmd)

    control_arm(cmd)
    time.sleep(delay)
    return state


def move_joint_deg(deg, delay=1, gripper=0):
    cmd = convert_deg(deg, gripper=gripper)

    print("输入角度:", deg)
    print("发送给机械臂:", cmd)

    control_arm(cmd)
    time.sleep(delay)


# =========================
# 5. 单关节增量控制
# =========================
def move_joint_delta(state_now, joint_index, delta_rad, delay=1, gripper=0):
    """
    joint_index: 0~4
    delta_rad: 该关节增量(弧度)
    """
    state_new = np.array(state_now, dtype=float).copy()
    state_new[joint_index] += delta_rad
    state_new = clip_to_joint_limits(state_new)

    print(f"\n--- 第 {joint_index+1} 关节增量运动 {np.degrees(delta_rad):.2f} 度 ---")
    return move_joint_rad(state_new, delay=delay, gripper=gripper)


# =========================
# 6. 逆运动学:只优先约束位置
# =========================
def solve_ik_position_only(T_target, q0, mask=None, ilimit=200, slimit=200):
    if mask is None:
        mask = [1, 1, 1, 0, 0, 0]

    sol = DFbot.ikine_LM(
        T_target,
        q0=q0,
        ilimit=ilimit,
        slimit=slimit,
        joint_limits=True,
        mask=mask
    )
    return sol


# =========================
# 7. 单步笛卡尔相对移动
# =========================
def move_cartesian_relative_once(state_now, dx=0, dy=0, dz=0, delay=1, show_result=True):
    T_now = DFbot.fkine(state_now).A

    T_target = T_now.copy()
    T_target[0, 3] += dx
    T_target[1, 3] += dy
    T_target[2, 3] += dz

    print("当前末端位姿 T_now =\n", T_now)
    print("目标末端位姿 T_target =\n", T_target)

    sol = solve_ik_position_only(T_target, q0=state_now)

    if not sol.success:
        print("逆运动学求解失败!")
        print("失败原因:", sol.reason)
        return False, state_now

    state_new = clip_to_joint_limits(sol.q)

    if not within_joint_limits(state_new):
        print("逆解结果超出关节限制")
        return False, state_now

    if show_result:
        print("逆解成功,新的关节角(弧度):", state_new)
        print("新的关节角(角度):", rad_to_deg(state_new))

    state_new = move_joint_rad(state_new, delay=delay)
    return True, state_new


# =========================
# 8. 带缩步重试的笛卡尔移动
# =========================
def move_cartesian_relative(state_now, dx=0, dy=0, dz=0, delay=1, show_result=True, retry=5):
    scale = 1.0

    for k in range(retry):
        dx_try = dx * scale
        dy_try = dy * scale
        dz_try = dz * scale

        print(f"\n第 {k+1} 次尝试: dx={dx_try:.4f}, dy={dy_try:.4f}, dz={dz_try:.4f}")

        ok, state_new = move_cartesian_relative_once(
            state_now,
            dx=dx_try,
            dy=dy_try,
            dz=dz_try,
            delay=delay,
            show_result=show_result
        )

        if ok:
            return state_new

        scale *= 0.5
        print("本次失败,自动缩小步长后重试...")

    print("多次尝试后仍然失败,保持原状态不动。")
    return state_now


# =========================
# 9. 分步平滑移动
# =========================
def move_cartesian_smooth(state_now, dx=0, dy=0, dz=0, steps=5, delay=0.5):
    dx_step = dx / steps
    dy_step = dy / steps
    dz_step = dz / steps

    for i in range(steps):
        print(f"\n===== 平滑移动第 {i+1}/{steps} 步 =====")
        state_now = move_cartesian_relative(
            state_now,
            dx=dx_step,
            dy=dy_step,
            dz=dz_step,
            delay=delay,
            show_result=True,
            retry=5
        )
    return state_now


# =========================
# 10. 末端上下动作(保留逆运动学)
# =========================
def move_up(state_now, step=0.02, delay=1, smooth=True):
    print("\n--- 执行动作:向上移动 ---")
    if smooth:
        return move_cartesian_smooth(state_now, dz=step, steps=5, delay=delay)
    else:
        return move_cartesian_relative(state_now, dz=step, delay=delay)


def move_down(state_now, step=0.02, delay=1, smooth=True):
    print("\n--- 执行动作:向下移动 ---")
    if smooth:
        return move_cartesian_smooth(state_now, dz=-step, steps=5, delay=delay)
    else:
        return move_cartesian_relative(state_now, dz=-step, delay=delay)


# =========================
# 11. 重新定义左右动作:直接控制第1关节
# =========================
def move_left(state_now, step_deg=5, delay=1):
    """
    向左:底座(第1关节)左转
    """
    print("\n--- 执行动作:向左(底座左转) ---")
    return move_joint_delta(state_now, joint_index=0, delta_rad=np.deg2rad(step_deg), delay=delay)


def move_right(state_now, step_deg=5, delay=1):
    """
    向右:底座(第1关节)右转
    """
    print("\n--- 执行动作:向右(底座右转) ---")
    return move_joint_delta(state_now, joint_index=0, delta_rad=np.deg2rad(-step_deg), delay=delay)


# =========================
# 12. 重新定义旋转动作:直接控制第5关节
# =========================
def rotate_left(state_now, step_deg=5, delay=1):
    """
    向左旋转:第5关节左转
    """
    print("\n--- 执行动作:向左旋转(末端左转) ---")
    return move_joint_delta(state_now, joint_index=4, delta_rad=np.deg2rad(step_deg), delay=delay)


def rotate_right(state_now, step_deg=5, delay=1):
    """
    向右旋转:第5关节右转
    """
    print("\n--- 执行动作:向右旋转(末端右转) ---")
    return move_joint_delta(state_now, joint_index=4, delta_rad=np.deg2rad(-step_deg), delay=delay)


# =========================
# 13. 夹爪控制(第6通道)
# =========================
def gripper_open(state_now, gripper_deg=30, delay=1):
    print("\n--- 执行动作:夹爪打开 ---")
    return move_joint_rad(state_now, delay=delay, gripper=gripper_deg)


def gripper_close(state_now, gripper_deg=0, delay=1):
    print("\n--- 执行动作:夹爪闭合 ---")
    return move_joint_rad(state_now, delay=delay, gripper=gripper_deg)


# =========================
# 14. 组合动作封装
# =========================
def action_up_down(state_now, step=0.02, delay=1):
    print("\n=== 组合动作:上 -> 下 ===")
    state_now = move_up(state_now, step=step, delay=delay, smooth=True)
    state_now = move_down(state_now, step=step, delay=delay, smooth=True)
    return state_now


def action_left_right(state_now, step_deg=10, delay=1):
    print("\n=== 组合动作:左 -> 右 ===")
    state_now = move_left(state_now, step_deg=step_deg, delay=delay)
    state_now = move_right(state_now, step_deg=step_deg, delay=delay)
    return state_now


def action_rotate_lr(state_now, step_deg=10, delay=1):
    print("\n=== 组合动作:左旋 -> 右旋 ===")
    state_now = rotate_left(state_now, step_deg=step_deg, delay=delay)
    state_now = rotate_right(state_now, step_deg=step_deg, delay=delay)
    return state_now


# =========================
# 15. 推荐姿态
# =========================
state0 = np.array([0, 0, 0, 0, 0], dtype=float)
state_ready = np.array([0, -0.4, 0.5, 0.6, 0.2], dtype=float)
deg0 = [0, 0, 0, 0, 0]


# =========================
# 16. 可视化
# =========================
DFbot.plot(state0, block=False)


# =========================
# 17. 主程序
# =========================
if __name__ == "__main__":
    print("\n===== 到初始位置 =====")
    current_state = move_joint_deg(deg0, delay=2)

    print("\n===== 到 ready 姿态 =====")
    current_state = move_joint_rad(state_ready, delay=2)

    #print("\n===== 测试:向上 =====")
    #current_state = move_up(current_state, step=0.03, delay=0.6, smooth=True)

    #print("\n===== 测试:向下 =====")
    #current_state = move_down(current_state, step=0.06, delay=0.6, smooth=True)

    print("\n===== 测试:向左 =====")
    current_state = move_left(current_state, step_deg=50, delay=1)

    print("\n===== 测试:向右 =====")
    current_state = move_right(current_state, step_deg=50, delay=1)

    #print("\n===== 测试:向左旋转 =====")
    #current_state = rotate_left(current_state, step_deg=50, delay=1)

    #print("\n===== 测试:向右旋转 =====")
    #current_state = rotate_right(current_state, step_deg=50, delay=1)

    #print("\n===== 测试:夹爪打开/闭合 =====")
    #gripper_open(current_state, gripper_deg=30, delay=1)
    #gripper_close(current_state, gripper_deg=0, delay=1)

    print("\n===== 动作执行完成 =====")

到此,其实已经可以直接在虚拟机上面控制机械臂运动了

三、配置OpenClaw的skill
我们上面已经定义好机械臂的运动代码了,现在想直接使用自然语言进行一个机械臂运动的控制,OpenClaw刚好可以实现上述功能,本质上就是根据你事先配置好的skill.md进行学习
 首先我们需要找到OpenClaw的目录我的如下:

进入skills目录下,创建一个新的目录dfbot-arm-codegen,再在此目录下创建一个新的文件夹references

在dfbot-arm-codegen目录下创建一个skill.md的脚本文件,用来教会OpenClaw如何使用你编译好的代码
脚本内容如下:

---
name: dfbot-arm-codegen
description: 引导 OpenClaw 生成基于 DFbot 机械臂的控制代码。支持笛卡尔空间位移、关节控制和夹爪操作。
metadata:
  {
    "openclaw":
      {
        "emoji": "🤖",
        "requires": { "bins": ["python3"] },
      },
  }
---

## 功能概览
- 本技能根据用户指令生成 Python 脚本。
- 依赖用户本地的 `dfbot_controller.py` 模块。

## 生成代码的硬性规则 (CRITICAL)

1. **指定运行与存放目录**:
   - CRITICAL: 所有生成的 Python 脚本必须明确说明或默认在以下目录下运行:
     `/home/rlk/.nvm/versions/node/v22.22.1/lib/node_modules/openclaw/workspace`
   - 提醒用户确保 `dfbot_controller.py` 和 `jiekou.py` 已放置在该目录下,否则脚本将无法导入依赖。

2. **状态追踪**:
   - 机械臂所有移动函数(如 `move_up`, `move_left`)都必须接收 `state_now` 并在执行后返回新的 `current_state`。
   - 必须链式更新状态:`current_state = move_up(current_state, ...)`。

3. **导入与初始化**:
   - 必须从 `dfbot_controller` 导入 `deg0`, `state_ready` 以及各种 `move_*` 函数。
   - 脚本开头通常先执行 `current_state = move_joint_deg(deg0)` 初始化。

4. **单位规范**:
   - 笛卡尔移动 (`move_up/down/smooth`) 单位是 **米 (m)**。
   - 关节转动 (`move_left/right`, `rotate_left/right`) 单位是 **度 (°)**。
   - 夹爪开合单位是 **度 (°)** (30度为开,0度为关)。

## 使用本技能生成代码
   - 根据用户需求,结合 `references/robot-api.md` 生成完整脚本。
   - 生成后告知用户:脚本已针对 `/home/rlk/.nvm/versions/node/v22.22.1/lib/node_modules/openclaw/workspace` 路径优化,请在该目录下执行 `python3 <生成的脚本名>.py`。

## 参考资料
- 详细 API 见 `references/robot-api.md`。

再references目录创建robot-api.md教会它如何使用我们定义好的函数

# DFbot API 速查与最小可运行模板

供 OpenClaw 根据用户自然语言生成机械臂控制代码时参考。所有底层逻辑已在 `dfbot_controller.py` 中封装完成。

## 1. 预设状态与基础控制

从 `dfbot_controller.py` 中导入。机械臂控制的核心逻辑是**状态更新**,所有的动作函数都会返回最新的关节状态数组(弧度),必须用变量接收并传递给下一次动作!

```python
from dfbot_controller import deg0, state_ready, move_joint_deg, move_joint_rad

# 1. 移动到零位(使用角度),返回初始化的弧度状态
current_state = move_joint_deg(deg0, delay=2)

# 2. 移动到准备姿态(使用弧度)
current_state = move_joint_rad(state_ready, delay=2)
```

## 2. 常用动作接口
|动作类型|函数签名|说明|
|------|------|------|------|
|向上移动|move_up(state_now, step=0.02, delay=1, smooth=True)|笛卡尔Z轴增加,step单位:米 (m)|
向下移动|move_down(state_now, step=0.02, delay=1, smooth=True)|笛卡尔Z轴减少,step单位:米 (m)|
底座向左|move_left(state_now, step_deg=5, delay=1)|第1关节左转,单位:角度 (°)|
底座向右|move_right(state_now, step_deg=5, delay=1)|第1关节右转,单位:角度 (°)|
末端左旋|rotate_left(state_now, step_deg=5, delay=1)|第5关节左旋,单位:角度 (°)|
末端右旋|rotate_right(state_now, step_deg=5, delay=1)|第5关节右旋,单位:角度 (°)|
任意平滑|ove_cartesian_smooth(state_now, dx=0, dy=0, dz=0, steps=5, delay=0.5)|对当前位姿平滑移动|


## 3.夹爪控制

夹爪单独控制,不改变主要机械臂的5轴运动学状态,但同样需要传递和返回状态:

```python
from dfbot_controller import gripper_open, gripper_close

# 30度为打开
current_state = gripper_open(current_state, gripper_deg=30, delay=1)
# 0度为闭合
current_state = gripper_close(current_state, gripper_deg=0, delay=1)
```



## 4.最小可运行模板(生成代码时基于此扩展)

```python
#!/usr/bin/env python3
import time

# 导入用户封装好的 DFbot 模块
from dfbot_controller import (
    deg0, state_ready, 
    move_joint_deg, move_joint_rad,
    move_up, move_down, move_left, move_right,
    rotate_left, rotate_right,
    gripper_open, gripper_close
)

def main():
    print("===== 开始执行 DFbot 控制任务 =====")
    
    # 1. 初始化到零位并获取初始状态
    current_state = move_joint_deg(deg0, delay=2)
    
    # 2. 移动到工作准备姿态
    current_state = move_joint_rad(state_ready, delay=2)
    
    # 3. 夹爪打开准备
    current_state = gripper_open(current_state, gripper_deg=30, delay=1)
    
    # --- 根据用户需求在这里插入具体动作 ---
    
    # 示例:向左转动 20 度
    current_state = move_left(current_state, step_deg=20, delay=1.5)
    
    # 示例:向下移动 3 厘米 (0.03米) 准备抓取
    current_state = move_down(current_state, step=0.03, delay=1, smooth=True)
    
    # 示例:闭合夹爪
    current_state = gripper_close(current_state, gripper_deg=0, delay=1)
    
    # 示例:向上提起 5 厘米 (0.05米)
    current_state = move_up(current_state, step=0.05, delay=1.5, smooth=True)
    
    # -----------------------------------
    
    # 4. 任务结束,返回零位
    print("===== 任务完成,复位 =====")
    current_state = move_joint_deg(deg0, delay=2)

if __name__ == "__main__":
    main()

```

生成代码时请根据用户描述替换或增加运动步骤











这两部分其实可以让AI给你生成

配置好skill之后重新启动一下OpenClaw,然后进行一些配置的提示
我的提示词如下:

最后就可以用你的语言直接控制机械臂啦

综上,这个项目只是一个简单的尝试,机械臂也只能做一些简单的运动,希望能给一些人帮助

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐