Robotics StackExchange | Archived questions

ROS TCP Connector C# Lost Publishers & Freezing

Hello there,

I am trying to set envirovment variables and then, do roslaunch ros_tcp_endpoint endpoint.launchfrom Unity. Where, i am connecting to a master selected before from a menu by click of a button, then subscribing to master for getting a live video feed and publishing some messages again on click of a button. Here is my code:

using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
using UnityEngine.SceneManagement;
using Unity.Robotics.ROSTCPConnector;
using UnityEngine.InputSystem;
using RosImage = RosMessageTypes.Sensor.CompressedImageMsg;
using ROString = RosMessageTypes.Std.StringMsg;
using RosMessageTypes.Geometry;
using UnityEngine.UI;
using TMPro;

public class SubnPub : MonoBehaviour
{

    private Process process = new Process();

    ROString directionMsg;

    ROSConnection directionPublisher;

    private Texture2D liveFeedTexture;

    public string topic = "/camera/image/compressed";
    public RawImage TheScreen;

    private bool isStopped = false;
    public TextMeshProUGUI startstopText;

    public Button upButton, downButton, leftButton, rightButton;

    // Start is called before the first frame update
    void Start()
    {

        UnityEngine.Debug.Log("Current Device IP: "+DataKeeper.currentDeviceIP);

        //In order to prevent cmd from closing and killing the running commands in the process, /k added before commands.
    private string command;

        command = "/c cd \\ && .\\my_catkin_wp\\devel\\setup.bat && set ROS_MASTER_URI=http://" + DataKeeper.currentDeviceIP + ":11311 && roslaunch ros_tcp_endpoint endpoint.launch";

        //This function will open the cmd and then, run the commands to set the ROS_MASTER_URI to ip of the selected
        // device and to launch the "ros_tcp_endpoint.launch" file to start the connection between ROS and Unity.
        SetRosEnv();

        UnityEngine.Debug.Log("Current Device IP: " + DataKeeper.currentDeviceIP);

        liveFeedTexture = new Texture2D(1832, 1920, TextureFormat.RGB8, false);

        TheScreen.texture = liveFeedTexture;

        ROSConnection.GetOrCreateInstance().Subscribe<RosImage>(topic, ChangeFeedTexture);

        UnityEngine.Debug.Log("Subscribed to the image.");
        UnityEngine.Debug.Log("Current Button is: "+startstopText.text);
        UnityEngine.Debug.Log("Is Stop button clicked :"+isStopped.ToString());

        directionPublisher = ROSConnection.GetOrCreateInstance();
        directionPublisher.RegisterPublisher<ROString>("/unity/direction");

    }

    void ChangeFeedTexture(RosImage videoFeed)
    {

        if (isStopped == false)
        {

            liveFeedTexture.LoadImage(videoFeed.data);

            //FlipTextureVertical(liveFeedTexture);

            liveFeedTexture.Apply();

        }

    }

    private void SetRosEnv()
    {
        //Creates process start info object for setting starting options
        ProcessStartInfo startInfo = new ProcessStartInfo();

        //Sets file to be opened the cmd.exe for opening the command prompt
        startInfo.FileName = "cmd.exe";

        // Set UseShellExecute to false to redirect input/output
        startInfo.UseShellExecute = false;

        //Set verb to "runas" for running as administrator
        startInfo.Verb = "runas";

        //Hide and prevent creation of cmd window
        startInfo.WindowStyle = ProcessWindowStyle.Hidden;
        startInfo.CreateNoWindow = true;

        //Redirect standard input/output/error to receive output from the ROS command
        startInfo.RedirectStandardInput = true;
        startInfo.RedirectStandardOutput = true;
        startInfo.RedirectStandardError = true;

        // Create and start the process
        process.StartInfo = startInfo;
        process.OutputDataReceived += (sender, args1) => UnityEngine.Debug.Log("Output: \n" + "\n" + args1.Data);
        process.ErrorDataReceived += (sender, args1) => UnityEngine.Debug.Log("Error: \n" + "\n" + args1.Data);
        process.Start();
        DataKeeper.currentProcessID = process.Id;
        process.BeginOutputReadLine();

        process.StandardInput.WriteLine("cd /d C:");
        process.StandardInput.WriteLine("cd \\");
        process.StandardInput.WriteLine(".\\my_catkin_wp\\devel\\setup.bat");
        process.StandardInput.WriteLine("set ROS_MASTER_URI=http://" + DataKeeper.currentDeviceIP + ":11311");
        process.StandardInput.WriteLine("roslaunch ros_tcp_endpoint endpoint.launch");

    }

    public void OnStartStopClicked()
    {

        isStopped = !isStopped;

        UnityEngine.Debug.Log("Changed to "+isStopped.ToString());

        if (isStopped == false)
        {

            UnityEngine.Debug.Log("Starting the live stream!");

            startstopText.text = "Stop";

        }

        else
        {

            UnityEngine.Debug.Log("Stopping the live stream!");

            startstopText.text = "Start";

        }

    }

    public void OnUPButton()
    {

        directionMsg = new ROString("forward");
        directionPublisher.Publish("/unity/direction", directionMsg);

    }

    public void OnDownButton()
    {

        directionMsg = new ROString("backward");
        directionPublisher.Publish("/unity/direction", directionMsg);

    }

    public void OnLeftButton()
    {

        directionMsg = new ROString("left");
        directionPublisher.Publish("/unity/direction", directionMsg);

    }

    public void OnRightButton()
    {

        directionMsg = new ROString("right");
        directionPublisher.Publish("/unity/direction", directionMsg);

    }

    public void OnExitButton()
    {

        process.OutputDataReceived += (sender, args1) => UnityEngine.Debug.Log("Output: \n" + "\n" + args1.Data);
        process.ErrorDataReceived += (sender, args1) => UnityEngine.Debug.Log("Error: \n" + "\n" + args1.Data);

        process.StandardInput.WriteLine("\x3");
        process.Kill();
        DataKeeper.currentProcessID = null;
        DataKeeper.currentDeviceIP = "";
        SceneManager.LoadScene("DevicesMenu");

    }

}

This code works and i can see the live feed. The problem with this code is after a few seconds when i run rostopic list i can't see the "/unity/direction" topic and publisher is lost.

using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
using UnityEngine.SceneManagement;
using Unity.Robotics.ROSTCPConnector;
using UnityEngine.InputSystem;
using RosImage = RosMessageTypes.Sensor.CompressedImageMsg;
using ROString = RosMessageTypes.Std.StringMsg;
using RosMessageTypes.Geometry;
using ROSPose = RosMessageTypes.Geometry.PoseMsg;
using UnityEngine.UI;
using TMPro;

public class SubnPub: MonoBehaviour
{

    private Process process = new Process();

    ROString directionMsg;

    ROSConnection directionPublisher;

    private Texture2D liveFeedTexture;

    public string topic = "/camera/image/compressed";
    public RawImage TheScreen;

    private bool isStopped = false;
    public TextMeshProUGUI startstopText;

    public Button upButton, downButton, leftButton, rightButton;

    // Start is called before the first frame update
    void Start()
    {

        UnityEngine.Debug.Log("Current Device IP: "+DataKeeper.currentDeviceIP);

        //In order to prevent cmd from closing and killing the running commands in the process, /k added before commands.
    private string command;

        command = "/c cd \\ && .\\my_catkin_wp\\devel\\setup.bat && set ROS_MASTER_URI=http://" + DataKeeper.currentDeviceIP + ":11311 && roslaunch ros_tcp_endpoint endpoint.launch";

        //This function will open the cmd and then, run the commands to set the ROS_MASTER_URI to ip of the selected
        // device and to launch the "ros_tcp_endpoint.launch" file to start the connection between ROS and Unity.
        SetRosEnv();

        UnityEngine.Debug.Log("Current Device IP: " + DataKeeper.currentDeviceIP);

        liveFeedTexture = new Texture2D(1832, 1920, TextureFormat.RGB8, false);

        TheScreen.texture = liveFeedTexture;

        ROSConnection.GetOrCreateInstance().Subscribe<RosImage>(topic, ChangeFeedTexture);

        UnityEngine.Debug.Log("Subscribed to the image.");
        UnityEngine.Debug.Log("Current Button is: "+startstopText.text);
        UnityEngine.Debug.Log("Is Stop button clicked :"+isStopped.ToString());

        directionPublisher = ROSConnection.GetOrCreateInstance();
        directionPublisher.RegisterPublisher<ROString>("/unity/direction");

    }

    void ChangeFeedTexture(RosImage videoFeed)
    {

        if (isStopped == false)
        {

            liveFeedTexture.LoadImage(videoFeed.data);

            //FlipTextureVertical(liveFeedTexture);

            liveFeedTexture.Apply();

        }

    }

    private void SetRosEnv()
    {
        //Creates process start info object for setting starting options
        ProcessStartInfo startInfo = new ProcessStartInfo();

        //Sets file to be opened the cmd.exe for opening the command prompt
        startInfo.FileName = "cmd.exe";

        //Starting arguements set to commands wanted to be runned
        startInfo.Arguments = command;

        // Set UseShellExecute to false to redirect input/output
        startInfo.UseShellExecute = false;

        //Set verb to "runas" for running as administrator
        startInfo.Verb = "runas";

        //Hide and prevent creation of cmd window
        startInfo.WindowStyle = ProcessWindowStyle.Hidden;
        startInfo.CreateNoWindow = true;

        //Redirect standard input/output/error to receive output from the ROS command
        startInfo.RedirectStandardInput = true;
        startInfo.RedirectStandardOutput = true;
        startInfo.RedirectStandardError = true;

        // Create and start the process
        Process process = new Process();
        process.StartInfo = startInfo;
        UnityEngine.Debug.Log("Commands to be run: \n" + process.StartInfo.Arguments);
        process.Start();

        //process.WaitForExit();

        UnityEngine.Debug.Log("OUTPUT: \n\n" + process.StandardOutput.ReadToEnd());
        UnityEngine.Debug.Log("OUTPUT: \n\n" + process.StandardOutput.ReadToEnd());

    }

    public void OnStartStopClicked()
    {

        isStopped = !isStopped;

        UnityEngine.Debug.Log("Changed to "+isStopped.ToString());

        if (isStopped == false)
        {

            UnityEngine.Debug.Log("Starting the live stream!");

            startstopText.text = "Stop";

        }

        else
        {

            UnityEngine.Debug.Log("Stopping the live stream!");

            startstopText.text = "Start";

        }

    }

    public void OnUPButton()
    {

        directionMsg = new ROString("forward");
        directionPublisher.Publish("/unity/direction", directionMsg);

    }

    public void OnDownButton()
    {

        directionMsg = new ROString("backward");
        directionPublisher.Publish("/unity/direction", directionMsg);

    }

    public void OnLeftButton()
    {

        directionMsg = new ROString("left");
        directionPublisher.Publish("/unity/direction", directionMsg);

    }

    public void OnRightButton()
    {

        directionMsg = new ROString("right");
        directionPublisher.Publish("/unity/direction", directionMsg);

    }

    public void OnExitButton()
    {

        process.Dispose();

        DataKeeper.currentDeviceIP = "";
        SceneManager.LoadScene("DevicesMenu");

    }

}

The problem is the process in this code doesn't exits and can't get to see the live feed.

I would appreciate any help, any advice,

Thanks in advance.

Asked by mericgeren on 2023-07-25 16:41:17 UTC

Comments

Answers