Skip to content

User_App_Fibonacci_Action_Client

Martin Bischoff edited this page Aug 13, 2019 · 7 revisions

Fibonacci Action Client

0. This tutorial assumes that you have completed:

1. Creating a simple client

1.1 Initialization

Create a new empty GameObject. This is where we will attach our fibonacci client script.

User_App_UnityClient_GameObject

And we shall call it with a very unoriginal name FibonacciClient.

User_App_UnityClient_Name

1.2 Creating the script to be attached to FibonacciClient GameObject

1.2.1 The code

Please take a look at the code at Assets/RosSharp/Scripts/RosBridgeClient/ActionHandling/FibonacciActionClientComponent.cs

Original can be found in our repository

1.2.2 The code explained

using System;

using UnityEngine;

using RosSharp.RosBridgeClient.Actionlib;
using RosSharp.RosBridgeClient.Protocols;
using RosSharp.RosBridgeClient.MessageTypes.ActionlibTutorials;
  • System gives you String for string manipulations and Guid for generating Goal ID
  • UnityEngine gives you access to Unity functions
  • RosSharp.RosBridgeClient.Actionlib is the action library used forimplementing simple action clients
  • RosSharp.RosBridgeClient.Protocols is used for WebSockets connection to ROS
  • RosSharp.RosBridgeClient.MessageTypes.ActionlibTutorials is where the C# classes for Fibonacci.action lives
namespace RosSharp.RosBridgeClient
{
    public class FibonacciActionClientComponent : MonoBehaviour
    {

Here we will enclose our classes in the RosBridgeClient namespace and we will have a class that extends MonoBehaviour to be executed by Unity.

        public string actionName = "fibonacci";
        public Protocol protocol = Protocol.WebSocketSharp;
        public string serverURL = "ws://192.168.137.195:9090";
        public RosSocket.SerializerEnum serializer = RosSocket.SerializerEnum.JSON;
        public int timeout = 10;
        public float timeStep = 0.2f;
        public int fibonacciOrder = 20;
  • actionName: provides rostopic name in order to communicate with ROS
  • protocol: for this example, we will use WebSocketSharp. The other option is WebSocketNET
  • serverURL: address for the action server. Starts with ws:// which stands for WebSocket, followed by ROS host machine IP and the port which RosBridge is communicating through
  • serializer: for this example, we will use JSON. The other option is BSON
  • timeout time in seconds to wait for communication with ROS. Not used in this example
  • timestep time interval in seconds for each run loop in client, which is responsible for checking action status, loop intervals, etc.
  • fibonacciOrder the length of the fibonacci sequence requested
        private FibonacciActionClient client;

An instance of our fibonacci client class (we will cover that soon)

        public string status = "";
        public string feedback = "";
        public string result = "";

We will use those public variables to show action status in inspector

        private void Awake()
        {
            FibonacciAction action = new FibonacciAction();
            action.action_goal.goal.order = fibonacciOrder;
            client = new FibonacciActionClient(action, actionName, serverURL, protocol, serializer, timeout, timeStep);
        }

When an instance of our extension to MonoBehaviour is created (Awake), we will create an instance of FibonacciActionClient (implemented later in the tutorial), and pass in a FibonacciAction instance with its action_goal set with our requested fibonacci order.

        // Start is called before the first frame update
        private void Start()
        {
            client.Start();
        }

Before the first frame update when we enter play mode (Start), start the client

        // Update is called once per frame
        private void Update()
        {
            status = client.GetStatusString();
            feedback = client.GetFeedbackString();
            result = client.GetResultString();
        }

For each frame (Update]), we will update our displayed action status from client instance.

        private void OnDestroy()
        {
            client.Stop();
        }

When Unity exits play mode (OnDestroy) we will stop the client

        public void SendGoal()
        {
            client.SendGoalFromUnity();
        }

        public void CancelGoal()
        {
            client.CancelGoalFromUnity();
        }
    }

Above methods will be bound to inspector buttons in an editor script. More on that later

    public class FibonacciActionClient : ActionClient<FibonacciAction, FibonacciActionGoal, FibonacciActionResult, FibonacciActionFeedback, FibonacciGoal, FibonacciResult, FibonacciFeedback>
    {
        public FibonacciActionClient(FibonacciAction action, string actionName, string serverURL, Protocol protocol, RosSocket.SerializerEnum serializer, int timeout, float timeStep) : base(action, actionName, serverURL, protocol, serializer, timeStep) { }

Now, onto the FibonacciActionClient where all the action takes place

FibonacciActionClient will extend RosSharp.RosBridgeClient.Actionlib.ActionClient and we will provide generic arguments <FibonacciAction, FibonacciActionGoal, FibonacciActionResult, FibonacciActionFeedback, FibonacciGoal, FibonacciResult, FibonacciFeedback> which corresponds to generated classes from Fibonacci.action to ensure type safety (aka not using random message classes and cause bad things to happen).

        protected override string GoalID()
        {
            return "fibonacci-unity-" + Guid.NewGuid();
        }

We will generate a GoalID that consists of fibonacci-unity- and a randomly generated GUID to identify the goal send from our client

        protected override void OnFeedbackReceived()
        {
            // Not implemented since get string directly returns stored feedback
        }

        protected override void OnResultReceived()
        {
            // Not implemented since get string directly returns stored result
        }

For this example, the client doesn't do anything on feedback or result received. The base ActionClient has feedback and result updated when receiving those.

        public string GetStatusString()
        {
            if (goalStatus != null) {
                return ((ActionStatus)(goalStatus.status)).ToString();
            }
            return "";
        }

        public string GetFeedbackString()
        {
            return String.Join(",", action.action_feedback.feedback.sequence);
        }

        public string GetResultString()
        {
            return String.Join(",", action.action_result.result.sequence);
        }

Those methods allow our Unity MonoBehaviour class FibonacciActionClientComponent to get status, feedback and result string from client and display those in inspector.

       public void SendGoalFromUnity()
        {
            SendGoal();
        }

        public void CancelGoalFromUnity()
        {
            CancelGoal();
        }

These methods expose protected methods to FibonacciActionClientComponent to be triggered on button click in inspector

       protected override void Log(string log)
        {
            Debug.Log("Fibonacci Action Client: " + log);
        }

        protected override void LogWarning(string log)
        {
            Debug.LogWarning("Fibonacci Action Client: " + log);
        }

        protected override void LogError(string log)
        {
            Debug.LogError("Fibonacci Action Client: " + log);
        }
    }
}

ActionClient base classes uses abstract log methods and we implement those here with Unity Debug class to be visible in Unity console and log.

1.3 The custom inspector

1.3.1 The code

Please take a look at the code at Assets/RosSharp/Scripts/RosBridgeClient/Editor/FibonacciAction/FibonacciActionClientEditor.cs

Original and be found in our repository

1.3.2 The code explained

using UnityEditor;
using UnityEngine;

UnityEditor and UnityEngine provides us with access to Unity APIs

namespace RosSharp.RosBridgeClient
{

Again, we will enclose our classes in the RosBridgeClient namespace

[CustomEditor(typeof(FibonacciActionClientComponent))]
public class FibonacciActionClientEditor : Editor
{

Here, we define a custom editor for FibonacciActionClientComponent, which is an extension of Unity Editor

public override void OnInspectorGUI()
{
    base.OnInspectorGUI();

OnInspectorGUI is responsible for managing UI elements in the inspector window. We will add our buttons here.

By calling base.OnInspectorGUI(); we will render the default elements, which are the public variables in FibonacciActionClientComponent

            if (GUILayout.Button("Send Goal"))
            {
                ((FibonacciActionClientComponent)target).SendGoal();
            }

            if (GUILayout.Button("Cancel Goal"))
            {
                ((FibonacciActionClientComponent)target).CancelGoal();
            }

The above adds the SendGoal and CancelGoal button that calls corresponding methods in FibonacciActionClientComponent

            Repaint();
        }
    }
}

Repaint to apply changes to inspector

2. Attach client script to FibonacciClient GameObject

Now since we have all the parts ready, attach FibonacciActionClientComponent to FibonacciClient GameObject by dragging the script from project browser and dropping on FibonacciClient.

Select FibonacciClient and check the inspector to see that FibonacciActionClientComponent has been attached

User_App_UnityClient_Inspector

3. RUN!

3.1 Fire up ROS Bridge

Note: This section assumes that you have ROS installed on a machine accessible from Unity machine and have file_server installed in ROS. See our wiki page for installation guide

In order to get Unity to talk to ROS, fire up RosBridgeClient by running the following in terminal

$ roslaunch rosbridge_server rosbridge_websocket.launch

Then get fibonacci server from ROS tutorial Writing a Simple Action Server using the Execute Callback running by executing the following in a separate terminal window:

$ rosrun actionlib_tutorials fibonacci_server

User_App_Actionlib_RosServer

Then, back in Unity, start play mode and click Send Goal in FibonacciClient inspector. Action status, feedback and result will be displayed once server receives the goal.

User_App_UnityClient_Inspector_Feedback

© Siemens AG, 2017-2019 Author: Sifan Ye ([email protected])

Clone this wiki locally