10 URCap示例概述
本节简要介绍了URCaps SDK中包含的每个URCap示例。
10.1 常规样品
Hello World Swing是本教程的主要示例,介绍了URCap的所有核心概念。这包括对PolyScope的程序节点和安装节点的贡献,这些节点无缝地挂接到:
. UI
程序和安装文件的持久性
程序的创建和执行
程序撤销/重做功能
信息:
。可从以下网址获取:
– URCap API version 1.3.0.
– PolyScope 3.6.0/5.0.4版
. Main API interfaces: SwingProgramNodeService, ProgramNodeContribution, Swing- ProgramNodeView, ContributionProvider, SwingInstallationNodeService, Installa- tionNodeContribution, SwingInstallationNodeView, UndoRedoManager, DataModel, ScriptWriter.
My Daemon Swing 是 Hello World Swing URCap 的扩展,展示了如何将 Python 2.5 或 C ++ 守护进程与 URCap 软件平台集成。当 URCap 依赖于未在 Java 中实现的驱动程序或服务器时,这很有用。此外,URCap 展示了如何使用 XML-RPC 协议与安装节点中的守护进程以及程序节点生成的脚本代码进行通信。
信息:
。可从以下网址获取:
– URCap API version 1.3.0.
– PolyScope 3.6.0/5.0.4版
.主要API接口:DaemonComment、DaemonService。
脚本函数Swing演示了如何在表达式编辑器中向可用脚本函数列表中添加函数。URCap最终用户经常使用的脚本函数应添加到此列表中。
信息:
。可从以下网址获取:
– URCap API version 1.3.0
– PolyScope 3.6.0/5.0.4版
.主要API接口:函数、函数模型
Pick或Place Swing是一个玩具示例,展示了如何通过TreeNodeneneneba API对程序树进行更改。程序节点服务(SwingProgramNodeService接口)以这样的方式配置,即它创建的程序节点贡献只能由URCap插入程序树,而不能由最终用户从PolyScope的UI插入。
信息:
。可从以下网址获取:
– URCap API version 1.3.0.
– PolyScope 3.6.0/5.0.4版
. Main API interfaces: ProgramModel, TreeNode, ProgramNodeFactory, SwingPro- gramNodeService, ContributionConiguration
Ellipse Swing 是一个玩具示例,其中使用姿势来定义椭圆状运动的中心点。该运动是通过插入一个预先配置的 MoveP 程序节点来实现的,该节点包含预先定义和命名的 Waypoint 节点。此示例演示了如何:
通过要求终端用户使用移动选项卡来为机器人位置获取一个姿势
. 命名航点
请求终端用户将机器人移动到给定的目标位置
允许终端用户使用内置 PolyScope 支持从程序树中的选定程序节点开始,并在该节点上暂停/中断。在这种情况下,终端用户可以从椭圆(URCap)程序节点下的特定航点子节点开始或中断。
注意:
分配航路点节点自定义名称的功能仅在URLCap API版本1.4.0(与PolyScope版本3.7.0/5.1.0一起发布)中可用
请求用户将机器人移动到去交错的中心点仅适用于URCap API 1.5.0版(与PolyScope 3.8.0/5.2.0版一起发布)。
从URCap API版本1.6.0(与PolyScope版本3.9.0/5.3.0一起发布)开始,已使用等效的生成器替换了不推荐使用的移动节点锥形工厂(MoveNodeConigFactory接口),并预先配置了对MoveP节点的TCP选择。
.仅从URCap API版本1.9.0(与PolyScope版本5.6.0一起发布)提供对允许最终用户从子节点开始和中断子节点的支持。
从URCap API 1.11.0版(与PolyScope 3.14.0/5.9.0一起发布)开始,已将不推荐使用的方法getUserDefinedRobotPosition(RobotPositionCallback)与等效的getUserDefine dRobotPost(RobotPosition Callback2)方法重新放在一起。此外,用于创建固定位置Waypoint节点配置(createFixedPositionConfig(…)没有TCP偏移)的已弃用的工厂方法已被替换为同样以TCP偏移为参数的等效方法。
信息:
。可从以下网址获取:
– URCap API version 1.3.0.
– PolyScope 3.6.0/5.0.4版本。
主要API接口:UserInteraction、RobotPositionCallback2、RobotMovement、,
机器人运动回调、路点节点配置、移动节点配置、移动N-
odeConigBuilders、MovePConigBuilder、PoseFactory、Pose、SimpleValueFactory、关节位置
循环计数器摆动演示了如何使用变量。 在此示例中,所选变量将在每次执行程序节点时递增。
此示例还演示了如何允许最终用户使用内置 PolyScope 支持从程序树中的选定程序节点开始和暂停/中断。在这种情况下,最终用户可以从 Cycle Counter (URCap) 程序节点下的任何子节点开始或中断。
备注:
.仅从URCap API版本1.9.0(与PolyScope版本5.6.0一起发布)提供对允许最终用户从子节点开始和中断子节点的支持
信息:
。可从以下网址获取:
– URCap API version 1.3.0.
PolyScope版本3.6.0/5.0.4。
.主要API接口:变量、变量工厂、表达式生成器
闲置时间摆动演示了如何使用 ProgramNodeVisitor 来遍历子树中的所有程序节点。 在此示例中,将访问所有 Wait 节点。 如果将 Wait 节点配置为等待一段时间,则所选变量中将累积该数量的闲置时间(以秒为单位)。
信息:
。可从以下网址获取:
– URCap API version 1.3.0.
– PolyScope 3.6.0/5.0.4版
.主要API接口:ProgramNodeVisitor、WaitNodeConig
本地化摇摆演示了如何在URCaps中实现本地化。PolyScope本地化设置通过SystemSettings API访问。
信息:
。可从以下网址获取:
– URCap API version 1.3.0.
– PolyScope 3.6.0/5.0.4版
.主要API接口:系统设置、本地化、单元、SimpleValueFactory
用户输入 演示了如何使用虚拟屏幕键盘/小键盘和用户输入验证。
信息:
。可从以下网址获取:
– URCap API version 1.3.0.
PolyScope版本3.6.0/5.0.4。
. Main API interfaces: KeyboardInput, InputValidationFactory
My Toolbar 演示了如何实现 PolyScope 工具栏贡献。
信息:
。可从以下网址获取:
– URCap API version 1.3.0.
– PolyScope 5.0.4版本。
. Main API interfaces: SwingToolbarService, SwingToolbarContribution.
节点排序摇摆演示了如何在PolyScope中为URCap的程序节点贡献定义特定的排序顺序。
信息:
。可从以下网址获取:
– URCap API version 1.5.0.
PolyScope版本3.8.0/5.2.0。
. Main API interfaces: ContributionConiguration, SwingProgramNodeService.
工具切换器摆动是一个玩具示例,展示了如何将TCPs添加到PolyScope中,以及如何访问PolyScope中可用的TCPs列表。
在安装节点贡献中,用户可以更改工具位置,启用/禁用不同的工具TCP,并在工具长度和所有启用的工具TCP之间设置平移偏移。
在程序节点贡献中,用户可以从PolyScope中所有可用TCP的列表中选择新工具的TCP。执行程序节点时,机器人将移动到用户定义的工具更改位置,更改工具(通过等待时间模拟),最后将活动TCP更改为所选TCP。
信息:
。可从以下网址获取:
– URCap API version 1.5.0.
– PolyScope 3.8.0/5.2.0版本。
.主要API接口:TCPContributionModel、TCPModel。
注意:
从URCap API 1.11.0版(与PolyScope 3.14.0/5.9.0一起发布)开始,已将不推荐使用的方法getUserDefinedRobotPosition(RobotPositionCallback)与等效的getUserDefine dRobotPost(RobotPosition Callback2)方法重新放在一起。
MoveUntilDetectionSwing演示了如何通过URCap API使用Distance和Until程序节点。
程序节点贡献创建了一个方向节点,该节点将机器人向下移动,直到传感器被触发(通过输入),或直到达到最大距离。如果传感器被触发,则通过设置高输出激活连接的物理设备(例如夹具)。如果在传感器触发之前达到最大距离,则将生成一个弹出窗口向用户显示错误。用户可以通过移动直到检测节点中的文本字段指定最大距离。
信息:
。可从以下网址获得:
– URCap API version 1.6.0.
PolyScope 3.9.0/5.3.0版本。
.主要API接口:DirectionNode、DirectionNodeConigBuilder、UntilNode、UntilNodeConigFactory。
工具I/O控制Swing演示了如何使用资源模型,并通过URCap API请求对工具I/O接口的独占控制。它还演示了如何检查底层机器人系统上是否有特定的功能(在本例中为工具通信接口(TCI)和工具输出模式功能)。
有关资源控制的更多详细信息,请参阅单独的资源控制文档。系统功能的概念及其可用性的检查在单独的功能文档中进行了描述。
信息:
。可从以下网址获取:
– URCap API version 1.7.0.
– PolyScope 3.10.0/5.4.0版本。
. Main API interfaces: ResourceModel, ControllableResourceModel, ToolIOInterface- Controller, ToolIOInterface, ToolIOInterfaceControllable, CapabilityManager.
抓取和释放摆动演示了如何在模板程序节点中使用抓取器设备。
在程序节点贡献中,用户可以在PolyScope中可用的已注册夹具中选择一个夹具。选择夹具后,可以将所选夹具应用于模板节点。这将插入两个Gripper程序节点,用于
选定的夹具:一个节点配置为夹紧动作,一个节点配置为释放动作。
本示例演示了如何:
获取PolyScope中可用的夹具列表
在程序树中插入一个特定夹具设备的夹具程序节点。为夹紧和释放动作配置一个夹具程序节点
注意:要在程序节点中选择抓手,可以安装一些抓手驱动器URCap示例(例如Simple Gripper)。
有关如何在模板节点中使用设备的更多详细信息,请参阅单独的 在模板中使用设备 文档。
信息:
。可从以下网址获取:
– URCap API version 1.9.0.
– PolyScope 3.12.0/5.6.0版本。
.主要API接口:GripperManager、GripperProgramNodeFactory、GripperNode、GripConigBuilder、ReleaseConigBuilder和GripperDevice。
创建功能切换是一个示例,展示了如何向PolyScope贡献功能,以及如何修改和删除功能。
在安装贡献中,用户可以定义一个功能,然后对其进行更新和删除。创建的功能存储在安装贡献的数据模型中。
在程序节点贡献中,如果尚未完成,用户将被要求从安装贡献中创建一个特征。创建特征后,用户可以按一个按钮来创建相对于所创建特征的移动。移动是通过插入一个包含预定义航点节点的预配置MoveL程序节点来实现的。当程序节点被执行时,机器人将以所创建的特征为中心执行一个方形移动。
信息:
。可从以下网址获取:
– URCap API version 1.9.0.
PolyScope版本3.12.0/5.6.0。
.主要API接口:FeatureContributionModel。
备注:
从URCap API 1.11.0版(与PolyScope 3.14.0/5.9.0一起发布)开始,已将不推荐使用的方法getUserDefinedRobotPosition(RobotPositionCallback)与等效的getUserDefine dRobotPost(RobotPosition Callback2)方法重新放在一起。此外,用于创建固定位置Waypoint节点配置(createFixedPositionConfig(…)没有TCP偏移)的已弃用的工厂方法已被替换为同样以TCP偏移为参数的等效方法。刀具长度用作TCP偏移量。
创建有效载荷摆动是一个示例,展示了如何向PolyScope贡献有效载荷以及如何修改和删除它。
在安装过程中,用户可以创建有效载荷,随后更新创建的有效载荷的质量和重心(CoG)参数,以及删除有效载荷。用户为质量和重心(CoG)参数输入的值使用API提供的参数限制进行验证。创建的有效负载存储在安装贡献的数据模型中。
在程序节点贡献中,如果尚未完成,则将要求用户从安装贡献中创建有效载荷。创建有效载荷后,用户可以按按钮创建一个包含预选有效载荷(在安装贡献中创建)的Set Payload节点。
信息:
。可从以下网址获取:
– URCap API version 1.13.0
PolyScope 5.11.0版本
.主要API接口:PayloadContributionModel、RobotLimits、SetPayloadNode
10.2 驱动程序示例
自定义用户输入 演示了如何在为驱动因素定义自定义UI时使用不同类型的用户输入(例如组合框和复选框输入)和其他(非用户输入)UI元素(例如文本组件)。
URCap还展示了如何使用更高级的UI元素来控制/分组布局,以及如何添加自定义输入验证器来检测可输入用户输入的错误,在本例中是IP地址用户输入(文本字段)。
信息:
。可从以下网址获取:
– URCap API version 1.7.0.
– PolyScope 3.11.0/5.5.0版本。
.主要API接口:CustomUserInputConfiguration。
Simple Gripper演示了如何为仅支持强制“默认”抓取和释放动作的基本抓取器创建抓取器驱动程序。URCap在脚本代码生成中使用数字输出来触发抓取和释放动作。
有关夹持器驱动器贡献的更多详细信息,请参阅单独的夹持器驱动器文档。
信息:
。可从以下网址获取:
– URCap API version 1.8.0.
– PolyScope 3.11.0/5.5.0版本。
.主要API接口:GripperContribution.
高级夹具演示了如何为更高级的夹具创建夹具驱动程序,该夹具支持一些可选的夹具功能并控制工具I/O接口资源的输出电压设置。URCap演示了如何:
. 构想抓取器功能,例如抓取和释放检测的宽度、速度、力、真空和反馈
请求对工具I/O接口资源的独占控制
. 配置工具输入/输出接口的输出电压输入/输出设置
补充信息:
有关夹持器驱动器贡献的详细信息,请参阅单独的夹持器驱动器文档。
有关系统资源控制的信息,请参阅单独的资源控制文档。
要查看工具I/O接口的其他设置如何配置的示例,请参阅工具I/O控制摆动URCap示例。
注意:
夹持器的反馈功能仅适用于URCap API版本1.9.0(与PolyScope版本3.12.0/5.6.0一起发布)
信息:
。可从以下网址获取:
– URCap API version 1.8.0.
– PolyScope 3.11.0/5.5.0版本。
主要API接口:GripperContribution、GripperCapabilities、SystemConigu-ration、GripActionParameters、ReleaseActionParameters和GripperFeedbackCapabili-ties。
自定义夹具设置演示了如何创建夹具驱动程序,该驱动程序在安装节点中定义了自定义UI,用于设置夹具,并为夹具添加一个TCP到PolyScope。
有关夹持器驱动器贡献的更多详细信息,请参阅单独的夹持器驱动器文档。
信息:
。可从以下网址获取:
– URCap API version 1.8.0.
– PolyScope 3.11.0/5.5.0版本。
.主要API接口:GripperContribution、TCPConfiguration、CustomUserInput-Configuration。
在这个例子中,夹具是一个带有两个独立物理夹具(区域)的真空双夹具,这些区域“内置”在夹持装置中。URCap使用户可以选择三个单独的区域(夹具),命名为Zone A,Zone B和Zone A+B。用户可以独立操作Zone A和Zone B,或者选择通过选择Zone A+B同时使用两个区域。
在安装节点中定义了一个自定义UI,允许用户启用“使用易碎物品处理”选项。启用时,这将限制可用于夹紧动作的最大真空度。这是通过同时减少所有区域已注册真空能力的最大值和默认值参数来实现的。
URCap展示了如何配置多夹具能力以支持多个永久启用的单独夹具,为每个单独的夹具(区域)添加专用TCP,动态更新所有单独夹具(区域)的已注册(参数基于)能力的参数值。在这种情况下,已注册的能力是夹具真空能力。有关夹具驱动程序贡献的更多详细信息,请参阅单独的夹具驱动程序文档。
信息:
* 可从以下版本获取:
+ URCap API版本1.11.0
+ PolyScope版本3.14.0/5.9.0
* 主要API接口:
1. GripperContribution
2. GripperCapabilities
3. GripperListProvider
4. GripperListBuilder
5. SelectableGripper
6. SystemConiguration
7. TCPConiguration
8. Grip-VacuumCapability
用户只能使用标准夹具Gripper 1。选择双夹具选项将启用两个夹具,用户可以使用这两个夹具。根据选择的选项,标准夹具(Gripper 1)的TCP偏移量将相应地更新。
对于每个单独的夹具(夹具1和夹具2),用户可以配置连接到夹具上的指尖类型(在安装节点中)。有两种选择,标准型和扩展型。标准型是默认选项,而扩展型选项可以在连接宽范围的指尖时选择。选择扩展型选项将增加特定单独夹具(独立于其他夹具)的注册宽度能力的最大值和默认值参数。
URCap显示了如何:
设想多抓取器功能,以支持多个单独抓取器,其中一些抓取器最初被禁用
动态启用和禁用单个夹具
为每个单独的夹具添加一个专用的TCP
动态更新单个抓取器(独立于其他抓取器)的注册(基于参数)功能的参数值。在这种情况下,注册功能是宽度功能。
有关夹持器驱动器贡献的更多详细信息,请参阅单独的夹持器驱动器文档。
信息:
。可从以下网址获取:
– URCap API version 1.11.0.
– PolyScope 3.14.0/5.9.0版本。
. Main API interfaces: GripperContribution, GripperCapabilities, GripperListProvider, GripperListBuilder, SelectableGripper, MultiGripperCapability, SystemConiguration, TCPConiguration, WidthCapability
Simple Screwdriver演示了如何为仅支持强制启动和停止螺丝刀操作的基本螺丝刀创建螺丝刀驱动程序。URCap在脚本代码生成中使用数字输出启动和停止螺丝刀。
有关螺丝刀驱动器贡献的更多详细信息,请参阅单独的螺丝刀驱动器文档。
信息:
。可从以下网址获取:
– URCap API version 1.9.0.
– PolyScope 5.6.0版。
高级螺丝刀演示了如何创建支持某些可选操作和操作反馈功能的螺丝刀驱动程序,例如程序选择、进给螺钉、驱动螺钉OK和螺丝驱动准备就绪。URCap主要使用
实现这些功能的I/O。
有关螺丝刀驱动器贡献的更多详细信息,请参阅单独的螺丝刀驱动器文档。
信息:
。可从以下网址获取:
– URCap API version 1.9.0.
PolyScope 5.6.0版本。
自定义螺丝刀演示了如何创建一个螺丝刀贡献驱动程序,该驱动程序在Screwdriving安装节点中定义了一个自定义UI,用于设置螺丝刀,并为螺丝刀添加一个默认TCP到PolyScope。
有关螺丝刀驱动器贡献的更多详细信息,请参阅单独的螺丝刀驱动器文档。
信息:
。可从以下网址获取:
– URCap API version 1.9.0.
PolyScope 5.6.0版本。
11 使用Maven Archetype创建新的瘦项目
URCap开发有多种入门方式。一种是从现有的URCap项目开始并对其进行修改。当你掌握了它时,你可能想从一个具有基本Maven结构的空骨架开始。因此,进入URCaps SDK的目录并键入
$ ./ newURCap .sh
这会弹出一个对话框,您可以在其中为新的URCap选择组和工件ID
例如,可以将com.yourcompany作为组ID,将newapp作为工件ID。请参考Java组ID命名约定的最佳实践。
接下来,您必须指定URCap与哪个Universal Robots机器人系列兼容
也许你的URCap需要特定的硬件和/或软件功能,这些功能仅在特定的机器人系列(例如,仅限e系列机器人)上可用,或者URCap可能与所有机器人系列兼容。这些考虑因素应该决定你的选择。有关机器人系列兼容性的更多详细信息,请参阅第12.1节“机器人系列兼容性”。
最后,您还必须指定目标URLCap API版本。选择API的早期版本将使您的URCap与早期PolyScope版本兼容,但也会限制通过API访问的功能。第12.2节描述了URCap API兼容性。API兼容性。
在最后一个对话框中按“确定”按钮会在子文件夹./com.yourcompany.thenewapp下创建一个新的Maven项目。该项目可以很容易地导入到Java IDE中,例如Eclipse、Netbeans或IntelliJ。
请注意,生成的 pom.xml 文件包含一个部分,其中包含新 URCap 的一组属性,以及供应商、联系地址、版权、描述和简短许可信息等元数据,这些元数据将在 URCap 安装在 PolyScope 中时显示给用户。该部分还包含布尔兼容性滞后属性,指定 URCap 与不同可用机器人系列的兼容性。使用与新 URCap 相关的数据更新 URCap 元数据部分。有关此部分外观示例,请参阅清单 1。
如果您需要在项目设置后更改URCap API的版本以依赖它,这可以在项目的pom.xml文件中完成。在这里,您必须在pom.xml文件的<dependencies>部分下的URCap API依赖项中更新到所需版本,并在存在版本信息的情况下修改maven-bundle-plugin下的<import-package>元素。参见清单12、13和16中的示例
Listing 12: Modify URCap API runtime dependency in pom.xml
1 ...
2 <Import - Package >
3 com .ur. urcap . api *,
4 *
5 </ Import - Package >
6 ...
Listing 13: Specifying URCap API compile time dependency in pom.xml
1 ...
2 <dependencies >
3 ...
4 <dependency >
5 <groupId > com .ur.urcap </ groupId >
6 <artifactId >api </ artifactId >
7 <version >1.0.0.30 </ version >
8 <scope > provided </ scope >
9 </ dependency >
10 ...
11 </ dependencies >
12 ...
12 兼容性
12.1 机器人系列兼容性
开发URCaps时,您必须强制指定URCaps与哪个机器人系列兼容,即URCaps可以在哪个机器人系列上运行。其目的是通过确保最终用户无法安装与他们的机器人和/或Universal Robots在线仿真软件(URSim)不兼容的URCaps,为URCaps安装过程提供良好的用户体验。
在指定URCap的兼容性时,您需要考虑,您的URCap是否依赖于特定的硬件和/或软件功能,这些功能并非所有机器人系列都可用(例如,仅适用于e系列机器人),或者URCap是否可以在所有可用的机器人系列上运行。请注意,必须为Universal Robots(包括URCap不兼容的机器人系列)系列中可用的所有机器人系列指定URCap的兼容性。
12.1.1 兼容性标志
URCap的兼容性使用布尔兼容性滞后指定,布尔兼容性滞后在URCap项目的pom.xml Maven配置文件中定义为属性。两个兼容性滞后属性urcap .compatibility .CB3和urcap .compatibility .eSeries必须存在于pom.xml文件中的URCap元数据部分。清单14显示了包含两个兼容性滞后属性的元数据部分示例。
Listing 14: Compatibility flags in the pom.xml file’s URCap meta-data properties section
1 <! - -******************************************************************** - - >
2 <!- - Note : Update this section with relevant meta data -->
3 <!- - that comes along with your URCap -->
4 <! - -******************************************************************** - - >
5 <! - -******************* BEGINNING OF URCAP META DATA ******************* - - >
6 <urcap . symbolicname > com .ur. urcap . examples . helloworldswing </ urcap . symbolicname >
7 <urcap .vendor > Universal Robots </ urcap .vendor >
8 <urcap . contactAddress > Energivej 25 , 5260 Odense S, Denmark </ urcap .
contactAddress >
9 <urcap . copyright > Copyright (C) 2009 -2021 Universal Robots . All Rights Reserved
</ urcap . copyright >
10 <urcap . description > Hello World Swing sample URCap </ urcap . description >
11 <urcap . licenseType > Sample license </ urcap . licenseType >
12 <urcap . compatibility .CB3 >true </ urcap . compatibility .CB3 >
13 <urcap . compatibility . eSeries >true </ urcap . compatibility . eSeries >
14 <! - -********************** END OF URCAP META DATA ********************** - - >
这两个属性分别指定URCap与CB3和e系列机器人系列的兼容性。属性的可接受值是true或false。true值表示URCap可以在给定的机器人系列上安装和运行,false值表示URCap不能在给定的机器人系列上安装和运行。请注意,必须同时提供两个滞后值,包括URCap不兼容的机器人系列的滞后值。
使用第11节中提到的newURCap.sh脚本,使用Maven Archetype创建新的瘦项目,可以自动处理兼容性滞后问题。另一方面,如果现有的URCap需要更新以支持兼容性滞后,您必须手动更新URCap项目的pom.xml文件。只有当您使用低于1.12.0版本的URCap SDK创建URCap时,才需要使用newURCap.sh脚本或基于SDK中包含的URCap示例项目之一的修改来创建URCap。所需的更改在12.1.3小节“更新现有URCap”中进行了描述。
如果URCap的兼容性发生了变化,请记得相应地更新URCap的兼容性滞后值。
12.1.2 URCaps的安装和启动
当最终用户试图通过PolyScope中的URCap设置/设置屏幕安装新的URCap时,PolyScope将检查URCap的兼容性滞后。根据URCap兼容性滞后的布尔值和最终用户机器人(或在线模拟器)系列的类型,用户将被允许安装或阻止安装该URCap。如果URCap不兼容,最终用户将通过对话框得到通知。
同样,如果在启动PolyScope期间,UR- Cap是使用Maven(第6节“使用Maven进行部署”中所述)部署和安装的,而不是通过PolyScope UI安装的,则将检查UR- Cap的兼容性滞后。如果UR- Cap不兼容,则不允许启动,PolyScope中会显示错误对话框。
PolyScope启动期间将验证URCap是否存在兼容性滞后(如果URCap是使用Maven部署和安装的),如果缺少任何滞后,则不会启动URCap。同样,缺少兼容性滞后的URCap将无法通过PolyScope安装。在这些情况下,PolyScope将显示错误对话框。
请注意,如果不存在兼容性滞后,则仅会阻止启动或安装取决于URLCap API 1.12.0或更高版本的URLCap。
12.1.3 更新现有URCaps
如果你有一个现有的URCap需要更新以支持兼容性滞后,则必须对URCap项目的pom.xml文件进行更改。
首先,您必须将两个兼容性滞后属性 urcap .compatibility .CB3 和 urcap .compatibility .eSeries 添加到 URCap 元数据部分,如第 12.1.1 节“兼容性标志”中的清单 14 所示。请记住指定与 UR- Cap 兼容性相对应的布尔值。
Listing 15: Excerpt of the pom.xml file’s Maven bundle plugin configuration with compatiblity
flag support
1 ...
2 <build >
3 <plugins >
4 ...
5 <plugin >
6 <groupId > org . apache .felix </ groupId >
7 <artifactId >maven - bundle - plugin </ artifactId >
8 ...
9 <configuration >
10 <instructions >
11 <! - -******** DO NOT MODIFY THE ENTRIES OF THIS SECTION ******** - - >
12 <Bundle - Category >URCap </ Bundle - Category >
13 ...
14 <URCapCompatibility -CB3 >${ urcap . compatibility . CB3 } </
URCapCompatibility -CB3 >
15 <URCapCompatibility - eSeries >${ urcap . compatibility . eSeries } </
URCapCompatibility - eSeries >
16 <! - -*********************************************************** - - >
17 ...
18 <instructions >
19 <configuration >
20 <plugin >
21 ...
22 <plugins >
23 ...
为了使PolyScope能够读取兼容性滞后属性的指定值,还需要更新带有构建插件配置的<build>部分。在这里,必须更新Maven捆绑包插件的配置,以包含两个新指令<URCapCompatibility-CB3>和<URCapCompatibility-eSeries>,如列表15中的摘录所示。
为了方便起见,您可以使用 upgradeURCap.sh 脚本来更新您的 pom.xml 文件,而不是手动进行上述更改。
以下是脚本使用的示例,其中 /home/myuser/myURCap 是 URCap 项目文件夹的路径,/home/myuser/sdk 是 URCap SDK 文件夹的路径。
转到URCap SDK的文件夹,然后键入
$ ./ upgradeURCap .sh / home / myuser / myURCap
这将把所需的更改应用于 /home/myuser/myURCap 文件夹内的 URCap 项目的 pom.xml 文件。默认情况下,这两个兼容性滞后属性都被分配了布尔值 true(即您的 URCap 与 CB3 和 e-Series 机器人系列兼容)。如果预分配的默认值与您的 URCap 的兼容性不匹配,请记住相应地更改 pom.xml 文件中的兼容性滞后属性的值。
除了指定URCap项目文件夹的绝对路径外,您还可以指定相对路径
$ ./ upgradeURCap .sh ../ myURCap
此外,还可以将 upgradeURCap.sh 脚本复制到 URCap 项目文件夹中,然后通过键入以下命令从该文件夹中执行该脚本
$ cd myURCap
$ ./ upgradeURCap .sh .
最后,您可以选择使用compatibilityCB3和compatibilityESeries参数直接指定兼容性延迟的布尔值
$ ./ upgradeURCap .sh ../ myURCap compatibilityCB3 = false compatibilityESeries =
true
12.2 API兼容性
在开发URCaps时,您必须指定对要编译的URLCap API版本的依赖项。使用第11节中提到的newURCap.sh脚本。使用Maven Archetype创建新的瘦项目,这是自动为您处理的。第11节结尾介绍了如何更新现有URCap项目的URCap API依赖项版本。使用Maven Archetype创建新的瘦项目。
给定版本的API与特定版本的PolyScope兼容(见下表1)。PolyScope将与API的早期版本保持向后兼容。这意味着,如果您选择使用最新的API,则使用您的URCap的客户必须至少运行
发布给定API的PolyScope版本。
如果客户运行的是 PolyScope 的较新(未来)版本,则不会出现问题。但是,如果客户运行的PolyScope版本早于API发布的版本,则客户不可能使用您的URCap。因此,一个很好的经验法则是选择支持您希望使用的功能的API的最早版本。这将面向最广泛的受众。
例如,如果您指定了对API 1.1.0版本的依赖,则URCap将仅在PolyScope 3.4.0或更高版本上运行。如果您希望瞄准尽可能广泛的受众,您必须使用API 1.0.0版本,客户必须运行PolyScope 3.3.0或更高版本。
请注意,API 1.12.0版是CB3机器人支持的最终API版本。API更高版本仅适用于e系列机器人。
12.2.1 高级兼容性
与上面描述的相反,可以根据比PolyScope官方支持的新的API加载URCap。通过锥形化您的URCap以在运行时而不是安装时解析其依赖项,PolyScope将启动您的URCap,而不考虑指定的URLCap API版本依赖项。必须注意代码执行路径不使用给定版本的PolyScope支持的API中不可用的任何内容(否则将抛出NoSuchMethodError或NoClassDefFoundError)。
例如,您可以依赖API 1.5.0版本,并在PolyScope 3.7.0/5.1.0版本(官方仅支持API 1.4.0版本)上运行它,但在实际执行路径中,您只能使用API 1.4.0版本中的类型。
为了使URCap在运行时解析,pom.xml必须具有以下选项;resolution:=可选,附加到<import-package>部分中的URLcap API条目。完整的 <import-package> 部分可能看起来像这样
Listing 16: Excerpt of pom.xml file for advanced compatibility
1 ...
2 <Import - Package >
3 com .ur. urcap . api *; resolution := optional ,
4 *
5 </ Import - Package >
6 ...
这将使URCap启动,而不管实际的依赖关系状态如何。
如前所述,您还必须构建代码,这样就不会执行引用不受支持的API函数的代码。在将执行的类中也不得出现引用不支持类型的导入或捕获子句。清单17和18给出了如何构建此结构的示例。在清单17中,找到了与不受支持的API功能相关的所有代码,在18中,在创建AdvancedFeature类的实例之前,检查PolyScope版本号。
Listing 17: AdvancedFeature class showing advanced compatiblity
1 import com .ur. urcap . api. contribution . installation . InstallationAPIProvider ;
2 import com .ur. urcap . api. domain . InstallationAPI ;
3 import com .ur. urcap . api. domain . value . Pose ;
4 import com.ur. urcap . api. domain . value . PoseFactory ;
5 import com.ur. urcap . api. domain . value . simple . Angle ;
6 import com.ur. urcap . api. domain . value . simple . Length ;
7
8 public class AdvancedFeature {
9 private final InstallationAPIProvider apiProvider ;
10
11 public AdvancedFeature ( InstallationAPIProvider apiProvider ) {
12 this . apiProvider = apiProvider ;
13 }
14
15 public void addTCP () {
16 InstallationAPI installationAPI = apiProvider . getInstallationAPI () ;
17 PoseFactory poseFactory = installationAPI . getValueFactoryProvider () .
getPoseFactory () ;
18 Pose pose = poseFactory . createPose (0 , 0 , 100 , 0, 0, 0, Length . Unit .MM ,
Angle . Unit . RAD );
19 apiProvider . getInstallationAPI () . getTCPContributionModel () . addTCP ("
GRIPPER_TCP ", " Gripper ", pose );
20 }
21 }
Listing 18: Usage of AdvancedFeature class
1 SoftwareVersion softwareVersion = apiProvider . getSystemAPI () .
getSoftwareVersion () ;
2 if (( softwareVersion . getMajorVersion () == 3 && softwareVersion .
getMinorVersion () >= 8) ||
3 softwareVersion . getMajorVersion () == 5 && softwareVersion .
getMinorVersion () >= 2) {
4 new AdvancedFeature ( apiProvider ) . addTCP () ;
5 }
如果您选择使用此高级功能,您必须在所有您希望支持的PolyScope版本上仔细测试URCap,以确保所有代码执行路径都经过测试。
13 异常处理
如果在URCap中抛出且未捕获的所有异常,PolyScope都将捕获它们。如果当最终用户从URCap中选择安装节点或程序节点时发生这种情况,则URCap提供的UI将被替换为显示错误信息的屏幕。在其他所有情况下,将向最终用户显示一个对话框。错误屏幕和对话框将显示在URCap中发生的异常以及有关URCap的元数据信息。如果调用堆栈源自PolyScope(即当异常发生在PolyScope调用由URCap实现的URCap API接口中定义的方法时)或在PolyScope内部发生(例如由于在API方法调用中传递非法参数所致),则会出现这种情况。在这种情况下,它还将包含一个部分来显示来自异常的堆栈跟踪。如果在URCap的源代码中发生未捕获的异常(例如空指针异常),则PolyScope将尝试识别失败的URCap。如果成功,将显示错误对话框。如果PolyScope无法识别失败的URCap,则将显示没有元数据的通用错误对话框。
14 故障排除
在PolyScope内部,URCap作为OSGi包与Apache Felix OSGi框架一起安装。为了调试问题,可以使用Apache Felix命令行检查有关包的各种信息。
您可以通过在端口6666上打开一个TCP连接来建立与正在运行的Apache Felix的shell连接。
1 $ nc 127.0.0.1 6666
2
3 Felix Remote Shell Console :
4 ============================
5
6 ->
请注意,您需要使用nc命令,因为telnet命令在机器人上不可用,并且需要使用127.0.0.1,因为localhost在机器人上不起作用。
要查看已安装的捆绑包及其状态类型列表,请执行以下命令
1 -> ps
2 START LEVEL 1
3 ID State Level Name
4 [ 0] [ Active ] [ 0] System Bundle (5.2.0)
5 [ 1] [ Active ] [ 1] aopalliance (1.0)
6 [ 2] [ Active ] [ 1] org. aspectj . aspectjrt (1.8.2)
7 [ 3] [ Active ] [ 1] org. netbeans . awtextra (1.0)
8 [ 4] [ Active ] [ 1] net. java . balloontip (1.2.4)
9 [ 5] [ Active ] [ 1] cglib (2.2)
10 [ 6] [ Active ] [ 1] com.ur. dashboardserver (3.3.0. SNAPSHOT )
11 [ 7] [ Active ] [ 1] com.ur. domain (3.3.0. SNAPSHOT )
12 ...
13 [ 56] [ Active ] [ 1] com . thoughtworks . xstream (1.3.1)
14 [ 57] [ Active ] [ 1] helloworldswing (1.0.0. SNAPSHOT )
15 ->
在shell中,您可以键入help以查看可用命令的列表
1 -> help
2 uninstall
3 sysprop
4 bundlelevel
5 find
6 version
7 headers
8 refresh
9 start
10 obr
11 inspect
12 ps
13 stop
14 shutdown
15 help
16 update
17 install
18 log
19 cd
20 startlevel
21 resolve
22
23 Use ’help <command -name >’ for more information .
24 ->
例如,可以执行headers命令来显示单个已安装包的不同的属性
A URCaps和生成的脚本代码
URCap可以为安装和程序节点生成脚本代码。为了帮助调试,为这两种节点类型生成的脚本代码都注明了URCap信息。
以下示例取自使用Hello World Swing URCap的小程序。
要查看URCap生成的脚本代码,需要保存程序。假设程序名为hello.urp,则可以在hello.script中找到相应的脚本代码。
安装节点的脚本代码将用开始/结束URCap注释以及有关URCap的来源及其类型的信息包围
1 ...
2 # begin : URCap Installation Node
3 # Source : Hello World Swing , 1.0.0. SNAPSHOT , Universal Robots
4 # Type : Hello World Swing
5 hello_world_swing_popup_title = " Hello World "
6 # end: URCap Installation Node
7 ...
对于程序节点,脚本代码被开始/结束URCap注释包围,并包含有关URCap的来源及其类型的信息,如下所示。PolyScope生成的程序节点是# begin: URCap Program Node后的第一个标签,这里为$ 2。# end: URCap Program Node之前的其余标签,这里为语句$ 3,是插入在Hello World程序节点下的节点。
1 ...
2 # begin : URCap Program Node
3 # Source : Hello World Swing , 1.0.0. SNAPSHOT , Universal Robots
4 # Type : Hello World Swing
5 $ 2 " Hello World Swing : My node "
6 popup (" Hello My node , welcome to PolyScope !", hello_world_swing_popup_title ,
False , False , blocking = True )
7 $ 3 " Wait : 0.01 "
8 sleep (0.01)
9 # end: URCap Program Node
10 ...
B 我的守护程序和安装节点
Listing 19: Java class defining functionality for the My Daemon installation node
1 package com .ur. urcap . examples . mydaemonswing . impl ;
2
3 import com .ur. urcap . api. contribution . DaemonContribution ;
4 import com .ur. urcap . api. contribution . InstallationNodeContribution ;
5 import com .ur. urcap . api. contribution . installation . CreationContext ;
6 import com .ur. urcap . api. contribution . installation . InstallationAPIProvider ;
7 import com.ur. urcap . api. domain . data . DataModel ;
8 import com.ur. urcap . api. domain . script . ScriptWriter ;
9 import com.ur. urcap . api. domain . userinteraction . inputvalidation .
InputValidationFactory ;
10 import com.ur. urcap . api . domain . userinteraction . keyboard . KeyboardInputCallback ;
11 import com.ur. urcap . api . domain . userinteraction . keyboard . KeyboardInputFactory ;
12 import com.ur. urcap . api . domain . userinteraction . keyboard . KeyboardTextInput ;
13
14 import java .awt .*;
15 import java . util . Timer ;
16 import java . util . TimerTask ;
17
18 public class MyDaemonInstallationNodeContribution implements
InstallationNodeContribution {
19 private static final String POPUPTITLE_KEY = " popuptitle ";
20
21 private static final String XMLRPC_VARIABLE = " my_daemon_swing ";
22 private static final String ENABLED_KEY = " enabled ";
23 private static final String DEFAULT_VALUE = " Hello My Daemon ";
24 public static final int PORT = 40405;
25
26 private DataModel model ;
27
28 private final MyDaemonInstallationNodeView view ;
29 private final MyDaemonDaemonService daemonService ;
30 private XmlRpcMyDaemonInterface xmlRpcDaemonInterface ;
31 private Timer uiTimer ;
32 private boolean pauseTimer = false ;
33
34 private KeyboardInputFactory keyboardInputFactory ;
35 private final InputValidationFactory inputValidationFactory ;
36
37 public MyDaemonInstallationNodeContribution ( InstallationAPIProvider
apiProvider , MyDaemonInstallationNodeView view , DataModel model ,
MyDaemonDaemonService daemonService , CreationContext context ) {
38 keyboardInputFactory = apiProvider . getUserInterfaceAPI () .
getUserInteraction () . getKeyboardInputFactory () ;
39 inputValidationFactory = apiProvider . getUserInterfaceAPI () .
getUserInteraction () . getInputValidationFactory () ;
40 this . view = view ;
41 this . daemonService = daemonService ;
42 this . model = model ;
43 xmlRpcDaemonInterface = new XmlRpcMyDaemonInterface (" 127.0.0.1 ", PORT );
44 if ( context . getNodeCreationType () == CreationContext . NodeCreationType . NEW )
{
45 model .set ( POPUPTITLE_KEY , DEFAULT_VALUE );
46 }
47 applyDesiredDaemonStatus () ;
48 }
49
50 @Override
51 public void openView () {
52 view . setPopupText ( getPopupTitle () );
53
54 // UI updates from non -GUI threads must use EventQueue . invokeLater (or
SwingUtilities . invokeLater )
55 uiTimer = new Timer ( true );
56 uiTimer . schedule (new TimerTask () {
57 @Override
58 public void run () {
59 EventQueue . invokeLater ( new Runnable () {
60 @Override
61 public void run () {
62 if (! pauseTimer ) {
63 updateUI () ;
64 }
65 }
66 }) ;
67 }
68 }, 0, 1000) ;
69 }
70
71 @Override
72 public void closeView () {
73 if ( uiTimer != null ) {
74 uiTimer . cancel () ;
75 }
76 }
77
78 @Override
79 public void generateScript ( ScriptWriter writer ) {
80 writer . assign ( XMLRPC_VARIABLE , " rpc_factory (\" xmlrpc \" , \" http
://127.0.0.1: " + PORT + "/ RPC2 \") ");
81 // Apply the settings to the daemon on program start in the Installation
pre - amble
82 writer . appendLine ( XMLRPC_VARIABLE + ". set_title (\"" + getPopupTitle () + "
\") ");
83 }
84
85 private void updateUI () {
86 DaemonContribution . State state = getDaemonState () ;
87
88 if ( state == DaemonContribution . State . RUNNING ) {
89 view . setStartButtonEnabled ( false );
90 view . setStopButtonEnabled ( true );
91 } else {
92 view . setStartButtonEnabled ( true );
93 view . setStopButtonEnabled ( false );
94 }
95
96 String text = "";
97 switch ( state ) {
98 case RUNNING :
99 text = "My Daemon runs ";
100 break ;
101 case STOPPED :
102 text = "My Daemon stopped ";
103 break ;
104 case ERROR :
105 text = "My Daemon failed ";
106 break ;
107 }
108
109 view . setStatusLabel ( text );
110 }
111
112 public void onStartClick () {
113 model .set ( ENABLED_KEY , true );
114 applyDesiredDaemonStatus () ;
115 }
116
117 public void onStopClick () {
118 model .set ( ENABLED_KEY , false );
119 applyDesiredDaemonStatus () ;
120 }
121
122 private void applyDesiredDaemonStatus () {
123 new Thread ( new Runnable () {
124 @Override
125 public void run () {
126 if ( isDaemonEnabled () ) {
127 // Download the daemon settings to the daemon process on initial
start for real - time preview purposes
128 try {
129 pauseTimer = true ;
130 awaitDaemonRunning (5000) ;
131 xmlRpcDaemonInterface . setTitle ( getPopupTitle () );
132 } catch ( Exception e){
133 System . err . println (" Could not set the title in the daemon process .
");
134 } finally {
135 pauseTimer = false ;
136 }
137 } else {
138 daemonService . getDaemon () . stop () ;
139 }
140 }
141 }) . start () ;
142 }
143
144 private void awaitDaemonRunning ( long timeOutMilliSeconds ) throws
InterruptedException {
145 daemonService . getDaemon () . start () ;
146 long endTime = System . nanoTime () + timeOutMilliSeconds * 1000 L * 1000 L;
147 while ( System . nanoTime () < endTime && ( daemonService . getDaemon () . getState ()
!= DaemonContribution . State . RUNNING || ! xmlRpcDaemonInterface .
isReachable () )) {
148 Thread . sleep (100) ;
149 }
150 }
151
152 public String getPopupTitle () {
153 return model . get ( POPUPTITLE_KEY , DEFAULT_VALUE );
154 }
155
156 public KeyboardTextInput getInputForTextField () {
157 KeyboardTextInput keyboardInput = keyboardInputFactory .
createStringKeyboardInput () ;
158 keyboardInput . setErrorValidator ( inputValidationFactory .
createStringLengthValidator (1 , 255) );
159 keyboardInput . setInitialValue ( getPopupTitle () );
160 return keyboardInput ;
161 }
162
163 public KeyboardInputCallback < String > getCallbackForTextField () {
164 return new KeyboardInputCallback <String >() {
165 @Override
166 public void onOk ( String value ) {
167 setPopupTitle ( value );
168 view . setPopupText ( value );
169 }
170 };
171 }
172
173 private void setPopupTitle ( String title ) {
174 model .set ( POPUPTITLE_KEY , title );
175 // Apply the new setting to the daemon for real - time preview purposes
176 // Note this might influence a running program , since the actual state is
stored in the daemon .
177 try {
178 xmlRpcDaemonInterface . setTitle ( title ) ;
179 } catch ( Exception e){
180 System . err . println (" Could not set the title in the daemon process .") ;
181 }
182 }
183
184 public boolean isDefined () {
185 return model . isSet ( POPUPTITLE_KEY ) && getDaemonState () ==
DaemonContribution . State . RUNNING ;
186 }
187
188 private DaemonContribution . State getDaemonState () {
189 return daemonService . getDaemon () . getState () ;
190 }
191
192 private Boolean isDaemonEnabled () {
193 return model . get ( ENABLED_KEY , true ); // This daemon is enabled by default
194 }
195
196 public String getXMLRPCVariable () {
197 return XMLRPC_VARIABLE ;
198 }
199
200 public XmlRpcMyDaemonInterface getXmlRpcDaemonInterface () {
201 return xmlRpcDaemonInterface ;
202 }
203 }
Listing 20: Java class defining functionality for the My Daemon program node
1
2 package com .ur. urcap . examples . mydaemonswing . impl ;
3
4 import com.ur. urcap . api . contribution . ProgramNodeContribution ;
5 import com.ur. urcap . api . contribution . program . ProgramAPIProvider ;
6 import com.ur. urcap . api . domain . data . DataModel ;
7 import com.ur. urcap . api . domain . script . ScriptWriter ;
8 import com.ur. urcap . api . domain . userinteraction . keyboard . KeyboardInputCallback ;
9 import com.ur. urcap . api . domain . userinteraction . keyboard . KeyboardInputFactory ;
10 import com.ur. urcap . api . domain . userinteraction . keyboard . KeyboardTextInput ;
11
12 import java .awt .*;
13 import java . util . Timer ;
14 import java . util . TimerTask ;
15
16 public class MyDaemonProgramNodeContribution implements
ProgramNodeContribution {
17 private static final String NAME = " name ";
18
19 private final ProgramAPIProvider apiProvider ;
20 private final MyDaemonProgramNodeView view ;
21 private final DataModel model ;
22
23 private Timer uiTimer ;
24 private KeyboardInputFactory keyboardInputFactory ;
25
26 public MyDaemonProgramNodeContribution ( ProgramAPIProvider apiProvider ,
MyDaemonProgramNodeView view , DataModel model ) {
27 this . apiProvider = apiProvider ;
28 keyboardInputFactory = apiProvider . getUserInterfaceAPI () .
getUserInteraction () . getKeyboardInputFactory () ;
29 this . view = view ;
30 this . model = model ;
31 }
32
33 @Override
34 public void openView () {
35 view . setNameText ( getName () );
36
37 // UI updates from non -GUI threads must use EventQueue . invokeLater (or
SwingUtilities . invokeLater )
38 uiTimer = new Timer ( true );
39 uiTimer . schedule (new TimerTask () {
40 @Override
41 public void run () {
42 EventQueue . invokeLater ( new Runnable () {
43 @Override
44 public void run () {
45 updatePreview () ;
46 }
47 }) ;
48 }
49 }, 0, 1000) ;
50 }
51
52 @Override
53 public void closeView () {
54 uiTimer . cancel () ;
55 }
56
57 @Override
58 public String getTitle () {
59 return "My Daemon : " + getName () ;
60 }
61
62 @Override
63 public boolean isDefined () {
64 return getInstallation () . isDefined () && ! getName () . isEmpty () ;
65 }
66
67 @Override
68 public void generateScript ( ScriptWriter writer ) {
69 // Interact with the daemon process through XML - RPC calls
70 // Note , alternatively plain sockets can be used .
71 writer . assign (" mydaemon_message ", getInstallation () . getXMLRPCVariable () +
". get_message (\"" + getName () + " \") ");
72 writer . assign (" mydaemon_title ", getInstallation () . getXMLRPCVariable () + ".
get_title ()");
73 writer . appendLine (" popup ( mydaemon_message , mydaemon_title , False , False ,
blocking = True )");
74 writer . writeChildren () ;
75 }
76
77 private void updatePreview () {
78 String title ;
79 String message ;
80 try {
81 // Provide a real - time preview of the daemon state
82 title = getInstallation () . getXmlRpcDaemonInterface () . getTitle () ;
83 message = getInstallation () . getXmlRpcDaemonInterface () . getMessage (
getName () );
84 } catch ( Exception e) {
85 System . err . println (" Could not retrieve essential data from the daemon
process for the preview .") ;
86 title = message = "<Daemon disconnected >";
87 }
88
89 view . setTitlePreview ( title );
90 view . setMessagePreview ( message );
91 }
92
93 public KeyboardTextInput getInputForTextField () {
94 KeyboardTextInput keyboardTextInput = keyboardInputFactory .
createStringKeyboardInput () ;
95 keyboardTextInput . setInitialValue ( getName () );
96 return keyboardTextInput ;
97 }
98
99 public KeyboardInputCallback < String > getCallbackForTextField () {
100 return new KeyboardInputCallback <String >() {
101 @Override
102 public void onOk ( String value ) {
103 setName ( value );
104 view . setNameText ( value );
105 updatePreview () ;
106 }
107 };
108 }
109
110 private String getName () {
111 return model . get (NAME , "");
112 }
113
114 private void setName ( String name ) {
115 if ("". equals ( name ) ){
116 model . remove ( NAME );
117 } else {
118 model .set (NAME , name );
119 }
120 }
121
122 private MyDaemonInstallationNodeContribution getInstallation () {
123 return apiProvider . getProgramAPI () . getInstallationNode (
MyDaemonInstallationNodeContribution . class );
124 }
125 }
Listing 21: Java class for XML-RPC communication
1 package com .ur. urcap . examples . mydaemonswing . impl ;
2
3 import org. apache . xmlrpc . XmlRpcException ;
4 import org. apache . xmlrpc . client . XmlRpcClient ;
5 import org. apache . xmlrpc . client . XmlRpcClientConfigImpl ;
6
7 import java .net . MalformedURLException ;
8 import java .net .URL;
9 import java . util . ArrayList ;
10
11 public class XmlRpcMyDaemonInterface {
12
13 private final XmlRpcClient client ;
14
15 public XmlRpcMyDaemonInterface ( String host , int port ) {
16 XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl () ;
17 config . setEnabledForExtensions ( true );
18 try {
19 config . setServerURL ( new URL (" http :// " + host + ":" + port + "/ RPC2 ")) ;
20 } catch ( MalformedURLException e) {
21 e. printStackTrace () ;
22 }
23 config . setConnectionTimeout (1000) ; //1s
24 client = new XmlRpcClient () ;
25 client . setConfig ( config );
26 }
27
28 public boolean isReachable () {
29 try {
30 client . execute (" get_title ", new ArrayList < String >() );
31 return true ;
32 } catch ( XmlRpcException e) {
33 return false ;
34 }
35 }
36
37 public String getTitle () throws XmlRpcException , UnknownResponseException {
38 Object result = client . execute (" get_title ", new ArrayList < String >() );
39 return processString ( result );
40 }
41
42 public String setTitle ( String title ) throws XmlRpcException ,
UnknownResponseException {
43 ArrayList < String > args = new ArrayList <String >() ;
44 args . add ( title );
45 Object result = client . execute (" set_title ", args );
46 return processString ( result );
47 }
48
49 public String getMessage ( String name ) throws XmlRpcException ,
UnknownResponseException {
50 ArrayList < String > args = new ArrayList <String >() ;
51 args . add ( name );
52 Object result = client . execute (" get_message ", args );
53 return processString ( result );
54 }
55
56 private boolean processBoolean ( Object response ) throws
UnknownResponseException {
57 if ( response instanceof Boolean ) {
58 Boolean val = ( Boolean ) response ;
59 return val . booleanValue () ;
60 } else {
61 throw new UnknownResponseException () ;
62 }
63 }
64
65 private String processString ( Object response ) throws
UnknownResponseException {
66 if ( response instanceof String ) {
67 return ( String ) response ;
68 } else {
69 throw new UnknownResponseException () ;
70 }
71 }
72 }
Listing 22: hello-world.py Python 2.5 daemon example
1 #!/ usr / bin / env python
2
3 import sys
4
5 from SimpleXMLRPCServer import SimpleXMLRPCServer
6 from SocketServer import ThreadingMixIn
7
8 title = ""
9
10 def set_title ( new_title ):
11 global title
12 title = new_title
13 return title
14
15 def get_title () :
16 tmp = ""
17 if str ( title ):
18 tmp = title
19 else :
20 tmp = "No title set "
21 return tmp + " ( Python )"
22
23 def get_message ( name ):
24 if str ( name ):
25 return " Hello " + str( name ) + ", welcome to PolyScope !"
26 else :
27 return "No name set"
28
29 sys . stdout . write (" MyDaemon daemon started ")
30 sys . stderr . write (" MyDaemon daemon started ")
31
32 class MultithreadedSimpleXMLRPCServer ( ThreadingMixIn , SimpleXMLRPCServer ):
33 pass
34
35 server = MultithreadedSimpleXMLRPCServer ((" 127.0.0.1 ", 40405) )
36 server . RequestHandlerClass . protocol_version = " HTTP /1.1 "
37 server . register_function ( set_title , " set_title ")
38 server . register_function ( get_title , " get_title ")
39 server . register_function ( get_message , " get_message ")
40 server . serve_forever ()