ARCS 脚本编程快速入门

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开始。 {1, 2, 3}

2.2 函数

2.2.1 函数定义

语法定义:

function MyFunc(param)
    -- Do something
end

示例:

  • 自定义加函数

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

      sum = add(3,4)
    

2.2.2 多返回值

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

示例:

  • 自定义多返回值

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

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

2.3 条件语句

2.3.1 if 语句

语法格式:

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

2.3.2 if..else 语句

语法格式:

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

2.4 循环语句

2.4.1 while 循环

语法格式:

while(condition)
do
   statements
end

2.4.2 for 循环

  1. 数值for循环

    语法格式:

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

    语法格式:

     --打印数组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

语法格式:

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.h IO控制接口
    运动控制模块 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.h Socket通信接口
    同步运行模块 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. 将下面代码添加进去。

     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

    • 函数定义:

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

    • 参数:

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

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

    • 函数定义:

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

    • 参数:

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

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

    • 函数定义:

        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,则不会解释转义字符,而是将其原样返回
    • 示例:

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

    • 函数定义:

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

    • 参数:

      • socket_name:socket 名称
    • 示例:

      socketClose("socket_0")
      

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

操作步骤如下:

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

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

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

      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通信

      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连接。

results matching ""

    No results matching ""