4. 用Jython和Java编写新设备类

4.1. 介绍

可以使用GDA中的核心类编写新设备。这些代码可以用Jython或Java编写。

对于Jython和Java:

  1. 在代码中定义新设备

  2. 加载到服务器(对象服务器)

对于Jython:

  1. 在扩展ScanableMotionBase的Jython脚本中定义类

  2. 通过导入Jython模块将它们加载到对象服务器,并创建Jython定义的设备的实例

对于Java:

  1. 用Java编写实现不同设备接口的新设备。在这里,我们通过编写新的可扫描设备来说明

  2. 导入Spring Bean配置文件中定义的类的实例

为了说明用Java开发新设备并将它们合并到GDA中的过程,我们描述了几个实现Scanable接口的新设备的开发过程。然后,通过编辑服务器在启动时读取的配置文件,将这些设备包括在系统中。然后可以从Jython终端在GDA中扫描和操作这些设备。

在使用GDA的每个站点上,为GDA的新设备开发软件可能是一个要求,以便将特定的光束线组件容纳到GDA软件框架中。

用户应该首先阅读GDA用户手册中的“第5章:扫描”,了解GDA中使用的基本数据采集技术的介绍。下面,我们将描述开发实现Scanable接口的新类。这可能需要在每个站点使用GDA进行开发,以便将特定的光束线组件容纳到GDA软件框架中。

4.2. Scanable接口和ScanableBase类

所有Scanable类都实现Scanable接口。实现Scanable接口的核心基类在GDA中作为类gda.devive.scannable.ScanableBase提供。新的用户定义的可扫描实现应该扩展ScanableBase。发出命令‘ls Scanable’后,这些实例将在GDA终端中可见。

Scanable实现的最重要方法是:

  • getPosition()

  • 异步移动到()

  • isBusy()

扫描对象中必须定义的其他字段包括:

  • 名称

  • 初始位置

  • inputNames

  • 外部名称

  • 输出格式

  • 单位

有关可扫描实现中可用参数的完整描述,请参阅“GDA用户手册”的“第5章:扫描”。

文档配置源目录中提供了一个测试类,它具有用于构造几种不同类型的“虚拟”或可测试软件扫描对象的实例的静电方法:org.myls.gda.device.scannable.ScannableClassGenerator.它有几种方法:

  • genarateScanable高斯()

  • 生成可扫描高斯(高斯)

  • GenerateScanableSine()

  • GenerateScanableSine(正弦波)

此生成器构造两个可扫描类ScanableGauss和ScanableSine的实例。这些可扫描类在getPosition()返回的值上有所不同。对于ScanableGauss,该方法返回指定位置、宽度和高度为1的高斯的值,如果定义了附加噪声,则返回指定x值处的值:

@Override
public Object getPosition() throws DeviceException {

    // we assume the position is a double - it is only for testing
    double x = (Double) super.getPosition();
    double x2 = x - centre;
    double sigma = 0.425 * width // FWHM -> sd
    double noiseVal = height * (Math.random() * noise;
    double y = Math.exp(-(x2 * x2) / (sigma * sigma)) + noiseVal;
    return new Double[] { x, y };
}

4.3. 关于可扫描特性的描述及其之间的关系

(本材料来源于GDA用户手册中的“第5章:扫描”;为方便起见,在此重复)

必须在所有扫描对象的构造函数中设置多个字段的值。这些必填字段是:

  • 名称

  • inputNames

  • 外部名称

  • 输出格式

  • 当前位置

字段“inputNames”、“outputNames”和“outputFormat”一起定义此Scanable表示的数字、它们的名称以及将它们的值打印到文件或控制台的格式。

“”inputNames“”数组定义此Scanable的rawAchronousMoveTo预期的数组大小。inputNames数组的每个元素都是该元素的标签,用于文件头等。请注意,如果需要,此数组可以为空(大小为0)。

ExtraNames‘’数组的使用方式与inputNames数组类似,但列出了Scanable的rawGetPosition()方法返回的数组中的其他元素,即getRawPosition()返回的数组可能大于rawAsynousMoveTo()所需的数组。这允许Scanable保存和返回比移动pr所需更多的信息,以便在其rawAchronousMoveTo()方法内执行任何操作。此数组通常为空(大小为0)。

“”outputFormat“”数组列出了inputNames和ExtraNames数组元素的格式字符串。将rawGetPosition()方法的输出打印到控制台和日志文件时使用。

注解

绝对要求outputFormat数组的长度是inputNames和outputNames数组的长度之和,这样Scanable才能正常工作。‘“’

4.4. 向服务器添加新设备

通过将新设备定义为Spring beans配置文件中的bean,将其添加到服务器。在发行版中,此文件为‘xml’目录中的‘server_beans.xml’。有关在Spring bean配置文件中将新对象实例定义为bean的语法,可以参考此文件。此文件中定义的bean在服务器启动时加载到对象服务器中,并且可以由GDA客户端访问和操作。

可以使用getter和构造函数依赖注入。服务器上的每个对象都必须有一个“name”属性,该属性是其在服务器对象命名空间中的唯一标识符。作为示例,我们使用不同的bean定义定义了ScanableGauss类的几个实例:

  • scannableGaussian0-Bean定义中设置的所有属性

  • scannableGaussian1-仅在bean中设置高斯属性。其他属性(如输入和额外名称以及输出格式)在Java构造函数中设置为默认值

  • scannableGaussian2-使用构造函数参数定义scannable,该参数是Spring配置文件中定义的测试高斯bean。这演示了Spring的构造函数依赖项注入

  • scannableGaussian3-Bean中没有定义任何属性或构造函数参数。scannable是使用默认的无参数构造函数构造的。在Java类中,所有必需的属性都设置为默认值。

Spring配置文件中的scannableSine类的几个实例提供了类似的示例:

  • scannableSine0-正弦的名称和属性在bean定义中设置。其他属性(如输入和额外名称以及输出格式)的默认值在Java类中定义。

  • scannableSine1-正弦的属性由Bean配置文件中定义的测试正弦Bean(‘testSineWave’Bean)分配给对象

  • scannableSine2-在bean定义中没有定义除名称之外的任何属性。所有其他属性都在Java类的零参数构造函数中设置。

4.4.1. 示例:带有设置器注入的可扫描高斯

Scanable高斯的字段在Spring bean配置文件中设置为属性,并定义默认值。原子字段使用‘name’和‘value’属性字段定义;数组字段使用‘list’标记定义:

<bean id='scannableGaussian1' class='org.myls.gda.device.scannable.ScannableGaussian'>
   <property name='name' valuew='simpleScannable1'/>
   <property name='position' value='0.0'/>
   <property name='inputNames'>
      <list>
          <value>x</value>
      </list>
   </property>
   <property name='extraNames'>
      <list>
          <value>y</value>
      </list>
   </property>
   <property name='level' value='3'/>
   <property name='outputFormat'>
      <list>
          <value>%5.5G</value>
          <value>%5.5G</value>
      </list>
   </property>
   <property name='units'>
      <list>
          <value>mm</value>
          <value>counts</value>
      </list>
   </property>
</bean>

现在使用预定义的高斯Spring bean实例化ScanableGaussbean。测试高斯对象的Spring Bean定义:

<bean id='testGaussian' class='org.myls.gda.device.scannable.Gaussian'>
   <property name='testGaussian' value='testGaussian'/>
   <property name='centre' value='0.0'/>
   <property name='width' value='1.0'/>
   <property name='height' value='1.0'/>
   <property name='noise' value='0.1'/>
</bean>

此测试高斯bean可用于使用构造函数注入(将测试高斯作为构造函数参数)创建ScanableGauss的实例:

<bean id='scannableGaussian2'>
   <property name='name' value='scannableGassian2'/>
   <constructor-arg ref='testGaussian'/>
</bean>

4.4.2. 锻炼

从一个空的server_beans.xml文件开始,逐个添加可扫描组件,并在GDA Jython控制台中测试它们(需要重新启动服务器才能合并新组件)。

4.5. GDA中其他可扫描类和测试的示例

  • DummyMotor:来自核心:gda.device.Motor.DummyMotor

  • ScanableMotorTest:来自core/test:gda.device.scannable.ScanableMotorTest

  • 内核中的TotalDummyMotor(测试使用):gda.device.Motor.TotalDummyMotor

4.6. 演示终端中扫描仪的使用

现在可以从GDA客户端控制新组件。

4.6.1. 扫描1D

可以从GDA GUI中的Jython终端扫描和操作示例扫描。

按步骤0.01::扫描示例scannable scannableGaussian0,从-2到2。

>>> scan scannableGaussian0 -2.0 2.0 0.1

将scannableGaussian0的宽度从1更改为2,然后重新扫描::

>>> scannableGaussian0.setWidth(2)
>>> scan scannableGaussian0 -2.0 2.0 0.1

将scannableGaussian0的中心更改为-1.0并重新扫描::

>>> scannableGaussian0.setCentre(-1)
>>> scan scannableGaussian0 -2.0 2.0 0.1

4.6.2. 嵌套扫描

导入用户演示模块scannableClasses.py(位于‘Documentation/Users/Script’中,可从JythonEditor视图查看)中定义的演示可扫描类:

>>> import scannableClasses
>>> from scannableClasses import *
>>> sgw = ScannableGaussianWidth('sgw', scannableGaussian0)
>>> scan sgw 0.2 2.0 0.2 scannableGaussian0 -1.0 1.0 0.02

该嵌套扫描具有外部扫描,该外部扫描以0.2为步长将所包含的可扫描高斯的宽度设置为从0.2到2.0的不同值。然后,以0.02的步长绘制从-1.0到1.0的每个宽度的内部可扫描图像