IMMI with ROS controls

I am trying to figure out how to use a UR15 fully controlled by ROS with an injection molding machine. To do this without ROS there is the IMMI URcap that manages the necessary Euromp67 signals, the standard for picker/press communication.

So far I haven’t figured out how to read or write to the IMMI I/O from a ROS topic/node/service so I tried using the /urscript_interface/script_command to send urscript sections of code.

​    
    def _urscript(self, script: str):
        msg = String()
        msg.data = script
        self._urscript_pub.publish(msg)

    def _set_output(self, bit: int, value: bool):
        """Set a single EM67 output via direct URScript call."""
        if not self.press_connected:
            return
        v = "True" if value else "False"
        self._urscript(f"set_euromap_output({bit}, {v})\n")

#   LATER IN PROGRAM

        # Assert all permission outputs so press can complete its cycle
        self._set_output(EM67Out.MOLD_AREA_FREE,         True)
        self._set_output(EM67Out.ENABLE_MOLD_CLOSURE,    True)
        self._set_output(EM67Out.ENABLE_FULL_MOLD_OPEN,  True)
        self._set_output(EM67Out.ENABLE_EJECTOR_FORWARD, True)
        self._set_output(EM67Out.ENABLE_EJECTOR_BACK,    True)
        self._set_output(EM67Out.ROBOT_OPERATION_MODE,   False)
        time.sleep(0.1)  # let outputs settle before press reads them

 

Also tried:


        self.get_logger().info("EM67: Startup Check — asserting all outputs")
        self._urscript(
            "set_euromap_output(8,True)\n"
            "set_euromap_output(15,True)\n"
            "set_euromap_output(1,True)\n"
            "set_euromap_output(2,True)\n"
            "set_euromap_output(9,True)\n"
            "set_euromap_output(10,True)\n"
            "set_euromap_output(11,True)\n"
            "set_euromap_output(12,True)\n"
            "set_euromap_output(13,True)\n"
            "set_euromap_output(14,True)\n"
        )

        input(
            "\n  EM67 Startup Check — all outputs asserted.\n"
            "  Verify outputs on pendant I/O → External → IMMI,\n"
            "  then press Enter to activate robot operation… "
        )

        self._urscript("set_euromap_output(8, False)\n")
        self.get_logger().info("✓ Startup Check complete — Robot Operation Mode LOW")
 

However that doesn’t seem to be working. I want to run the robot in headless mode which is the main reason I am trying to move this fully into ROS. Previously I was controlling robot movements with ROS and then nesting the External Control URCap inside the IMMI URCap template. Having to start the mold, the teach pendant and a ROS2 python program is not a user friendly set up.

For some additional context here is what the .script file shows for the first IMMI check:

​   $ 3 "Startup Check"
   set_euromap_output(8,True)
   set_euromap_output(15,True)
   set_euromap_output(1,True)
   set_euromap_output(2,True)
   set_euromap_output(9,True)
   set_euromap_output(10,True)
   set_euromap_output(11,True)
   set_euromap_output(12,True)
   set_euromap_output(13,True)
   set_euromap_output(14,True)

And I have tried sending one line at a time

​$ ros2 topic pub -t 3 /urscript_interface/script_command std_msgs/msg/String   'data: "get_euromap_input(2)"'
Waiting for at least 1 matching subscription(s)...
Waiting for at least 1 matching subscription(s)...
publisher: beginning loop
publishing #1: std_msgs.msg.String(data='get_euromap_input(2)')
publishing #2: std_msgs.msg.String(data='get_euromap_input(2)')
publishing #3: std_msgs.msg.String(data='get_euromap_input(2)')

$ ros2 topic pub -t 3 /urscript_interface/script_command std_msgs/msg/String   'data: "set_euromap_output(15, True)"'
Waiting for at least 1 matching subscription(s)...
Waiting for at least 1 matching subscription(s)...
Waiting for at least 1 matching subscription(s)...
publisher: beginning loop
publishing #1: std_msgs.msg.String(data='set_euromap_output(15, True)')
publishing #2: std_msgs.msg.String(data='set_euromap_output(15, True)')
publishing #3: std_msgs.msg.String(data='set_euromap_output(15, True)')

Any help on Euromap67/IMMI from ROS would be appreciated.

Hi,

using the script interface is probably the easiest to get that working. Things to consider there:

  • Each script line sent to the interface gets executed as its own program. If there’s a program running already, the running program will be interrupted. Therefore, publishing many individual set_euromap_output calls directly after another will not work. They will inevitably interrupt each other.
  • When sending multi-line programs, they should be wrapped into a function.

The following works for me:

import rclpy
from rclpy.node import Node
from std_msgs.msg import String


class UrscriptSenderExample(Node):
    def __init__(self):
        super().__init__("urscript_sender_example")
        self._pub = self.create_publisher(String, "urscript_interface/script_command", 10)

        self.timer = self.create_timer(1.0, self.timer_callback)
        self.i = 0

    def timer_callback(self):
        if self.i == 0:
            self.setup()
        self.i = self.i+1

    def setup(self):
        self.send_once(
            "def setup():\n"
            "  set_euromap_output(8,True)\n"
            "  set_euromap_output(15,True)\n"
            "  set_euromap_output(1,True)\n"
            "  set_euromap_output(2,True)\n"
            "  set_euromap_output(9,True)\n"
            "  set_euromap_output(10,True)\n"
            "  set_euromap_output(11,True)\n"
            "  set_euromap_output(12,True)\n"
            "  set_euromap_output(13,True)\n"
            "  set_euromap_output(14,True)\n"
            "end\n"
        )

    def send_once(self, script_code: str = None):
        msg = String(data=script_code)
        self._pub.publish(msg)
        self.get_logger().info("Published URScript snippet")


def main(args=None):
    rclpy.init(args=args)
    node = UrscriptSenderExample()
    try:
        rclpy.spin(node)
    finally:
        node.destroy_node()
        rclpy.shutdown()


if __name__ == "__main__":
    main()

That being said, I found some possible improvements for the urscript interface. I will probably add a PR to the ROS driver soon.

What ROS distribution are you working on?

Edit: The pull request for improving the script interface is here: Update urscript interface to use primary client by urfeex · Pull Request #1767 · UniversalRobots/Universal_Robots_ROS2_Driver · GitHub

I am working in Humble. Your code worked for me too, after I realized the Secondary Client was disabled. That may have been my problem all along, but knowing that the code wasn’t the issue made it an easier mistake to find.

Thanks for your assistance!