Skip to content

Lua 脚本编程快速入门

1. ARCS 脚本简介

ARCS的脚本编程是指⽤脚本语⾔来控制机器⼈。这种编程方式基于LUA语言,它遵循LUA语法规则,为用户提供了灵活而强大的编程环境。

2. Lua 语法

Lua语法教程可参考 https://www.runoob.com/lua/lua-tutorial.html

2.1 常用变量类型

类型说明示例
nil表示一个无效值。
当打印一个没有被赋值的变量时,便会输出一个nil值。
nil
boolean布尔值,只有两个可选值:true和false。true
false
number数字,包括整型、浮点型。1
-5
3.1415
string字符串。一对双引号或单引号之间的字符。"abc"
'abc'
function自定义函数。print
table表。用{}表示。默认索引从1开始。

2.2 函数

2.2.1 函数定义

语法定义:

lua
function MyFunc(param)
    -- Do something
end

示例:

  • 自定义加函数

    function add(a,b)
    	return a+b
    end
  • 函数调用

    sum = add(3,4)

2.2.2 多返回值

Lua函数可以无返回值,也可以有一个或多个返回值。

示例:

  • 自定义多返回值

    lua
    function add(a,b)
        return a,b,(a+b)
    end
  • 函数调用

    lua
    x,y,z = add(a,b)

2.3 条件语句

2.3.1 if 语句

语法格式:

lua
if(布尔表达式)
then
   --[ 在布尔表达式为 true 时执行的语句 --]
end

2.3.2 if..else 语句

语法格式:

lua
if(布尔表达式)
then
   --[ 布尔表达式为 true 时执行该语句块 --]
else
   --[ 布尔表达式为 false 时执行该语句块 --]
end

2.4 循环语句

2.4.1 while 循环

语法格式:

lua
while(condition)
do
   statements
end

2.4.2 for 循环

  1. 数值for循环

    语法格式:

    lua
    for var=exp1,exp2,exp3 do  
        <执行体>  
    end
  2. 泛型for循环

    语法格式:

    lua
    --打印数组a的所有值  
    number = {"one", "two", "three"}
    for i, num in ipairs(number) do
        print(i, num)
    end

    i是数组索引值,num是对应索引的数组元素值。

    ipairs是Lua提供的一个迭代器函数,用来迭代数组。

2.4.3 repeat...until

语法格式:

lua
repeat
   statements
until( condition )

3.ARCS脚本的API查看方法

可以通过SDK API手册查找Lua脚本的API定义。

步骤如下:

  1. 打开SDK API 手册链接:ARCS SDK API: 首页 (aubo-robotics.cn)

  2. 点击“文件”,可以查看到所有SDK头文件的列表 image-20240321133915548

  3. API分类模块化,一个.h头文件对应一个模块。模块分类如下:

    模块名称头文件名说明
    力控模块force_control.h力控接口
    IO控制模块io_control.hIO控制接口
    运动控制模块motion_control.h运动控制接口
    机器人算法模块robot_algorithm.h机器人算法相关的对外接口
    机器人配置模块robot_config.h获取机器人配置接口,如获取DH参数、碰撞等级、安装位姿等等
    机器人管理模块robot_manage.h机器人管理接口,如上电、启动、拖动示教模式等
    机器人状态模块robot_state.h获取机器人状态接口,如关节速度、关节角度、固件/硬件版本
    数学模块math.h数学方法接口,如欧拉角与四元数转换、位姿的加减运算
    寄存器模块register_control.h寄存器操作接口,用于三个模块之间的数据交换功能
    运行时模块runtime_machine.h脚本解释器运行时接口, 可以实现脚本解释器的暂停、脚本解释器的设置/取消断点
    串口通信模块serial.h串口通信接口
    socket通信模块socket.hSocket通信接口
    同步运行模块sync_move.h同步运行接口
    系统信息模块system_info.h获取系统信息接口,如接口板的版本号、示教器软件的版本号
    日志系统模块trace.h向控制器日志系统注入日志方面的接口

4. 根据模块查找需要的API定义。例如,想查找关节运动的API定义,关节运动属于运动模块,运动模块对应motion_control.h。所以,点击“motion_control.h”。

image-20240321135838885

5. 点击“arcs::common_interface::MotionControl”,可查看其成员函数。

image-20240321140320761

成员函数如下图所示:

image-20240321140602210

7. 找到关节运动对应的函数名——moveJoint,点击“moveJoint”

image-20240321140914092

8. moveJoint函数的定义如下图所示,其中,Lua函数原型就是moveJoint的Lua语法定义。

image-20240321141043123

9. 根据上面moveJoint的Lua函数定义,moveJoint示例如下:

pi = 3.14159265358979323846
-- 关节角,单位:弧度
q = {-0.93/180*pi, -15.77/180*pi, 97.57/180*pi, 23.33/180*pi,    89.99/180*pi, -1.82/180*pi}
moveJoint(Waypoint_1_q, 1, 1, 0, 0)

机械臂以1rad/s的速度和1rad/s^2的加速度做关节运动到路点[-0.93°, -15.77°, 97.57°, 23.33°, 89.99°, -1.82°]。

4. 在示教器中使用脚本的方法

以下是在示教器中新建、编写和运行脚本的操作步骤:

  1. 在“编程”界面中,点击“新建”。新建一个工程。

    image-20240321150041320
  2. 在“模板”程序节点中,选择“脚本”。

    image-20240321150355682
  3. 脚本代码分为“行脚本”和“脚本文件”这两种类型。下面示例讲解的是脚本文件。

    选择“文件”,点击“保存为”。

    image-20240321150944018
  4. 输入脚本文件名,点击“保存”。

    image-20240321151202943
  5. 点击“编辑”

    image-20240321151307307
  6. 将下面代码添加进去。

    lua
    pi = 3.14159265358979323846
    -- 关节⾓,单位:弧度
    Waypoint_1_q = {-0.93/180*pi, -15.77/180*pi, 97.57/180*pi,
    23.33/180*pi, 89.99/180*pi, -1.82/180*pi}
    Waypoint_2_q = {-16.67/180*pi, -21.25/180*pi, 56.19/180*pi,
    -12.57/180*pi, 89.99/180*pi, -17.56/180*pi}
    Waypoint_3_q = {30.22/180*pi, -14.97/180*pi, 61.42/180*pi,
    -13.62/180*pi, 89.99/180*pi, 29.33/180*pi}
    -- 设置运动速度⽐率
    setSpeedFraction(0.8)
    -- 以关节运动的⽅式依次经过3个路点:Waypoint_1、Waypoint_2和Waypoint_3
    moveJoint(Waypoint_1_q, 1, 1, 0, 0)
    -- 将信息打印到aubo_control⽇志中
    textmsg("joint move to waypoint_1")
    moveJoint(Waypoint_2_q, 1, 1, 0, 0)
    textmsg("joint move to waypoint_2")
    moveJoint(Waypoint_3_q, 1, 1, 0, 0)
    textmsg("joint move to waypoint_3")
    image-20240321151542271
  7. 运行程序。

    image-20240321151759348

5. 示教器脚本示例

5.1 textmsg函数

  1. 使用textmsg()可以打印类型为字符串的信息至aubo_control日志中。其打印信息可在示教器的主页界面中看到。

    image-20240321153009674
  2. textmsg的Lua函数定义: textmsg(msg: string) -> nil

  3. 用法:
    (1)当变量类型为String(字符串)时:

    -- 获取机器人的名称
    name = getName()
    textmsg(name)

    (2)当变量类型为Boolean(布尔值) 时:

    -- 机器人是否已经停止下来
    is_steady = isSteady()
    textmsg(tostring(is_steady))

    (3)当变量类型为Number(数字) 时:

    -- 获取机器人的模式状态
    mode_type = getRobotModeType()
    textmsg("The type of robot mode is "..mode_type)

    (4)当变量类型为Table(表) 时:

    -- 获取当前的机械臂关节角度
    joint_positions = getJointPositions()
    textmsg(table.concat(joint_positions, ', '))

5.2 TCP/IP通信示例

5.2.1 实现TCP/IP通信的方法

这里有两种方法可以实现机器人和外部设备的socket通信:

  • 方法1是使用Lua的Socket库。

    Lua的Socket库是一种通用的网络编程库,允许在Lua脚本中创建Socket连接,进行数据传输和接收。

  • 方法2是使用由遨博提供的Socket类Lua接口。

    遨博提供了专门的Socket类脚本接口,允许机器人直接与外部设备进行通信。

5.2.2 遨博的Socket类Lua接口介绍

  1. socketOpen

    • 函数定义:

      lua
      socketOpen(address: string, port: number, socket_name: string) -> nil
    • 功能:建立TCP/IP以太网socket通信

    • 参数:

      • address:目标服务器的IP地址
      • port:目标服务器的端口号
      • socket_name:socket名称
    • 示例:

      lua
      socketOpen('192.168.10.46', '8000', "socket_0")
  2. socketSendLine

    • 函数定义:

      lua
      socketSendLine(str: string, socket_name: string) -> nil
    • 功能:向服务器发送带有换行字符的字符串,以ASCII编码将字符串通过socket发送

    • 参数:

      • str:要发送的字符串
      • socket_name:socket名称
    • 示例:

      lua
      socketSendLine("abcd", "socket_0")
  3. socketReadString

    • 函数定义:

      lua
      socketReadString(variable: string, socket_name: string, prefix: string, suffix: string, interpret_escape: boolean) -> number
    • 功能:从socket中读取所有数据,并将数据作为字符串返回

    • 参数:

      • variable:要读取的字符串
      • socket_name:socket 名称
      • prefix:指定了从socket中提取的子串(消息)的起始位置。从socket中到达 "prefix" 结束的数据将被忽略和移除
      • suffix:指定了从socket中提取的子串(消息)的结束位置。在 "suffix" 之后的任何剩余数据将被保留
      • interpret_escape:表示是否解释转义字符。如果设置为true,函数会解释字符串中的转义字符(例如'\r'、'\n'、'\t'等),如果设置为false,则不会解释转义字符,而是将其原样返回
    • 示例:

      lua
      socketReadString("camera", "socket_0", "", "", false)
  4. socketClose

    • 函数定义:

      lua
      socketClose(socket_name: string) -> nil
    • 功能:关闭与服务器的socket连接

    • 参数:

      • socket_name:socket 名称
    • 示例:

      lua

    socketClose("socket_0") ```

5.2.3 通过脚本实现TCP/IP通信的操作步骤

操作步骤如下:

  1. 确认外部设备与机器人处于同一局域网中,保证双方可以互相ping通(Windows系统建议关闭防火墙)。

  2. 以机器人为客户端,外部设备为服务端,方法1和方法2的脚本代码示例分别如下。

    • 方法1:使用Lua的Socket库来实现TCP通信
    lua
    local socket = require("socket.core")
    local tcp = socket.tcp()
    local host = '192.168.10.46' --服务端IP地址
    local port = '8000' --串口号
    
    local clicon = tcp:connect(host,port)
    if(clicon) then
        textmsg('connect '..host..' ok!')
    else
        textmsg('connect error')
    end
    
    take_photo = "get" --发送给服务端的字符串
    
    tcp:settimeout(2)
    
    str1 = nil --服务端发送的数据
    
    while (true) do  
        --如果服务端关闭则停止循环
        if status =="closed" then
            textmsg("server is closed!")
            break 
        end
    
        --发送给服务端字符串
        tcp:send(take_photo)
        sleep(1)
        
        --接收服务端发送的字符串,只有接收到good,停止循环
        s, status, str1 = tcp:receive()
        if str1 == "good" then
            textmsg("receive: "..str1)
            break
        end
    
    end
    
    tcp:close()

    这段代码的主要作用是机器人与指定的服务端建立TCP连接,然后发送字符串 "get" 给服务端,并且持续接收服务端发送的数据,直到接收到 "good" 字符串为止,最后关闭TCP连接。

    • 方法2:使用由遨博提供的Socket类接口来实现TCP通信
    lua
    ip = "192.168.10.46" --服务端IP地址
    port = 8000 --串口号
    client_name = "socket_0" --客户端名称
    rec_key = "camera" --接收服务端发送的字符串
    socketOpen(ip, port, client_name) ----与服务端建立通信
    socketSendLine("abcd", client_name) --发送给服务端字符串
    sleep(1)
    
    rec_str = ""
    --接收服务端发送的字符串后停止循环
    while(rec_str == nil or rec_str == "") 
    do
        socketReadString(rec_key, client_name, "", "", false) 
        sleep(0.1)
        rec_str = getString(rec_key, "")
        textmsg("**********")
        textmsg(rec_str)
        textmsg("**********")
        sleep(1)
        socketSendLine("dfgh", client_name)
    end
    
    socketClose(client_name)

    这段代码的主要作用机器人是与服务端建立Socket连接,发送一些字符串给服务端,然后循环地接收服务端发送的字符串,直到接收到非空的字符串为止,最后关闭与服务端的socket连接。

  3. 以TCP调试助手来模拟服务端,指定服务器的监听端口号为8000。

    image-20240401151447235
  4. 以机械臂作为客户端,修改方法1或方法2的示例代码中服务器的IP地址和端口号。

  5. 在示教器中新建一个脚本模板,运行方法1或方法2中的脚本示例。

    注意:运行工程前,请取消勾选”程序一直循环“。

    image-20240401152501845
  6. 运行结果如下:

    • 方法1:使用Lua的Socket库来实现TCP通信

      运行示教器工程后,TCP调试助手会一直接收到机器人发送的“get”字符串。

      image-20240401152824063

      在TCP调试助手中向机器人发送“good”字符串后,

      image-20240401153418282

      机器人停止循环发送“get”字符串,并且关闭socket连接。

      image-20240401153645540
    • 方法2:使用由遨博提供的Socket类接口来实现TCP通信

      运行示教器工程后,TCP调试助手会一直接收到机器人发送的“dfgh”字符串。

      image-20240401155918475

      在TCP调试助手中向机器人发送一个非空的字符串,例如“stop”后,

      image-20240401160036819

      机器人停止循环发送“dfgh”字符串,并且关闭socket连接。