本文就基于 C#的 ABB 机械臂二次开发相关内容做一个介绍,主要包括与机械臂控制器的连接和断开、机械臂 RAPID 程序变量的读写、机械臂输入信号的监听和输出信号的控制、机械臂当前位姿的读取。

ABB SDK

经过两年多对机械臂的接触,真觉得 ABB 机械臂好用。不仅仅是因为精度较高,更重要的是比较开放,支持 C#的二次开发,甚至也支持网络服务器开发,通过 RESTful API 实现控制。个人认为是机械臂行业的龙头老大。

https://developercenter.robotstudio.com/pc-sdk

这个网址是 ABB 机械臂 PC SDK 的开发者中心,提供了 C#、VB 两种语言的二次开发 API 文档和一些简单案例。但目前似乎只支持 Windows 系统。我采用的是 C#语言进行开发。

在这个网址找到 SDK 安装包并安装到本地,在目录中找到三个 dll 文件(ABB.Robotics.Controllers.PC.dllRobotStudio.Services.RobApi.dllRobotStudio.Services.RobApi.Desktop.dll),在 C#程序中对其进行引用。

ABB SDK结构

ABB SDK结构

上图是 SDK 源程序的结构图,在项目开头引入对应命名空间。

1
2
3
4
5
using ABB.Robotics.Controllers;
using ABB.Robotics.Controllers.Discovery;
using ABB.Robotics.Controllers.MotionDomain;
using ABB.Robotics.Controllers.RapidDomain;
using ABB.Robotics.Controllers.IOSystemDomain;

然后就可以敲代码实现一些功能了。

机械臂控制器的连接和断开

先上代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
private NetworkScanner scanner = null;
public Controller robot = null;

private void Form1_Load(object sender, EventArgs e)
{
//机器人通信模块
try
{
scanner = new NetworkScanner();
}
catch (Exception)
{
MessageBox.Show("ABBSDK初始化错误");
}
}

private void btn_ConnectRob_Click(object sender, EventArgs e)
{
try
{
//扫描网络中的控制器
scanner.Scan();
//获取扫描到的控制器信息
ControllerInfoCollection controllers = scanner.Controllers;
//遍历信息
foreach (ControllerInfo controllerInfo in controllers)
{
//判断控制器是否可用,是否是需要连接的
if (controllerInfo.Availability == Availability.Available && (controllerInfo.SystemName == textB_RobID.Text || controllerInfo.Id == textB_RobID.Text))
{
//创建控制器对象
robot = ControllerFactory.CreateFrom(controllerInfo);
//登录
robot.Logon(UserInfo.DefaultUser);
MessageBox.Show("robot登录成功");
}

}
if (robot == null)
{
MessageBox.Show("robot登录失败,未找到对应机械臂");
}
}
catch (Exception exception)
{
MessageBox.Show(exception.Message, Name, MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}

private void btn_CloseRob_Click(object sender, EventArgs e)
{
try
{
//判断是否已连接
if (RobControl.IsConnected(robot))
{
//控制器登出
robot.Logoff();
MessageBox.Show("robot已断开连接");
}
}
catch (Exception exception)
{
MessageBox.Show(exception.Message, Name, MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}

}

//判断是否连接
public bool IsConnected(Controller controller)
{
if (controller == null || controller.CurrentUser == null) return false;
return controller.Connected;
}

控件设计如下:
两个按钮分别控制控制器的连接和断开,连接控制器时连接名称为 TextBox 文本字符串的控制器。

连接断开控制器

连接断开控制器

连接控制器的基本流程是:

  1. 先创建一个扫描器,使用Scan()对当前局域网中的所有机械臂控制器进行扫描;
  2. 通过扫描器的Controllers属性将所有信息存入集合中,每个控制器信息以ControllerInfo的形式储存,包含的控制器的名称、ID、IP、是否虚拟、是否可用等信息。
  3. 创建一个Controller对象,调用ControllerFactory.CreateFrom()方法创建控制器,方法传入扫描到的ControllerInfo
  4. 使用控制器的Logon()方法实现登录。

断开控制器就比较简单了,对已登录的控制器执行Logoff()方法登出。

机械臂 RAPID 程序变量的读写

首先是变量读取:

1
2
3
RapidData rapiddata = robot1.Rapid.GetTask(cTasks1.Text.ToString()).GetModule(cBmodules1.Text.ToString()).GetRapidData(cvalue1.Text.ToString());
value1.Text = rapiddata.StringValue.ToString();
textBox1.Text = rapiddata.RapidType.ToString();

依次通过 TaskModule、变量名获取对应的RapidData,然后可以通过RapidDataStringValue属性获取值、通过RapidType变量类型。

对于变量写入,必须要将机械臂控制器置于自动模式,而且要事先知道要修改变量的类型:

1
2
3
4
5
6
7
8
9
10
11
RapidData data = robot1.Rapid.GetTask(cTasks1.Text.ToString()).GetModule(cBmodules1.Text.ToString()).GetRapidData(cvalue1.Text.ToString());
if (data.RapidType.ToString() == "robtarget")
{
RobTarget tempdata = (RobTarget)data.Value;
tempdata.FillFromString2(value1.Text.ToString());
//请求权限并写入控制器
using (Mastership m = Mastership.Request(robot1.Rapid))
{
data.Value = tempdata;
}
}

首先读出要写入的变量,获取RapidData类型数据,将其值强制转换为其类型,通过FillFromString2()方法传入新值的内容,然后请求权限将这个值重新赋给RapidData数据的值即可。

机械臂输入信号的监听和输出信号的控制

机械臂的 IO 操作需要调用开发包的IOSystem模块。下面针对数字信号,实现信号读取、信号值改变、输入信号监听三个方面。

信号获取

1
2
3
Signal sig = robot.IOSystem.GetSignal(IOName.Text);
DigitalSignal digitalSig = (DigitalSignal)sig;
int val = digitalSig.Get();

获取的val即为名为IOName.Text的数字信号的值,为 0 或 1。

信号写入

1
2
3
4
5
6
7
8
9
10
Signal sig = robot1.IOSystem.GetSignal(IOName.Text);
DigitalSignal digitalSig = (DigitalSignal)sig;
if (IOValue.Text == "1")
{
digitalSig.Set();
}
else if (IOValue.Text == "0")
{
digitalSig.Reset();
}

digitalSig.Set()表示将数字信号置 1,digitalSig.Reset()表示将数字信号置 0。

信号监听

可以向信号的Changed事件添加预订,该预订在信号状态反转时触发。

1
2
3
4
5
6
7
8
9
10
Signal sig = robot1.IOSystem.GetSignal(IOName.Text);
DigitalSignal digitalSig = (DigitalSignal)sig;
sig.Changed += new EventHandler<SignalChangedEventArgs>(sig_Changed);

private void sig_Changed(object sender, SignalChangedEventArgs e)
{
//通过e获取监听到的信号状态
SignalState state = e.NewSignalState;
float val = state.Value;
}

通过val可以获取监听变量的值,如果值变为期望的状态则可以在后续代码添加相应的动作。

机械臂当前位姿的读取

获取当前位姿的功能在开发包的MotionSystem中。获取当前位姿有两种形式:

  1. 一种是获取当前机械臂末端位姿,包含 xyz 坐标和四元数构成的姿态;
  2. 另一种是六个关节的偏移角。

首先看第一种,获取末端位姿:

1
2
3
4
5
6
7
8
RobTarget robtarget = robot1.MotionSystem.ActiveMechanicalUnit.GetPosition(CoordinateSystemType.WorkObject);
xvalue.Text = robtarget.Trans.X.ToString();
yvalue.Text = robtarget.Trans.Y.ToString();
zvalue.Text = robtarget.Trans.Z.ToString();
q1value.Text = robtarget.Rot.Q1.ToString();
q2value.Text = robtarget.Rot.Q2.ToString();
q3value.Text = robtarget.Rot.Q3.ToString();
q4value.Text = robtarget.Rot.Q4.ToString();

然后是第二种,获取六关节偏移角:

1
2
3
4
5
6
7
JointTarget jointtarget = robot1.MotionSystem.ActiveMechanicalUnit.GetPosition();
value1.Text = a.RobAx.Rax_1.ToString();
value2.Text = a.RobAx.Rax_2.ToString();
value3.Text = a.RobAx.Rax_3.ToString();
value4.Text = a.RobAx.Rax_4.ToString();
value5.Text = a.RobAx.Rax_5.ToString();
value6.Text = a.RobAx.Rax_6.ToString();