背景介绍
目前,市面上大多数的拖动试教机器人是UR的协作机器人和DLR-KUKA的iiwa机器人,相比于UR机器人,iiwa机器人在结构上有一点重要的不同。
UR在每个关节上采取的是双编码器的方式,分别测量电机角度和连杆角度。而iiwa机器人在每个关节上还加入了一个单轴力矩传感器(一般位于减速器输出端与末端连杆间),用于测量每个关节的输出力矩。如图所示,iiwa在牵引拖动时表现更好,同时iiwa机器人拥有更小的运动盲区。用户可以施加更小的力就可以牵着机器人按其意图运动,而不会担心机械臂运动受限。
ROS API说明
以iiwa为代表的七轴机械臂在高精度的工作中有着很重要的应用,但是作为以java语言为驱动的机械臂,相较于以python为驱动的UR机械臂而言,其上手难度更高,难以去进行二次开发。之前常用的开发主要通过SunriseWorkbench等软件进行的开发。难以满足现有的分布式控制需求。为此也有很多人通过使用ROSjava来对iiwa机器人进行开发。但是ROSjava已在几年前停止了维护。为此本文尝试通过TCP+ROS+Python的搭建方法来满足机械臂的驱动需求。本文为KUKA-iiwa 智能机器人提供了应用程序编程接口(API)。来支持后续的iiwa开发工作。该API建立在KUKA iiwa内核安全性的基础上,可实现紧密的工作并与操作员进行交互。它将功能引入了机器人操作系统(ROS),后者提供了一个分布式开发环境,同时允许多种新的设备形式轻松地进行接口。
API架构
开发的API设计得很简单,通过TCP通讯建立出一套方便与ROS交互开发的平台。API体系结构侧重于突破通常在Smartpad上运行的KUKA Sunrise控制器中可用的功能。通过使用下图所示的通用结构,可以看到该体系结构扩展了KUKA LBR iiwa的功能。API公开了在机器网络上操作的接口。这允许在KUKA LBR iiwa的操作中轻松部署和利用不同的传感方法和额外的计算资源。
KUKA-iiwa的守护程序还处理一些低级但通用和关键的控制任务,例如碰撞检测。这样的操作可以给我们的二次开发提供基础的安全保障。ROS-KUKA节点也以Python脚本语言实现,通过订阅ROS节点来使KUKA守护程序和ROS主节点之间起到中间接口的作用。通过python订阅来自其他控制ROS节点的命令,并将它们传递给KUKA服务端。这样可以实现良好的外部扩展。同样,它从KUKA服务端接收感官和状态信息,并通过ROS将其其发布到python中。从而实现在计算机上不安装KUKA Sunrise OS即可外部运行此ROS-KUKA节点,这意味着无需修改KUKA Sunrise Cabinet。因此,保留了KUKA提供的安全协议,并且添加了功能而不是对其进行了更改。无需在Sunrise OS上安装第三方软件(例如ROS),只需使用基于标准Sunrise的应用程序就可以设置KUKA iiwa ROS接口。
下表列出了可通过API调用的ROS主题以读取KUKA-iiwa内部的参数
订阅主题名称 | 描述 | 例子 |
JointPosition [A1,A2,A3,A4,A5,A6,A7]time | 对应了iiwa7个自由度 | JointPosition [0.0, 0.17, 0.0, 1.92, 0.0,0.35, 0.0] 1459253274.1 |
ToolPosition [X, Y, Z, A, B, C] time | 工具末端的位置以及三个旋转量 | ToolPosition [433.59711426170867,0.028881929589094864, 601.4449734558293,3.1414002368275726, 1.0471367465304213,3.141453681799645] 1459253274.11 |
ToolForce [X, Y, Z] time | 力模式施加的力 | ToolForce [13.485958070668463,0.3785658886199012, 5.964988607372689] 1459253274.11’ |
ToolTorque [A, B, C] time | 设置对应的三个扭矩参数 | ToolTorque [13.485958070668463, 0.3785658886199012, 5.964988607372689] 1459253274.11’ |
JointAcceleration Float time | joint关节加速度值 | JointAcceleration 0.4 1459253274.11’ |
JointVelocity Float time | joint关节速度值 | JointVelocity 1.0 1459253274.11’ |
JointJerk Float time | 关节选取最优的jerk | JointJerk 1.0 1459253274.11’ |
isCompliance Boolean time | 判断机器人状态是否符合规范 | isCompliance off 1459253274.11’ |
isReadyToMove Boolean time | 判断机器人是否执行完所有步骤 | isReadyToMove true 1459253274.11’ |
isCollision Boolean time | 检测是否碰撞 | isCollision false 1459253274.11’ |
isMastered Boolean time | 是否为主程序 | isMastered true 1459253274.11’ |
isJointOutOfRange Boolean time | 是否超出设定值范围 | isJointOutOfRange false 1459253274.11’ |
另外一个表列出了可通过字符串调用的ROS主题以向KUKA-iiwa发送指令
订阅主题名称 | 描述 | 例子 |
setJointAcceleration F | 设定/变更关节加速度值 | ’setJointAcceleration 0.4’ |
setJointVelocity F | 设定/更改关节速度值 | ’setJointVelocity 1.0’ |
setJointJerk F | 设置/更改关节Jerk速度值 | ’setJointJerk 1.0’ |
setPosition A1 A2 A3 A4 A5 A6 A7 ptp/lin | 根据关节位置移动机器人手臂。可以选择点对点(ptp)或线性(lin)运动。float类型的角度值(以度为单位)可以在A1-7中替换。如果不需要移动任何轴,可以使用-代替值。该示例为除A2不变的每个轴分配新位置。 | ’setPosition 0 21 0 -100 0 60 0 ptp’ |
setPositionXYZABC X Y Z A B C ptp/lin | 在机器人笛卡尔空间中移动机器人末端执行器。可以选择点对点(ptp)或线性(lin)运动。这会将机器人末端执行器移动到特定位置[x,y,z]方向[a,b,c](浮点中的值)。如果不需要更改任何参数,可以使用-代替值。 | ’setPositionXYZABC 700 0 290 – 180 0 -180 lin’ |
MoveXYZABC X Y Z A B C | 仅通过点对点(ptp)运动在机器人笛卡尔空间中移动机器人末端执行器。对于给定值(以毫米和度为单位),这会将机器人末端执行器沿特定方向[x,y,z]和/或方向[a,b,c]移动。 | MoveXYZABC 10 20 0 30 0 0 |
MoveCirc X1 Y1 Z1 A1 B1 C1 X2 Y2 Z2 A2 B2 C2 BlendingOri | 以给定的混合值将机器人末端执行器从第一个位置( [x1 y1 z1 a1 b1c1])的当前位置以弧形/圆周运动从其当前位置移动到第二个位置([x2y2 z2 a2 b2 c2]) 。 | MoveCirc 700 0 290 -180 0 -180 710 0 300 -180 0 -180 0.1 |
setCompliance X Y Z Z B C | 在每个x,y,z,a,b和c中具有特定刚度的情况下激活机器人的Compliance模式。给定的示例仅在x和y直角坐标系中以非常低的刚度激活Compliance。 | ’setCompliance 10 10 5000 300 300 300’ |
resetCompliance | 停用机器人的“合规性”模式 | ’resetCompliance’ |
resetCollision | 如果检测到任何碰撞,则重置碰撞 | ’resetCollision’ |
forceStop | 停止机器人并删除所有等待执行的机器人运动队列 | ’forceStop’ |
setWorkspace xmin ymin zmin xmax ymax zmax | 定义工作区边界 | ‘SetWorkspace 100 -300 0 600 300 500’ |
ROS环境搭建
安装api
如前所述,API有两个主要部分:1)KUKA守护程序(java)和2)ROSKUKA节点(Python)。KUKA守护程序可以作为标准KUKA应用程序安装在KUKA Sunrise Cabinet上:
1) 将“ ROS_API”文件夹作为新的Java包导入到您的KUKA Sunrise项目中(记得电脑与KUKA通过网线相连,并在Sunrise中发现示例程序后)。
ROS_API/ROS.java
package application;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import com.kuka.common.ThreadUtil;
import com.kuka.roboticsAPI.applicationModel.RoboticsAPIApplication;
import static com.kuka.roboticsAPI.motionModel.BasicMotions.*;
import com.kuka.roboticsAPI.conditionModel.ICallbackAction;
import com.kuka.roboticsAPI.conditionModel.ICondition;
import com.kuka.roboticsAPI.conditionModel.JointTorqueCondition;
import com.kuka.roboticsAPI.deviceModel.Device;
import com.kuka.roboticsAPI.deviceModel.JointEnum;
import com.kuka.roboticsAPI.deviceModel.JointPosition;
import com.kuka.roboticsAPI.deviceModel.LBR;
import com.kuka.roboticsAPI.executionModel.IFiredTriggerInfo;
import com.kuka.roboticsAPI.geometricModel.CartDOF;
import com.kuka.roboticsAPI.geometricModel.Frame;
import com.kuka.roboticsAPI.geometricModel.Tool;
import com.kuka.roboticsAPI.motionModel.ErrorHandlingAction;
import com.kuka.roboticsAPI.motionModel.IMotionContainer;
import com.kuka.roboticsAPI.motionModel.IErrorHandler;
import com.kuka.roboticsAPI.motionModel.MotionBatch;
import com.kuka.roboticsAPI.motionModel.OrientationReferenceSystem;
import com.kuka.roboticsAPI.motionModel.controlModeModel.CartesianImpedanceControlMode;
import com.kuka.roboticsAPI.uiModel.ApplicationDialogType;
/*******************************************************
* 您需要在“模板数据->模板工具组”中创建一个tool1并将其命名为“ tool”。
* 在“ tool1”下插入新的空白框架,并将其命名为“ TCP”。
* 在“ tool1”的属性中,设置transformation值。
* 在“ tool1”的属性中,选择“ TCP”作为“Default Motion Frame”。
* 使机器人与Sunrise Workbench同步.
* 在机器人控制板上,对工具执行自动载荷数据确定.
*******************************************************/
public class ROS extends RoboticsAPIApplication {
public boolean RUN = false; // socket是否已连接并且应用程序正在运行?
public boolean isCompliance = false;//机器人是否为顺从模式
public boolean isCollision = false;//机器人是否碰撞
public LBR lbr; // Kuka iiwa机器人
public Tool tool;//导入tool工具
public PrintWriter outputStream;//输出数据流
public BufferedReader inputStream;//输入数据流
public Socket skt; // TCP Socket
public String CommandStr; // 命令字符串
String []strParams = new String[20];
float []params = new float[10];
public long LastReceivedTime = System.currentTimeMillis();//当前系统时间
public double JointAcceleration;//关节加速度
public double JointVelocity;//关节速度
public double JointJerk;//关节的加加速度
public double Acceleration = 1.0;//加速度
public double Velocity = 1.0;//速度
public double CartVelocity = 10;
public IMotionContainer handleCompliance;//处理顺从模式
public CartesianImpedanceControlMode cartImpCtrlMode = new CartesianImpedanceControlMode();//笛卡尔阻抗控制模式
public boolean isCartImpCtrlMode = false;//是CartImp Ctrl模式
private IErrorHandler errorHandler;
//===========================================================
public void initialize() {
getController("KUKA_Sunrise_Cabinet_1");//获取KUKA Sunrise Cabinet控制器
lbr = getContext().getDeviceFromType(LBR.class);//获取kuka机器人的编号
tool = getApplicationData().createFromTemplate("tool1");//获取template data 里面 tool1的参数
tool.attachTo(lbr.getFlange());//将对应的数据绑到机器人上
JointAcceleration = 1.0;
JointVelocity = 1.0;
JointJerk = 1.0;//加加速度
cartImpCtrlMode.parametrize(CartDOF.X).setStiffness(5000.0);//x方向的刚度设置,所需要的力
cartImpCtrlMode.parametrize(CartDOF.Y).setStiffness(5000.0);
cartImpCtrlMode.parametrize(CartDOF.Z).setStiffness(5000.0);
cartImpCtrlMode.parametrize(CartDOF.A).setStiffness(300.0);
cartImpCtrlMode.parametrize(CartDOF.B).setStiffness(300.0);
cartImpCtrlMode.parametrize(CartDOF.C).setStiffness(300.0);
cartImpCtrlMode.parametrize(CartDOF.ALL).setDamping(1.0);//设置阻尼
errorHandler = new IErrorHandler() {//触发的error打印
@Override
public ErrorHandlingAction handleError(Device device,
IMotionContainer failedContainer,
List<IMotionContainer> canceledContainers) {
getLogger().warn("Excecution of the following motion failed: "
+ failedContainer.getCommand().toString());
getLogger().info("The following motions will not be executed:");
for (int i = 0; i < canceledContainers.size(); i++) {
getLogger().info(canceledContainers.get(i)
.getCommand().toString());
}
return ErrorHandlingAction.Ignore;
}
};
getApplicationControl()
.registerMoveAsyncErrorHandler(errorHandler);//注册移动异步错误处理程序
}
public void socketConnection() // 正在连接到服务器 172.31.1.50 Port:1234
{
System.out.println("Connecting to server at 172.31.1.50 Port:1234");
while (true){
try{
skt = new Socket("172.31.1.50", 1234); // 如果需要,请根据运行ROS-KUKA节点服务器的系统修改IP和端口
System.out.println("KUKA iiwa is connected to the server.");
break;
}
catch(IOException e1){
System.out.println("ERROR connecting to the server!");
}
}
try{
outputStream = new PrintWriter(skt.getOutputStream(), true);//打印出数据
inputStream = new BufferedReader(new InputStreamReader(skt.getInputStream()));//从Buffer读取数据
RUN = true;
}
catch(IOException e)
{
System.out.println("Error creating inPort and outPort");
}
}
public void reply(PrintWriter outputStream, String buffer)//调用outputstream输出对应的指令
{
outputStream.write(buffer);
outputStream.flush();
}
public String getLine(BufferedReader inputStream)
{
String line;
try{
while(!inputStream.ready()){}
line = inputStream.readLine();
//System.out.println("Command received: " + line);
return line;
}
catch(Exception e){
return "Error command";
}
}
public void behaviourAfterCollision() {
isCollision = true;//将是否碰撞设为真
IMotionContainer handle;
CartesianImpedanceControlMode CollisionSoft = new CartesianImpedanceControlMode();//笛卡尔阻抗控制模式
CollisionSoft.parametrize(CartDOF.ALL).setDamping(.7);
CollisionSoft.parametrize(CartDOF.ROT).setStiffness(100);
CollisionSoft.parametrize(CartDOF.TRANSL).setStiffness(600);
handle = tool.moveAsync(positionHold(CollisionSoft, -1, TimeUnit.SECONDS));
/*getApplicationUI().displayModalDialog(ApplicationDialogType.WARNING,
"Collision Has Occurred!\n\n LBR is compliant...",
"Continue");*/
handle.cancel();
}
public ICondition defineSensitivity() {
//double sensCLS = getApplicationData().getProcessData("sensCLS").getValue(); // Uncomment if you have "sensCLS" defined.
double sensCLS = 30; // Modify the value if required.
//Offsetkompensation
double actTJ1 = lbr.getExternalTorque().getSingleTorqueValue(JointEnum.J1);
double actTJ2 = lbr.getExternalTorque().getSingleTorqueValue(JointEnum.J2);
double actTJ3 = lbr.getExternalTorque().getSingleTorqueValue(JointEnum.J3);
double actTJ4 = lbr.getExternalTorque().getSingleTorqueValue(JointEnum.J4);
double actTJ5 = lbr.getExternalTorque().getSingleTorqueValue(JointEnum.J5);
double actTJ6 = lbr.getExternalTorque().getSingleTorqueValue(JointEnum.J6);
double actTJ7 = lbr.getExternalTorque().getSingleTorqueValue(JointEnum.J7);
//Abbruchbedingungen pro Achse
JointTorqueCondition jt1 = new JointTorqueCondition(JointEnum.J1, -sensCLS+actTJ1, sensCLS+actTJ1);
JointTorqueCondition jt2 = new JointTorqueCondition(JointEnum.J2, -sensCLS+actTJ2, sensCLS+actTJ2);
JointTorqueCondition jt3 = new JointTorqueCondition(JointEnum.J3, -sensCLS+actTJ3, sensCLS+actTJ3);
JointTorqueCondition jt4 = new JointTorqueCondition(JointEnum.J4, -sensCLS+actTJ4, sensCLS+actTJ4);
JointTorqueCondition jt5 = new JointTorqueCondition(JointEnum.J5, -sensCLS+actTJ5, sensCLS+actTJ5);
JointTorqueCondition jt6 = new JointTorqueCondition(JointEnum.J6, -sensCLS+actTJ6, sensCLS+actTJ6);
JointTorqueCondition jt7 = new JointTorqueCondition(JointEnum.J7, -sensCLS+actTJ7, sensCLS+actTJ7);
ICondition forceCon = jt1.or(jt2, jt3, jt4, jt5, jt6, jt7);
return forceCon;
}
private IMotionContainer _currentMotion;//当前运动状态
public void MoveSafe(MotionBatch MB) {
ICondition forceCon = defineSensitivity();//定义灵敏度
ICallbackAction ica = new ICallbackAction() {//回调行为
@Override//override伪代码,表示方法重写,对ica.onTriggerFire调用
public void onTriggerFired(IFiredTriggerInfo triggerInformation)
{
triggerInformation.getMotionContainer().cancel();//获取运动容器
behaviourAfterCollision();//在碰撞后
}
};
if(isCartImpCtrlMode)//是否CartImp Ctrl模式
{
MB.setJointAccelerationRel(JointAcceleration)
.setJointVelocityRel(JointVelocity)
.setMode(cartImpCtrlMode)
.triggerWhen(forceCon, ica);
}
else
{
MB.setJointAccelerationRel(JointAcceleration)
.setJointVelocityRel(JointVelocity)
.triggerWhen(forceCon, ica);
}
if(lbr.isReadyToMove())//是否准备移动
this._currentMotion=tool.moveAsync(MB);//异步移动
}
//===========================================================
public void setTool(String message){ // 设置tool的名字,receives: "setTool TOOLNAME"
strParams = message.split(" ");
if (strParams.length==2){
tool = getApplicationData().createFromTemplate(strParams[1]);
tool.attachTo(lbr.getFlange());
getLogger().info("Switched to " + strParams[1]);
}
else{
getLogger().info("Unacceptable 'setTool' command!");
}
}
public void setJointAcceleration(String message){
strParams = message.split(" ");
if (strParams.length==2)
params[0] = Float.parseFloat(strParams[1]);
if (0.0 < params[0] && params[0] <= 1.0)
JointAcceleration = params[0];
else
getLogger().info("JointAcceleration must be 0<JA<=1");
}
public void setJointVelocity(String message){
strParams = message.split(" ");
if (strParams.length==2)
params[0] = Float.parseFloat(strParams[1]);
if (0.0 < params[0] && params[0] <= 1.0)
JointVelocity = params[0];
else
getLogger().info("JointVelocity must be 0<JV<=1");
}
public void setJointJerk(String message){//加加速度
strParams = message.split(" ");
if (strParams.length==2)
params[0] = Float.parseFloat(strParams[1]);
if (0.0 < params[0] && params[0] <= 1.0)
JointJerk = params[0];
else
getLogger().info("JointJerk must be 0<JJ<=1");
}
public void CartVelocity(String message){
strParams = message.split(" ");
if (strParams.length==2)
params[0] = Float.parseFloat(strParams[1]);
if (0.0 < params[0] && params[0] <= 10000)
CartVelocity = params[0];
else
getLogger().info("CartVelocity must be 0<CV<=10000");
}
public void setPosition(String message) // "setPosition A0 A1 - A3 A4 A5 A6" 这只是ptp动作
{ strParams = message.split(" ");
double A0 = lbr.getCurrentJointPosition().get(0);
double A1 = lbr.getCurrentJointPosition().get(1);
double A2 = lbr.getCurrentJointPosition().get(2);
double A3 = lbr.getCurrentJointPosition().get(3);
double A4 = lbr.getCurrentJointPosition().get(4);
double A5 = lbr.getCurrentJointPosition().get(5);
double A6 = lbr.getCurrentJointPosition().get(6);
if (strParams.length==8){
if( !strParams[1].equals("-") )
A0 = Math.toRadians( Float.parseFloat(strParams[1]) );
if( !strParams[2].equals("-") )
A1 = Math.toRadians( Float.parseFloat(strParams[2]) );
if( !strParams[3].equals("-") )
A2 = Math.toRadians( Float.parseFloat(strParams[3]) );
if( !strParams[4].equals("-") )
A3 = Math.toRadians( Float.parseFloat(strParams[4]) );
if( !strParams[5].equals("-") )
A4 = Math.toRadians( Float.parseFloat(strParams[5]) );
if( !strParams[6].equals("-") )
A5 = Math.toRadians( Float.parseFloat(strParams[6]) );
if( !strParams[7].equals("-") )
A6 = Math.toRadians( Float.parseFloat(strParams[7]) );
MotionBatch motion = new MotionBatch(ptp(A0,A1,A2,A3,A4,A5,A6).setJointJerkRel(JointJerk));//设置对应的7个角度
MoveSafe(motion);//移动到该点
}
else{
getLogger().info("Unacceptable 'setPosition' command!");
}
}
public void setPositionXYZABC(String message) // setPositionXYZABC x y z a - c ptp/lin
{
double x = lbr.getCurrentCartesianPosition(tool.getDefaultMotionFrame()).getX();
double y = lbr.getCurrentCartesianPosition(tool.getDefaultMotionFrame()).getY();
double z = lbr.getCurrentCartesianPosition(tool.getDefaultMotionFrame()).getZ();
double a = lbr.getCurrentCartesianPosition(tool.getDefaultMotionFrame()).getAlphaRad();
double b = lbr.getCurrentCartesianPosition(tool.getDefaultMotionFrame()).getBetaRad();
double c = lbr.getCurrentCartesianPosition(tool.getDefaultMotionFrame()).getGammaRad();
strParams = message.split(" ");
if (strParams.length==8){
if( !strParams[1].equals("-"))
x = Float.parseFloat(strParams[1]);
if( !strParams[2].equals("-"))
y = Float.parseFloat(strParams[2]);
if( !strParams[3].equals("-"))
z = Float.parseFloat(strParams[3]);
if( !strParams[4].equals("-"))
a = Math.toRadians( Float.parseFloat(strParams[4]) );
if( !strParams[5].equals("-"))
b = Math.toRadians( Float.parseFloat(strParams[5]) );
if( !strParams[6].equals("-"))
c = Math.toRadians( Float.parseFloat(strParams[6]) );
Frame f = new Frame(getApplicationData().getFrame("/Air"), x, y, z, a, b, c );//获取在Air下的对应参数,转化为7个角度值
if( strParams[7].equals("ptp"))//两种配置方法
MoveSafe( new MotionBatch(ptp(f).setJointJerkRel(JointJerk) ));
else if( strParams[7].equals("lin"))
MoveSafe( new MotionBatch(lin(f).setJointJerkRel(JointJerk).setCartVelocity(CartVelocity) ));
else
getLogger().info("Unacceptable motion! ptp/lin ?");
}
else{
getLogger().info("Unacceptable setPositionXYZABC command!");
}
}
public void MoveXYZABC(String message) // "MoveXYZABC x y 0 a 0 c" 这是一个动作
{
strParams = message.split(" ");
if (strParams.length==7){
double x = Float.parseFloat(strParams[1]);
double y = Float.parseFloat(strParams[2]);
double z = Float.parseFloat(strParams[3]);
double a = Math.toRadians( Float.parseFloat(strParams[4]) );
double b = Math.toRadians( Float.parseFloat(strParams[5]) );
double c = Math.toRadians( Float.parseFloat(strParams[6]) );
MotionBatch motion = new MotionBatch(linRel(x, y, z, a, b, c).setJointJerkRel(JointJerk).setCartVelocity(CartVelocity));//设置末端的位置和距离
MoveSafe(motion);//移动到该点
}
else{
getLogger().info("Unacceptable MoveXYZABC command!");
}
}
public void MoveCirc(String message) // "MoveCirc x1 y1 z1 a1 b1 c1 x2 y2 z2 a2 b2 c2 blending"
{
strParams = message.split(" ");
if (strParams.length==14){
double x1 = Float.parseFloat(strParams[1]);
double y1 = Float.parseFloat(strParams[2]);
double z1 = Float.parseFloat(strParams[3]);
double a1 = Math.toRadians( Float.parseFloat(strParams[4]) );
double b1 = Math.toRadians( Float.parseFloat(strParams[5]) );
double c1 = Math.toRadians( Float.parseFloat(strParams[6]) );
double x2 = Float.parseFloat(strParams[7]);
double y2 = Float.parseFloat(strParams[8]);
double z2 = Float.parseFloat(strParams[9]);
double a2 = Math.toRadians( Float.parseFloat(strParams[10]) );
double b2 = Math.toRadians( Float.parseFloat(strParams[11]) );
double c2 = Math.toRadians( Float.parseFloat(strParams[12]) );
double BlendingOri = Math.toRadians( Float.parseFloat(strParams[13]) );
Frame f1 = new Frame(getApplicationData().getFrame("/Air"), x1, y1, z1, a1, b1, c1 );
Frame f2 = new Frame(getApplicationData().getFrame("/Air"), x2, y2, z2, a2, b2, c2 );
MoveSafe( new MotionBatch( circ(f1, f2).setBlendingOri(BlendingOri).setOrientationReferenceSystem(OrientationReferenceSystem.Path).setCartVelocity(CartVelocity) ));
}
else{
getLogger().info("Unacceptable MoveCirc command!");
}
}
public void setForceStop(){//设置力停止
try{
if(!(this._currentMotion.isFinished() ||
this._currentMotion.hasError()))//判断是否停止或者存在问题
this._currentMotion.cancel();//如果没有停止并且没有报错,则退出
}
catch(Exception e){
// nop
};
CartesianImpedanceControlMode ForceStop = new CartesianImpedanceControlMode();//笛卡尔阻抗控制模式
ForceStop.parametrize(CartDOF.ALL).setDamping(.7);//设置所有阻尼为0.7
ForceStop.parametrize(CartDOF.ROT).setStiffness(300);//设置所有旋转刚度为300
ForceStop.parametrize(CartDOF.TRANSL).setStiffness(5000);//设置转动关节刚度为5000
handleCompliance = lbr.moveAsync(positionHold(ForceStop, 0, TimeUnit.SECONDS));//异步移动
handleCompliance.cancel();
isCompliance = false;//设置不为顺从模式
behaviourAfterCollision();//当锁死后触发
getLogger().info("ForceStop!");
}
public void setCompliance(String message){ //(为顺从模式) "setCompliance 10 10 5000 300 300 300"
// setCompliance "X-Stiffness" "Y-Stiffness" "Z-Stiffness" "A-R-Stiffness" "b-R-Stiffness" "c-R-Stiffness"
// x,y = 10 not to soft (robot stands by its own)
// x = 5000 max Stiffness.
// az, by, cx = 300 max rotational Stiffness.
CartesianImpedanceControlMode soft = new CartesianImpedanceControlMode();
strParams = message.split(" ");
if (strParams.length==7){
float x = Float.parseFloat(strParams[1]);
float y = Float.parseFloat(strParams[2]);
float z = Float.parseFloat(strParams[3]);
float az = Float.parseFloat(strParams[4]);
float by = Float.parseFloat(strParams[5]);
float cx = Float.parseFloat(strParams[6]);
soft.parametrize(CartDOF.ALL).setDamping(0.7);
soft.parametrize(CartDOF.X).setStiffness(x);
soft.parametrize(CartDOF.Y).setStiffness(y);
soft.parametrize(CartDOF.Z).setStiffness(z);
soft.parametrize(CartDOF.A).setStiffness(az);
soft.parametrize(CartDOF.B).setStiffness(by);
soft.parametrize(CartDOF.C).setStiffness(cx);
if (isCompliance)
handleCompliance.cancel();
handleCompliance = tool.moveAsync(positionHold(soft, -1, TimeUnit.SECONDS));
isCompliance = true;
getLogger().info("Compliance is ON");
}
else{
getLogger().info("Unacceptable setCompliance command!");
}
}
public void setCartImpCtrl(String message){ // "setCartImpCtrl 5000 5000 500 300 300 300 Damping"
strParams = message.split(" ");
if (strParams.length==8){
float x = Float.parseFloat(strParams[1]);
float y = Float.parseFloat(strParams[2]);
float z = Float.parseFloat(strParams[3]);
float az = Float.parseFloat(strParams[4]);
float by = Float.parseFloat(strParams[5]);
float cx = Float.parseFloat(strParams[6]);
float Damping = Float.parseFloat(strParams[7]);
cartImpCtrlMode.parametrize(CartDOF.X).setStiffness(x);
cartImpCtrlMode.parametrize(CartDOF.Y).setStiffness(y);
cartImpCtrlMode.parametrize(CartDOF.Z).setStiffness(z);
cartImpCtrlMode.parametrize(CartDOF.A).setStiffness(az);
cartImpCtrlMode.parametrize(CartDOF.B).setStiffness(by);
cartImpCtrlMode.parametrize(CartDOF.C).setStiffness(cx);
if (0.0 < Damping && Damping <= 1.0)
cartImpCtrlMode.parametrize(CartDOF.ALL).setDamping(Damping);
else{
cartImpCtrlMode.parametrize(CartDOF.ALL).setDamping(1.0);
getLogger().info("CartImpCtrl: Damping must be 0<JA<=1. Damping set to 1.0");
}
isCartImpCtrlMode = true;
getLogger().info("New CartImpCtrl mode is set.");
}
else{
getLogger().info("Unacceptable CartImpCtrl command!");
}
}
public void resetCartImpCtrl(){//重置对应的状态
cartImpCtrlMode.parametrize(CartDOF.X).setStiffness(5000);
cartImpCtrlMode.parametrize(CartDOF.Y).setStiffness(5000);
cartImpCtrlMode.parametrize(CartDOF.Z).setStiffness(5000);
cartImpCtrlMode.parametrize(CartDOF.ROT).setStiffness(300);
cartImpCtrlMode.parametrize(CartDOF.ALL).setDamping(1.0);
isCartImpCtrlMode = false;
getLogger().info("CartImpCtrl is OFF!");
}
public void resetCompliance(){
CartesianImpedanceControlMode resetComp = new CartesianImpedanceControlMode();
resetComp.parametrize(CartDOF.ALL).setDamping(.7);
resetComp.parametrize(CartDOF.ROT).setStiffness(300);
resetComp.parametrize(CartDOF.TRANSL).setStiffness(5000);
if (isCompliance){
handleCompliance.cancel();
handleCompliance = tool.moveAsync(positionHold(resetComp, 0, TimeUnit.SECONDS));
isCompliance = false;
}
getLogger().info("Compliance is OFF");
}
public void getJointPosition(PrintWriter outputStream)//获取关节角度
{
LastReceivedTime = System.currentTimeMillis();//获取当前的系统时间
/*对应的7个角度参数值*/
double a0 = Math.toDegrees( lbr.getCurrentJointPosition().get(0) );
double a1 = Math.toDegrees( lbr.getCurrentJointPosition().get(1) );
double a2 = Math.toDegrees( lbr.getCurrentJointPosition().get(2) );
double a3 = Math.toDegrees( lbr.getCurrentJointPosition().get(3) );
double a4 = Math.toDegrees( lbr.getCurrentJointPosition().get(4) );
double a5 = Math.toDegrees( lbr.getCurrentJointPosition().get(5) );
double a6 = Math.toDegrees( lbr.getCurrentJointPosition().get(6) );
/*加入间隔等待发送 */
String buffer = Double.toString(a0) + ", " + Double.toString(a1) + ", "
+ Double.toString(a2) + ", " + Double.toString(a3) + ", "
+ Double.toString(a4) + ", " + Double.toString(a5) + ", "
+ Double.toString(a6);
reply(outputStream, ">"+"Joint_Pos " + buffer);//按照对应格式发送指令
}
public void getToolPosition(PrintWriter outputStream)//获取当前的工具末端参数
{
//三轴所在tcp位置
double x = lbr.getCurrentCartesianPosition(tool.getDefaultMotionFrame()).getX();
double y = lbr.getCurrentCartesianPosition(tool.getDefaultMotionFrame()).getY();
double z = lbr.getCurrentCartesianPosition(tool.getDefaultMotionFrame()).getZ();
//角度
double a = Math.toDegrees( lbr.getCurrentCartesianPosition(tool.getDefaultMotionFrame()).getAlphaRad() );
double b = Math.toDegrees( lbr.getCurrentCartesianPosition(tool.getDefaultMotionFrame()).getBetaRad() );
double g = Math.toDegrees( lbr.getCurrentCartesianPosition(tool.getDefaultMotionFrame()).getGammaRad() );
String buffer = Double.toString(x) + ", " + Double.toString(y) + ", " + Double.toString(z) + ", " + Double.toString(a) + ", " + Double.toString(b) + ", " + Double.toString(g);
LastReceivedTime = System.currentTimeMillis();
reply(outputStream, ">"+"Tool_Pos " + buffer);
}
public void getIsCompliance(PrintWriter outputStream)//根据boll判断是否为顺从模式
{
LastReceivedTime = System.currentTimeMillis();
if (isCompliance)
reply(outputStream, ">"+"isCompliance " + "true");
else
reply(outputStream, ">"+"isCompliance " + "false");
}
public void getToolForce(PrintWriter outputStream)////获取工具对应的所收的到力
{
double x = lbr.getExternalForceTorque(tool.getDefaultMotionFrame()).getForce().getX();
double y = lbr.getExternalForceTorque(tool.getDefaultMotionFrame()).getForce().getY();
double z = lbr.getExternalForceTorque(tool.getDefaultMotionFrame()).getForce().getZ();
String buffer = Double.toString(x) + ", " + Double.toString(y) + ", " + Double.toString(z);
LastReceivedTime = System.currentTimeMillis();
reply(outputStream, ">"+"Tool_Force " + buffer);
}
public void getToolTorque(PrintWriter outputStream)//对应的工具扭矩
{
double x = lbr.getExternalForceTorque(tool.getDefaultMotionFrame()).getTorque().getX();
double y = lbr.getExternalForceTorque(tool.getDefaultMotionFrame()).getTorque().getY();
double z = lbr.getExternalForceTorque(tool.getDefaultMotionFrame()).getTorque().getZ();
String buffer = Double.toString(x) + ", " + Double.toString(y) + ", " + Double.toString(z);
LastReceivedTime = System.currentTimeMillis();
reply(outputStream, ">"+"Tool_Torque " + buffer);
}
public void getJointAcceleration(PrintWriter outputStream)//关节加速度
{
LastReceivedTime = System.currentTimeMillis();
reply(outputStream, ">"+"JointAcceleration " + Double.toString(JointAcceleration));
}
public void getJointVelocity(PrintWriter outputStream)//关节速度
{
LastReceivedTime = System.currentTimeMillis();
reply(outputStream, ">"+"JointVelocity " + Double.toString(JointVelocity));
}
public void getJointJerk(PrintWriter outputStream)//关节加加速度
{
LastReceivedTime = System.currentTimeMillis();
reply(outputStream, ">"+"JointJerk " + Double.toString(JointJerk));
}
public void getIsCollision(PrintWriter outputStream)//是否碰撞
{
LastReceivedTime = System.currentTimeMillis();
if (isCollision)
reply(outputStream, ">"+"isCollision " + "true");
else
reply(outputStream, ">"+"isCollision " + "false");
}
public void getIsReadyToMove(PrintWriter outputStream)//是否传输完毕,进行移动
{
LastReceivedTime = System.currentTimeMillis();
if (lbr.isReadyToMove())
reply(outputStream, ">"+"isReadyToMove " + "true");
else
reply(outputStream, ">"+"isReadyToMove " + "false");
}
public void getIsMastered(PrintWriter outputStream)//发送是否为主节点信息
{
LastReceivedTime = System.currentTimeMillis();
if (lbr.isMastered())
reply(outputStream, ">"+"isMastered " + "true");
else
reply(outputStream, ">"+"isMastered " + "false");
}
private void JointOutOfRange() { //关节超出范围
CartesianImpedanceControlMode OutOfRange = new CartesianImpedanceControlMode();//笛卡尔阻抗控制模式
OutOfRange.parametrize(CartDOF.ALL).setDamping(.7);
OutOfRange.parametrize(CartDOF.ROT).setStiffness(300);
OutOfRange.parametrize(CartDOF.TRANSL).setStiffness(5000);
IMotionContainer handle;
handle = tool.moveAsync(positionHold(OutOfRange, -1, TimeUnit.SECONDS));
getApplicationUI().displayModalDialog(ApplicationDialogType.WARNING,
"Joint Out Of Range!\n\n",
"Continue");//在UI中显示问题
handle.cancel();
}
private void getOperationMode(PrintWriter outputStream) {//操作模式
String opMode = lbr.getOperationMode().toString();
reply(outputStream, ">"+"OperationMode " + opMode);
}
public void sleep(String message){ // sleep in seconds.
strParams = message.split(" ");
float delay;
if (strParams.length==2)
{
delay = Float.parseFloat(strParams[1]);
if(delay >= 0)
ThreadUtil.milliSleep((long) (delay*1000));
else
getLogger().info("Delay cannot be a negative value!");
}
else
getLogger().info("Unacceptable sleep command!");
}
public void getIsFinished(PrintWriter outputStream)//获取运动是否结束
{
LastReceivedTime = System.currentTimeMillis();
try{
if(this._currentMotion.isFinished())//判断是否已经运行结束
reply(outputStream, ">"+"isFinished " + "true");
else
reply(outputStream, ">"+"isFinished " + "false");
}
catch(Exception e){
reply(outputStream, ">"+"isFinished " + "true");
};
}
public void getHasError(PrintWriter outputStream)//是否存在错误
{
LastReceivedTime = System.currentTimeMillis();
try{
if(this._currentMotion.hasError())//判断当前电机状态是否出现问题
reply(outputStream, ">"+"hasError " + "true");
else
reply(outputStream, ">"+"hasError " + "false");
}
catch(Exception e){
reply(outputStream, ">"+"hasError " + "true");
};
}
//===========================================================
public Thread Send_iiwa_data = new Thread(){//发送iiwa的数据
public void run(){
while (RUN)
{
getJointPosition(outputStream);//向ros发送当前的关节角
getToolPosition(outputStream);//向ros发送末端工具的位置
getToolForce(outputStream);//向ros发送工具对应的收到的力
getToolTorque(outputStream);//向ros发送工具扭矩
getIsCompliance(outputStream);//向ros发送合规性
getJointAcceleration(outputStream);//向ros发送关节加速度
getJointVelocity(outputStream);//向ros发送关节速度
getJointJerk(outputStream);//向ros发送关节加加速度
getIsCollision(outputStream);//向ros发送是否碰撞
getIsReadyToMove(outputStream);//向ros发送是否传输完毕,进行移动
getIsMastered(outputStream);//向ros发送发送是否为主节点信息
getOperationMode(outputStream);//向ros发送操作模式
getIsFinished(outputStream);//向ros发送运动是否结束
getHasError(outputStream);//向ros发送是否存在错误
ThreadUtil.milliSleep(100);//10hz频率
}
}
};
public Thread MonitorWorkspace = new Thread(){
JointPosition pos_last;
JointPosition pos_tmp;
double x;
double y;
double z;
public void run(){
while (RUN)
{
//============================================
pos_tmp = lbr.getCurrentJointPosition();//获取7个角度,并对其限制
if ((isCompliance) &&
(Math.toDegrees(pos_tmp.get(0)) < -165 || Math.toDegrees(pos_tmp.get(0)) > 165 ||
Math.toDegrees(pos_tmp.get(1)) < -115 || Math.toDegrees(pos_tmp.get(1)) > 115 ||
Math.toDegrees(pos_tmp.get(2)) < -165 || Math.toDegrees(pos_tmp.get(2)) > 165 ||
Math.toDegrees(pos_tmp.get(3)) < -115 || Math.toDegrees(pos_tmp.get(3)) > 115 ||
Math.toDegrees(pos_tmp.get(4)) < -165 || Math.toDegrees(pos_tmp.get(4)) > 165 ||
Math.toDegrees(pos_tmp.get(5)) < -115 || Math.toDegrees(pos_tmp.get(5)) > 115 ||
Math.toDegrees(pos_tmp.get(6)) < -170 || Math.toDegrees(pos_tmp.get(6)) > 170 ))//是否符合顺从模式,但是数值不在此期间
{
setForceStop();//强制停止
MoveSafe(new MotionBatch(ptp(pos_last).setJointJerkRel(JointJerk)));//恢复上一个状态,限定一定的加加速度进行平滑移动
JointOutOfRange();////关节超出范围后发送信息
}
else
pos_last = pos_tmp;//将上一个命令保存
//============================================获取现在的X,Y,Z参数
x = lbr.getCurrentCartesianPosition(tool.getDefaultMotionFrame()).getX();
y = lbr.getCurrentCartesianPosition(tool.getDefaultMotionFrame()).getY();
z = lbr.getCurrentCartesianPosition(tool.getDefaultMotionFrame()).getZ();
/*
if isInGreen(x,y,z): //Green zone
{
JointVelocity = 1;
JointAcceleration = 1;
}
else if isInYello(x,y,z): //Yello zone
{
JointVelocity = 1;
JointAcceleration = 1;
}
else if isInRead(x,y,z) //Red zone
{
JointVelocity = 1;
JointAcceleration = 1;
}
*/
//============================================
ThreadUtil.milliSleep(10);
}
}
};
//===========================================================
public void run() {
socketConnection();//使用socket链接
Send_iiwa_data.start();//创建一个新的thread实现
MonitorWorkspace.start();//监控工作区
while( RUN )//其余的一直在循环获得数据
{
CommandStr = getLine(inputStream);
String []lineSplt = CommandStr.split(" ");//分割对应指令
if( (lineSplt[0].toString()).equals("setPosition".toString()))
setPosition(CommandStr);//根据关节位置移动机器人手臂。可以选择点对点(ptp)或线性(lin)运动
if( (lineSplt[0].toString()).equals("setPositionXYZABC".toString()))
setPositionXYZABC(CommandStr);//在机器人笛卡尔空间中移动机器人末端执行器。可以选择点对点(ptp)或线性(lin)运动。这会将机器人末端执行器移动到特定位置[x,y,z]方向[a,b,c](浮点中的值)。如果不需要更改任何参数,可以使用-代替值
if( (lineSplt[0].toString()).equals("MoveXYZABC".toString()))
MoveXYZABC(CommandStr);//仅通过点对点(ptp)运动在机器人笛卡尔空间中移动机器人末端执行器。对于给定值(以毫米和度为单位),这会将机器人末端执行器沿特定方向[x,y,z]和/或方向[a,b,c]移动。
if( (lineSplt[0].toString()).equals("setCompliance".toString()))
setCompliance(CommandStr);//在每个x,y,z,a,b和c中具有特定刚度的情况下激活机器人的Compliance模式。给定的示例仅在x和y直角坐标系中以非常低的刚度激活Compliance(即为顺从模式)。
if( (lineSplt[0].toString()).equals("resetCartImpCtrl".toString()))
resetCartImpCtrl();//重置对应的
if( (lineSplt[0].toString()).equals("resetCompliance".toString()))
resetCompliance();//停用机器人的“Compliance”模式(即为顺从模式)
if( (lineSplt[0].toString()).equals("setCartImpCtrl".toString()))
setCartImpCtrl(CommandStr);
if( (lineSplt[0].toString()).equals("setTool".toString()))
setTool(CommandStr);//设置工具名称
if( (lineSplt[0].toString()).equals("setJointAcceleration".toString()))
setJointAcceleration(CommandStr);//设置对应的加速度
if( (lineSplt[0].toString()).equals("setJointVelocity".toString()))
setJointVelocity(CommandStr);//设置对应的速度
if( (lineSplt[0].toString()).equals("setJointJerk".toString()))
setJointJerk(CommandStr);//上述空间的切空间(加加速度,jerk)进行随机采样
if( (lineSplt[0].toString()).equals("setCartVelocity".toString()))
CartVelocity(CommandStr);//对应的速度设置
if( (lineSplt[0].toString()).equals("resetCollision".toString()))
isCollision = false;//如果检测到任何碰撞,则重置碰撞
if( (lineSplt[0].toString()).equals("forceStop".toString()))
setForceStop();//停止机器人并删除所有等待执行的机器人运动队列
if( (lineSplt[0].toString()).equals("MoveCirc".toString()))
MoveCirc(CommandStr);//以给定的混合值将机器人末端执行器 从第一个位置( [x1 y1 z1 a1 b1 c1])的当前位置以弧形/圆周运动从 其当前位置移动到第二个位置([x2 y2 z2 a2 b2 c2])
if( (lineSplt[0].toString()).equals("sleep".toString()))
sleep(CommandStr);
if( skt.isInputShutdown() || !skt.isConnected() || skt.isOutputShutdown() || skt.isClosed())
{
try {
skt.close();
} catch (IOException e) {
System.out.println("ERROR closing the port!");
}
RUN = false;
}
}
System.out.println("- - - APPLICATION TERMINATED - - -");
}
//===========================================================
/**
* Auto-generated method stub. Do not modify the contents of this method.
*/
public static void main(String[] args){
API_ROS_KUKA_V30032017 app = new API_ROS_KUKA_V30032017();
app.runApplication();
}
}
2) 您需要创建一个名称为“ Air”的新框架(参见下图):
a) 在包资源管理器中选择项目。
b) 右键单击“应用程序”数据视图中的“World”,然后从上下文菜单中选择“Insert new frame”。创建新框架并将其作为父框架的子元素插入框架树中。
c) 系统自动生成框架名称。在“属性”视图中将名称更改为“ Air”。
d) 确保转换(x,y,z,a,b,c)的所有值均为0。
3) 创建一个默认工具(参见下图):
a) 在包资源管理器中选择项目。
b) 在模板数据视图中,打开对象模板列表。
c) 右键单击“工具”的“模板组”,然后选择“名称为“ tool1”的新工具”。
d) 在“属性”视图中,输入框架相对于其父框架的变换数据(X,Y,Z:框架沿父框架轴的偏移量)(A,B,C:框架相对于参考的方向到父框架)
4) KUKA守护程序默认以IP地址172.31.1.50(在有线连接处设置固定IP,从而固定访问IP地址)和Port:1234连接到ROS-KUKA节点服务器。如果需要,请在“ API_ROS_KUKA_V30032017.java”行中更改此地址:skt = new Socket(“ 172.31.1.50”,1234);并在conf.txt文件中修改“server 172.31.1.50 port 1234”
5) 所有运动命令均通过称为“ MoveSafe”的功能执行。此功能对所有运动施加外力控制。如果检测到外力,则运动会终止。可以通过更改“ defineSensitivity()”函数中的“ sensCLS”值来修改MoveSafe的灵敏度。您可能需要根据任务更改默认值。
6) 将项目与机器人控制器同步。
相关运行示例程序
在终端运行
roscore
rosrun kuka_controller server_V30032017.py
server_V30032017.py
#!/usr/bin/env python
# KUKA API for ROS
version = 'V15032017++'
# 该脚本生成用于与KUKA iiwa通信的ROS节点
# 依赖项:conf.txt,ROS服务器,Rospy,KUKA iiwa java SDK,OPEN机械手。
#######################################################################################################################
import thread, time, os
import rospy
from std_msgs.msg import String
def cl_black(msge): return '\033[30m'+msge+'\033[0m'
def cl_red(msge): return '\033[31m'+msge+'\033[0m'
def cl_green(msge): return '\033[32m'+msge+'\033[0m'
def cl_orange(msge): return '\033[33m'+msge+'\033[0m'
def cl_blue(msge): return '\033[34m'+msge+'\033[0m'
def cl_purple(msge): return '\033[35m'+msge+'\033[0m'
def cl_cyan(msge): return '\033[36m'+msge+'\033[0m'
def cl_lightgrey(msge): return '\033[37m'+msge+'\033[0m'
def cl_darkgrey(msge): return '\033[90m'+msge+'\033[0m'
def cl_lightred(msge): return '\033[91m'+msge+'\033[0m'
def cl_lightgreen(msge): return '\033[92m'+msge+'\033[0m'
def cl_yellow(msge): return '\033[93m'+msge+'\033[0m'
def cl_lightblue(msge): return '\033[94m'+msge+'\033[0m'
def cl_pink(msge): return '\033[95m'+msge+'\033[0m'
def cl_lightcyan(msge): return '\033[96m'+msge+'\033[0m'
#######################################################################################################################
# 类别:TCP通信类型 #####################
class iiwa_socket:
# M: __init__ ===========================
def __init__(self, ip, port):
self.BUFFER_SIZE = 1024
self.isconnected = False
self.JointPosition = ([None,None,None,None,None,None,None],None)
self.ToolPosition = ([None,None,None,None,None,None],None)
self.ToolForce = ([None,None,None],None)
self.ToolTorque = ([None,None,None],None)
self.isCompliance = (False, None)
self.isCollision = (False, None)
self.isReadyToMove = (False, None)
self.isMastered = (False, None)
self.OperationMode = (None, None)
self.OprationMode = (None, None)
self.JointAcceleration = (None,None)
self.JointVelocity = (None,None)
self.JointJerk = (None,None)
self.isFinished = (False, None)
self.hasError = (False, None)
self.isready = False
try:
# 启动连接线程
thread.start_new_thread( self.socket, (ip, port, ) )
except:
print cl_red('Error: ') + "Unable to start connection thread"
# ~M: __init__ ==========================
# M: Stop connection ====================
def close(self):
self.isconnected = False
# ~M: Stop connection ===================
# M: Connection socket ==================
def socket(self, ip, port):
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 将socket绑定到端口
server_address = (ip, port)
os.system('clear')
print cl_pink('\n==========================================')
print cl_pink('< < < << SHEFFIELD ROBOTICS >> > > >')
print cl_pink('==========================================')
print cl_pink(' KUKA API for ROS')
print cl_pink(' Server Version: ' + version)
print cl_pink('==========================================\n')#设置对应的颜色打印
print cl_cyan('Starting up on:'), 'IP:', ip, 'Port:', port
try:
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(server_address)
except:
print cl_red('Error: ') + "Connection for KUKA cannot assign requested address:", ip, port
os._exit(-1)
# 监听传入的连接
sock.listen(1)
# 等待连接
print cl_cyan('Waiting for a connection...')
self.connection, client_address = sock.accept()
self.connection.settimeout(0.01)
print cl_cyan('Connection from'), client_address
self.isconnected = True
last_read_time = time.time()
while self.isconnected:
try:
data = self.connection.recv(self.BUFFER_SIZE)
last_read_time = time.time() # 保持接收时间
# 处理收到的数据包
for pack in data.split(">"): # 解析数据包
cmd_splt = pack.split()
if len(pack) and cmd_splt[0]=='Joint_Pos': # 如果是JointPosition
tmp = [float(''.join([c for c in s if c in '0123456789.eE-'])) for s in cmd_splt[1:]]
if len(tmp)==7: self.JointPosition = (tmp, last_read_time)
if len(pack) and cmd_splt[0]=='Tool_Pos': # 如果是ToolPosition
tmp = [float(''.join([c for c in s if c in '0123456789.eE-'])) for s in cmd_splt[1:]]
if len(tmp)==6: self.ToolPosition = (tmp, last_read_time)
if len(pack) and cmd_splt[0]=='Tool_Force': # 如果是ToolForce
tmp = [float(''.join([c for c in s if c in '0123456789.eE-'])) for s in cmd_splt[1:]]
if len(tmp)==3: self.ToolForce = (tmp, last_read_time)
if len(pack) and cmd_splt[0]=='Tool_Torque': # 如果是ToolTorque
tmp = [float(''.join([c for c in s if c in '0123456789.eE-'])) for s in cmd_splt[1:]]
if len(tmp)==3: self.ToolTorque = (tmp, last_read_time)
if len(pack) and cmd_splt[0]=='isCompliance': # 如果是Compliance
if cmd_splt[1] == "false": self.isCompliance = (False, last_read_time)
elif cmd_splt[1] == "true": self.isCompliance = (True, last_read_time)
if len(pack) and cmd_splt[0]=='isCollision': # 如果是Collision
if cmd_splt[1] == "false": self.isCollision = (False, last_read_time)
elif cmd_splt[1] == "true": self.isCollision = (True, last_read_time)
if len(pack) and cmd_splt[0]=='isReadyToMove': # 如果是ReadyToMove
if cmd_splt[1] == "false": self.isReadyToMove = (False, last_read_time)
elif cmd_splt[1] == "true": self.isReadyToMove = (True, last_read_time)
if len(pack) and cmd_splt[0]=='isMastered': # 如果是Mastered
if cmd_splt[1] == "false": self.isMastered = (False, last_read_time)
elif cmd_splt[1] == "true": self.isMastered = (True, last_read_time)
if len(pack) and cmd_splt[0] == 'OperationMode': # 如果是OperationMode
self.OperationMode = (cmd_splt[1], last_read_time)
if len(pack) and cmd_splt[0]=='JointAcceleration': # 如果是JointAcceleration
self.JointAcceleration = (float(cmd_splt[1]), last_read_time)
if len(pack) and cmd_splt[0]=='JointVelocity': # 如果是JointVelocity
self.JointVelocity = (float(cmd_splt[1]), last_read_time)
if len(pack) and cmd_splt[0]=='JointJerk': # 如果是JointJerk
self.JointJerk = (float(cmd_splt[1]), last_read_time)
if len(pack) and cmd_splt[0]=='isFinished': # 如果是Finished
if cmd_splt[1] == "false": self.isFinished = (False, last_read_time)
elif cmd_splt[1] == "true": self.isFinished = (True, last_read_time)
if len(pack) and cmd_splt[0]=='hasError': # 如果存在Error
if cmd_splt[1] == "false": self.hasError = (False, last_read_time)
elif cmd_splt[1] == "true": self.hasError = (True, last_read_time)
if ( all(item != None for item in self.JointPosition[0]) and
all(item != None for item in self.ToolPosition[0]) and
all(item != None for item in self.ToolForce[0]) and
all(item != None for item in self.ToolTorque[0]) and
self.isCompliance[1] != None and
self.isCollision[1] != None and
self.isReadyToMove[1] != None and
self.isMastered[1] != None and
self.OperationMode[1] != None ):
#self.OprationMode = (None, None)
self.isready = True
else:
self.isready = False
except:
elapsed_time = time.time() - last_read_time
if elapsed_time > 5.0: # 5秒内未收到包裹
self.close() #与iiwa断开
self.isconnected = False
print cl_lightred('No packet received from iiwa for 5s!')
self.connection.shutdown(socket.SHUT_RDWR)
self.connection.close()
sock.close()
self.isconnected = False
print cl_lightred('Connection is closed!')
def send(self, cmd):
thread.start_new_thread( self.__send, (cmd, ) )
def __send(self, cmd):
self.connection.sendall(cmd+'\r\n')
#######################################################################################################################
# 类:ROS类型节点 #####################
class kuka_iiwa_ros_node:
# M: __init__ ===========================
def __init__(self, ip, port): # Makes kuka_iiwa ROS node
self.iiwa_soc = iiwa_socket(ip, port)
# 等到iiwa连接到
while (not self.iiwa_soc.isready): pass
# 侦听kuka_iiwa命令
rospy.Subscriber("kuka_command", String, self.callback)
# 使发布者获得所有kuka_iiwa数据
pub_JointPosition = rospy.Publisher('JointPosition', String, queue_size=10)
pub_ToolPosition = rospy.Publisher('ToolPosition', String, queue_size=10)
pub_ToolForce = rospy.Publisher('ToolForce', String, queue_size=10)
pub_ToolTorque = rospy.Publisher('ToolTorque', String, queue_size=10)
pub_isCompliance = rospy.Publisher('isCompliance', String, queue_size=10)
pub_isCollision = rospy.Publisher('isCollision', String, queue_size=10)
pub_isReadyToMove = rospy.Publisher('isReadyToMove', String, queue_size=10)
pub_isMastered = rospy.Publisher('isMastered', String, queue_size=10)
pub_OperationMode = rospy.Publisher('OperationMode', String, queue_size=10)
pub_JointAcceleration = rospy.Publisher('JointAcceleration', String, queue_size=10)
pub_JointVelocity = rospy.Publisher('JointVelocity', String, queue_size=10)
pub_JointJerk = rospy.Publisher('JointJerk', String, queue_size=10)
pub_isFinished = rospy.Publisher('isFinished', String, queue_size=10)
pub_hasError = rospy.Publisher('hasError', String, queue_size=10)
# 制作node_iiwa节点
rospy.init_node('kuka_iiwa', anonymous=False)
rate = rospy.Rate(100) # 100hz更新速率。
while not rospy.is_shutdown() and self.iiwa_soc.isconnected:
#data_str = self.iiwa_soc.data + " %s" % rospy.get_time()
# 更新所有的kuka_iiwa数据
for [pub, data] in [ [pub_JointPosition, self.iiwa_soc.JointPosition],
[pub_ToolPosition, self.iiwa_soc.ToolPosition],
[pub_ToolForce, self.iiwa_soc.ToolForce],
[pub_ToolTorque, self.iiwa_soc.ToolTorque],
[pub_isCompliance, self.iiwa_soc.isCompliance],
[pub_isCollision, self.iiwa_soc.isCollision],
[pub_isReadyToMove, self.iiwa_soc.isReadyToMove],
[pub_isMastered, self.iiwa_soc.isMastered],
[pub_OperationMode, self.iiwa_soc.OperationMode],
[pub_JointAcceleration, self.iiwa_soc.JointAcceleration],
[pub_JointVelocity, self.iiwa_soc.JointVelocity],
[pub_JointJerk, self.iiwa_soc.JointJerk],
[pub_isFinished, self.iiwa_soc.isFinished],
[pub_hasError, self.iiwa_soc.hasError]]:
data_str = str(data[0]) +' '+ str(rospy.get_time())
##########rospy.loginfo(data_str)
pub.publish(data_str)
rate.sleep()
# ~M: __init__ ==========================
# M: callback ===========================
# 接收命令字符串并将其发送到KUKA iiwa
def callback(self, data):
###########rospy.loginfo(rospy.get_caller_id() + "Received command " + str(data.data) )
self.iiwa_soc.send(data.data) # e.g 'setPosition 45 60 0 -25 0 95 0' for going to start position
def read_conf():
f_conf = os.path.abspath(os.path.dirname(__file__)) + '/conf.txt'
if os.path.isfile(f_conf):
IP = ''
Port = ''
for line in open(f_conf, 'r'):
l_splt = line.split()
if len(l_splt)==4 and l_splt[0] == 'server':
IP = l_splt[1]
Port = int(l_splt[3])
if len(IP.split('.'))!=4 or Port<=0:
print cl_red('Error:'), "conf.txt doesn't include correct IP/Port! e.g. server 172.31.1.50 port 1234"
exit()
else:
print cl_red('Error:'), "conf.txt doesn't exist!"
exit()
return [IP, Port]
# ~M: Reading config file for Server IP and Port ================
if __name__ == '__main__':
[IP, Port] = read_conf()
try:
node = kuka_iiwa_ros_node(IP, Port) # Make a Kuka_iiwa ROS node
except rospy.ROSInterruptException:
pass
在KUKA-iiwa的控制台中运行: “ROS”
现在,API已启动并正在运行。最后一步是运行ROS节点以与API通信并控制机器人。Python提供了一些基本示例。例如,要开始,您可以运行:
rosrun kuka_controller demo_ReadData.py
demo_ReadData.py
#!/usr/bin/env python
# KUKA API for ROS
version = 'V15032017'
from client_lib import *
import time, os
# Making a connection object.
my_client = kuka_iiwa_ros_client()
while (not my_client.isready):
pass
# Initializing Tool 1
my_client.send_command('setTool tool1')
for i in range(1000):
os.system('clear')
print 'OperationMode\t=', my_client.OperationMode
print 'isCollision\t=', my_client.isCollision
print 'isCompliance\t=', my_client.isCompliance
print 'isMastered\t=', my_client.isMastered
print 'isready\t=', my_client.isready
print 'isReadyToMove\t=', my_client.isReadyToMove
print 'ToolPosition\t=', my_client.ToolPosition
print 'ToolForce\t=', my_client.ToolForce
print 'ToolTorque\t=', my_client.ToolTorque
print 'JointAcceleration\t=', my_client.JointAcceleration
print 'JointJerk\t=', my_client.JointJerk
print 'JointPosition\t=', my_client.JointPosition
print 'JointVelocity\t=', my_client.JointVelocity
time.sleep(1)
在此演示中,机器人不会移动。该演示程序接收机器人数据(如关节位置等)并打印出来。