Tango-way of having devices rely on each other

Hi tangoers,

what is the tango-way of ensuring that one device can only do X if a second device is in state Y?

For example let's assume you have a big laser and a water cooling system and one tango device for each of them. Obviously you want to ensure that the laser can only be turned on if the water is runing. On the other hand if someone turns off the laser the water cooling should be also stopped after grace period.

Now of course I could do the checking and synchronization between the two manually, but this problem sounds too generic in order for me being the first person to encounter it.

Combining both tango device servers into one is not a good solution IMHO.

Thanks,
Thomas
Hi Thomas,

what you described sounds like an interlock to me i.e. prevent A from doing something if B is not in a given state.

You are right this is a common scenario. We have hundreds of interlocks on our accelerator (water, beam position, thermocouple, vacuum) and we need to ensure they are all in a given state in order to turn on an operate the accelerator. Despite this we do not have a generic mechanism for automatically managing this in Tango. All cases to my knowledge are handled using one of the following approaches:

(1) device A reads either via a synchronous call or events the state(s) of B(s) before executing an action

(2) device B sends a hardware interlock to interrupt the beam or prevent it from switching on via device A

(3) device A and B are in the same server and A reads B's state before executing an action

Approach (1) is used for slow (scale of seconds) interlocks. Approach (2) is used for fast (scale of nano to milliseconds) critical interlocks and for switching of the beam without human intervention. Approach (3) is for intermediate speed (milliseconds to seconds) interlocks.

Your question about a generic solution in Tango is very valid. I think it doesn't exist because to date Tango has not been often used as a safety plc. This could be changed e.g. by introducing the possibility to link an action to the state of another device automatically (via the database for example). A bit like forwarded attributes. I heard about a generic Facade device server from MAXIV yesterday which could maybe be adapted to do this. We need their input to know if this can be done easily.

Andy
Hi Thomas,

As Andy said, this device interaction can be understood either as an interlock (one device stopping another one) or as a permit (a device is not allowed to do something if a pre-condition is not matched).

At Alba we normally use PLC's for interlocks; having few exceptions on interlocks triggered by Panic alarms. So the disabling of an ongoing action is always managed by a separate device (Tango or HW).

In the case of permits (e.g. enabling filling or orbit correction), we define a set of panic alarms and then we check the value of the alarm attribute before executing the target action. But this check is normally done at GUI's level or by some intermediate device (Composer or Façade) not in the target device itself.

If I had to implement this "precondition" behavior from scratch in an "standard" way, then I would have followed this approach:

* e.g. we have a device with an OpenValve() command that should be allowed only if a/b/c/Pressure has a valid value

* I would create an OpenValve_allowed property in Jive with the precondition:

  OpenValve_allowed = a/b/c/Pressure

* Then, check it in the is_OpenValve_allowed method of the device:

  def is_OpenValve_allowed(self,req_type):
    permit = AttributeProxy(self.OpenValve_allowed).read()
    if permit.quality != ATTR_VALID: 
      return False 
    else:
      return True

The same approach can be used for enabling/desabling an attribute using the is_{attribute}_allowed method. Using the permit quality for enabling/disabling the action would allow to easily tune the permits from jive, panic or taurus w/out modifying the device code.

If you prefer to do an asynchronous checking of the permit, just replace the AttributeProxy by a TaurusAttribute, CachedAttributeProxy or whatever asynchronous api you prefer.

Sergi Rubio




Keep on dancing,

http://www.tango-controls.org/resources/howto/how-fandango/
Edited 7 years ago
Andy
I heard about a generic Facade device server from MAXIV yesterday which could maybe be adapted to do this.
Andy

Hello Andy,

I have came across two GitHub projects on Facade pattern by MAXIV as below:
    - dev-maxiv-llrffacade (LLRF Facade device server. It's a simple device server with dynamic attributes and some specific syntax to be used.)

Is it the one you were referring to? Or can you help me to point the generic Facade device server which you quoted in the post. I have searched the Device Server Catalogue, but couldn't find it. I am interested in the generic Facade device server and would like to play with it.

Kind regards,
Jyotin

"All the great things are simple, and many can be expressed in a single word: freedom, justice, honor, duty, mercy, hope." - Winston Churchill
Hi Jyotin,

the one I was referring to is the second one you mention i.e. https://github.com/MaxIV-KitsControls/lib-maxiv-facadedevice

The expert is Vincent.

Andy
Andy
Hi Jyotin,

the one I was referring to is the second one you mention i.e. https://github.com/MaxIV-KitsControls/lib-maxiv-facadedevice

The expert is Vincent.

Andy

Thanks Andy. I will contact Vincent, in case I need further help.
Cheers!

Jyotin
Thanks Andy, Sergi and Jyotin for your answers!

My example might not have been the best. We use hardware interlocks for the things related to safety.
The real use case is not safety relevant.

(1) from Andy sounds like my use case. The facade server looks interesting, altough I would have to "adapt" it as the project is C++ only.

While thinking about this some more what I really would need is something like the "Allowed State machine" in pogo, only for multiple devices. Unfortunately this would be overkill to implement for my use case, so I gotta write it manually.

Tanks a lot again!

Thomas
Once you select the state machine in Pogo it will generate the "is_$Command_allowed" and "is_$Attribute_allowed methods", that you can later modify to add a check for an external attribute. It would provide your desired behavior in just 1-2 lines of code.

Using the facade approach is also possible as you can put the interlock logics in a boolean attribute of a python device and just read the boolean attribute from your C++ device.

Another approach is having an "Enable" boolean RW attribute within your C++ device and then having an independent device (facade, alarm, …) checking the conditions and updating the permit. While commissioning, permits and logics may be adjusted and sometimes is useful to have it apart of your device to not have to recompile for each change.

Sergi
Keep on dancing,

http://www.tango-controls.org/resources/howto/how-fandango/
sergi_rubio
Hi Thomas,

As Andy said, this device interaction can be understood either as an interlock (one device stopping another one) or as a permit (a device is not allowed to do something if a pre-condition is not matched).

At Alba we normally use PLC's for interlocks; having few exceptions on interlocks triggered by Panic alarms. So the disabling of an ongoing action is always managed by a separate device (Tango or HW).

In the case of permits (e.g. enabling filling or orbit correction), we define a set of panic alarms and then we check the value of the alarm attribute before executing the target action. But this check is normally done at GUI's level or by some intermediate device (Composer or Façade) not in the target device itself.

If I had to implement this "precondition" behavior from scratch in an "standard" way, then I would have followed this approach:

* e.g. we have a device with an OpenValve() command that should be allowed only if a/b/c/Pressure has a valid value

* I would create an OpenValve_allowed property in Jive with the precondition:

OpenValve_allowed = a/b/c/Pressure

* Then, check it in the is_OpenValve_allowed method of the device:

  def is_OpenValve_allowed(self,req_type):
    permit = AttributeProxy(self.OpenValve_allowed).read()
    if permit.quality != ATTR_VALID:
      return False
    else:
      return True


The same approach can be used for enabling/desabling an attribute using the is_{attribute}_allowed method. Using the permit quality for enabling/disabling the action would allow to easily tune the permits from jive, panic or taurus w/out modifying the device code.

If you prefer to do an asynchronous checking of the permit, just replace the AttributeProxy by a TaurusAttribute, CachedAttributeProxy or whatever asynchronous api you prefer.

Sergi Rubio

@Sergio This is exactly what we needed in our configuration of devices as well (to prevent device collisions) as we do not yet have a PLC or such for this purpose. I was just wondering if you could direct me on how to edit the specific device method in Jive for just one device as you have done with those lines of code with permit. Adding a device property such as OpenValve_allowed seems straightforward enough by going to the specific device in the Jive tree and 'Add Property' in the Properties tab, but cannot find the device methods.

Thanks in advance,
Jadyn
Hi Jadyn,

In case you generate the code for your devices using Pogo, the template wizard has an option called "State Machine" in which you can define which methods are allowed for each state. In this way you can disable OpenValve if the state is ALARM or MOVING for example.

In case you are using PythonHL or you have your device already written, I think that you can freely add a boolean method called "is_<YourAttributeOrCommandName>_allowed" and Tango will use that method to control whether the access to the attribute/command is allowed or not. The req_type argument is used to differentiate a read or write request.

I don't use PythonHL myself but as far as I remember it works. But in case it doesn't behave as you want, you can also pass a custom method to deal with the is_…_allowed behavior. You can do that as an argument when using @attribute or calling the add_attribute method:

https://pytango.readthedocs.io/en/stable/server_api/device.html#tango.LatestDeviceImpl.add_attribute

https://pytango.readthedocs.io/en/stable/server_api/server.html#tango.server.Device.add_attribute
Keep on dancing,

http://www.tango-controls.org/resources/howto/how-fandango/
 
Register or login to create to post a reply.