docs.unity3d.com
    Warning

    Warning: Unity Simulation is deprecated as of December 2023, and is no longer available.

    Communicating with external processes

    In the previous section you installed Simulation-Foundation and Simulation-ROS-Integrations packages. This section helps you set up the communication between Unity and ROS using those packages.

    Simulation-Foundation is the interfaces needed to communicate with an external process or service. (Herein, we will use "service" to mean any external process, service, or similar.) These interfaces are agnostic and can be implemented for ROS, GRPC etc.

    Simulation-ROS-Integrations is an implementation of those interfaces needed to communicate with ROS.

    In this section we discuss the components/interface we use to communicate with an external service.

    Interface/BaseClass Function
    BaseConnectionComponent BaseConnectionComponent is a MonoBehaviour class to configure and instantiate communication with the external service. It exposes the IConnector settings to the user via Inspector settings. It will then instantiate an IConnector instance at runtime.
    IConnector The IConnector interface is used to establish communication with the external service and then handle all communication with that service.

    An IConnector class implements methods to:

    1. Create or get an IPublisher used to publish messages to a topic to be read by an external service.

    2. Subscribe a callback to read messages from a topic sent by an external service.

    3. Implement a listener to handle service requests.

    4. Create a service client to send requests to a service.
    IPublisher The IPublisher interface is used to publish messages to a topic to be read by an external service.
    IServiceClient The IServiceClient interface is used to send service requests to an external application and receive a corresponding response.

    Adding a BaseConnectionComponent

    First we add a BaseConnectionComponent to the Unity scene.

    RosEndpointConnectorComponent is a derived class of BaseConnectionComponent. Add this component to the scene to communicate with ROS. RosEndpointConnectorComponent is contained in Simulation-ROS-Integrations.

    1. Create an empty GameObject in the scene. Rename it RosEndpointConnector.
    2. Click on Add Component in the inspector window and type the name ROS Endpoint Connector Component.
    3. Add the RosEndpointConnectorComponent from the list.
    4. Set the Endpoint IP address and Endpoint Port to the IP address and port of the machine running ROS.
    5. Make sure Connect On Start is checked.

    1366

    Getting a Reference to the IConnector Interface in Your Script

    Now you have a RosEndpointConnectorComponent in your scene. We can use it to get a reference to the IConnector interface to send and receive messages to ROS. There are two methods to get a reference to IConnector interface.

    Using RosEndpointConnector

    The RosEndpointConnectorComponent contains the reference to the IConnector interface. If you know which GameObject contains the RosEndpointConnectorComponent (RosEndpointConnector, from above), you can follow these steps to get the IConnector instance.

    1. Use the GetComponent API to get the RosEndpointConnectorComponent.
    2. Use GetConnector API to get the IConnector interface.

    The following code block illustrates this method.

    public class NewScript : MonoBehaviour
    {
      GameObject rosGameObject;
      RosEndpointConnectorComponent rosComponent;
      IConnector rosConnector;
      void Start()
      {
        rosComponent = rosGameObject.GetComponent<RosEndpointConnectorComponent>();
        var rosConnector = rosComponent.GetConnector();
      }
    }
    

    Note that, while this works fine, it is not the recommended way to fetch a reference to the Connector as it tightly couples your script to that specific Connector instance. Instead, consider using the ConnectorInjector interface.

    Using ConnectorInjector

    FindConnector

    The ConnectorInjector class in Simulation-Foundation makes it easier to get the IConnector interface from any script in the project. Use the FindConnector API in ConnectorInjector to get the IConnector. You pass a GameObject or MonoBehaviour to the FindConnector API. It searches down, and then up the GameObject tree hierarchy, looking for a BaseConnectionComponent component and returns its IConnector interface.

    If a BaseConnectionComponent cannot be found in the GameObject tree hierarchy, it returns the default IConnector from the default BaseConnectionComponent.

    Here is a code block on how to use ConnectorInjector from any MonoBehaviour.

    var myConnector = ConnectorInjector.FindConnector(this);
    

    Multiple Connectors

    FindConnector will respond dynamically to the composition of your scene. If you want to change the Connector a specific GameObject in the scene is using, simply add a new Connector to that GameObject's hierarchy. You may use a ProxyConnector to point your Object at a specific Connector not in the Object's hierarchy, or create a Connector per Object. The only restriction is that no two Connectors should contain the same connection information (e.g. you cannot create two RosEndpointConnectors that both connect to the exact same IP:Port). If you need that functionality, use the ProxyConnector to bind both objects to the shared connection.

    Using ConnectorInjector.GetDefaultConnector

    The ConnectorInjector class provides the GetDefaultConnector API to return the default IConnector. It will search the scene for the all BaseConnectionComponent components and return the first one found.

    The default IConnector can also be set with SetDefaultConnector: SetDefaultConnector(IConnector connection) SetDefaultConnector(BaseConnectionComponent connection)

    var rosConnector = ConnectorInjector.GetDefaultConnector();
    

    Sending and Receiving Messages Using the IPublisher Interface and Subscribe Method

    Now that you have an IConnector interface, you can send and receive messages. IConnector provides APIs to register a publisher or subscriber to a specific topic.

    Subscribing to Messages from an External Service

    IConnector provides the Subscribe API to subscribe to a topic.

    In this example, we subscribe to a topic called RobotPose with the message type Pose. Whenever the IConnector receives a message, it passes the message to the PoseCallback callback function.

    void PoseCallback(PoseMsg message){}
    
    void Update()
    {
      // Option 1
      rosConnector.Subscribe<PoseMsg>("RobotPose", PoseCallback);
    
      // Option 2
      rosConnector.Subscribe("RobotPose", PoseMsg.MessageTypeName, PoseCallback);
    }
    

    Publishing Messages to an External Service

    IConnector provides the RegisterPublisher API to create or get an IPublisher interface to publish to a topic. The IPublisher interface provides the Publish API to publish a message.

    In this example, we publish a PoseMsg to the RobotPose topic.

    // Registering the IPublisher
    
    // Option 1
    IPublisher posePublisher = rosConnector.RegisterPublisher<PoseMsg>("RobotPose")
    
    // Option 2
    IPublisher posePublisher = rosConnector.RegisterPublisher("RobotPose",PoseMsg.MessageTypeName)
    
    
    
    // Publish a Message
    PoseMsg sampleMsg = new PoseMsg();
    posePublisher.Publish(sampleMsg);
    

    Sending and Receiving Service Requests and Response Using the ImplementService Method and IServiceClient Interface

    Hosting a Service in Unity

    IConnector provides the ImplementService API to host a service in Unity. It receives an IMessage type request and responds with another IMessage type.

    In this example, we implement a service named "exampleService" that receives a TransformMsg request and responds with a PoseMsg.

    // Creating a service in Unity
    
    // Option 1
    IConnector exampleConnector = ConnectorInjector.FindConnector(gameObject);
    exampleConnector.ImplementService<TransformMsg,PoseMsg>("exampleServicde",exampleFunction);
    
    // Option 2
    exampleConnector.ImplementService("exampleService", TransformMsg.k_MessageTypeId, PoseMsg.k_MessageTypeId, exampleFunction);
    
    PoseMsg exampleFunction(TransformMsg arg1)
    {
      return new PoseMsg();
    }
    

    Creating a Service Client in Unity

    IConnector provides the RegisterServiceClient API to create a service client in Unity. It returns an IServiceClient interface. You can use its SendRequest API to send an IMessage request to a service and receive the IMessage response.

    In this example, we create a client to a service named "exampleService". We send a TransformMsg request to this service and receive a PoseMsg response.

    IConnector exampleConnector = ConnectorInjector.FindConnector(gameObject);
    IServiceClient serviceClient = exampleConnector.RegisterServiceClient<TransformMsg,PoseMsg>("exampleService");
    exampleConnector.RegisterServiceClient("exampleService", TransformMsg.k_MessageTypeId, PoseMsg.k_MessageTypeId);
    
    // Option 1
    serviceClient.SendRequest<TransformMsg, PoseMsg>(new TransformMsg(), exampleCallback);
    
    // Option 2
    serviceClient.SendRequest(new TransformMsg(), exampleCallbackIMessage);
    
    // Option 3
    Task<PoseMsg> result = serviceClient.SendRequest<TransformMsg, PoseMsg>(new TransformMsg());
    PoseMsg response = result.Result;
    
    // Option 4
    Task<IMessage> result1 = serviceClient.SendRequest(new TransformMsg());
    PoseMsg response1 = (PoseMsg)result1.Result;
    
    void exampleCallback(PoseMsg msg)
    {
    
    }
    
    void exampleCallbackIMessage(IMessage msg)
    {
    
    }
    

    IPublisher/Subscribe vs IServiceClient/ImplementService

    Both IPublisher and IServiceClient will send a message to an external service.

    IPublisher will publish the message but not wait for a response.

    IServiceClient will send the request and wait for a response.


    Updated 2022-08-31T23:11:26.000Z


    Copyright © 2023 Unity Technologies
    • Legal
    • Privacy Policy
    • Cookies
    • Do Not Sell or Share My Personal Information
    • Your Privacy Choices (Cookie Settings)
    "Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
    Generated by DocFX.