siemens / ros-sharp

ROS# is a set of open source software libraries and tools in C# for communicating with ROS from .NET applications, in particular Unity3D
Apache License 2.0
961 stars 365 forks source link

Problem when build a PC Standalone App #359

Closed flymaxty closed 3 years ago

flymaxty commented 3 years ago

I have a question!

Here is my question:

I'm trying to use Auto Generate Messages to generate custom messages. It works well when I run in Unity with Play button.

But when I build a PC Standalone Application, it returns the following error:

NullReferenceException: Object reference not set to an instance of an object
  at RosSharp.RosBridgeClient.UnityPublisher`1[T].Start () [0x0000d] in C:\Users\flyma\Workspace\unity\caster_moma_remote\Assets\RosSharp\Scripts\RosBridgeClient\RosCommuncation\UnityPublisher.cs:31 
  at RosSharp.RosBridgeClient.HeadController.Start () [0x00044] in C:\Users\flyma\Workspace\unity\caster_moma_remote\Assets\Scripts\HeadController.cs:24 

(Filename: C:/Users/flyma/Workspace/unity/caster_moma_remote/Assets/RosSharp/Scripts/RosBridgeClient/RosCommuncation/UnityPublisher.cs Line: 31)

It seems that did not find a ros connector, but I don't know why.

Here's my code

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using RosSharp.RosBridgeClient;

namespace RosSharp.RosBridgeClient
{
    [RequireComponent(typeof(RosConnector))]

    public class HeadController : UnityPublisher<MessageTypes.PanTiltMsg.PanTiltCmd>
    {
        private Camera cam;
        private MessageTypes.PanTiltMsg.PanTiltCmd message;
        private MessageTypes.PanTiltMsg.PanTiltCmd last_message;
        private float previousRealTime;        
        private Vector3 previousPosition = Vector3.zero;
        private Quaternion previousRotation = Quaternion.identity;

        protected override void Start()
        {
            message = new MessageTypes.PanTiltMsg.PanTiltCmd(0.0f, 0.0f, 30);
            last_message = new MessageTypes.PanTiltMsg.PanTiltCmd(0.0f, 0.0f, 30);
            cam = GameObject.Find("VRCamera").GetComponent<Camera>();
            base.Start();
        }

        private void FixedUpdate()
        {
            UpdateMessage();
        }

        private UnityEngine.Vector3 GetEuler(UnityEngine.Quaternion q)
        {
            float r11 = -2.0f*(q.y*q.z - q.w*q.x);
            float r12 = q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z;
            float r21 = 2.0f*(q.x*q.z + q.w*q.y);
            float r31 = -2.0f*(q.x*q.y - q.w*q.z);
            float r32 = q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z;

            UnityEngine.Vector3 ret = new  UnityEngine.Vector3();
            ret.z = Mathf.Atan2(r31, r32);
            ret.y = Mathf.Asin (r21);
            ret.x = Mathf.Atan2(r11, r12);

            return ret;
        }

        private void UpdateMessage()
        {
            // float deltaTime = Time.realtimeSinceStartup - previousRealTime;

            // Vector3 linearVelocity = (PublishedTransform.position - previousPosition)/deltaTime;
            // Vector3 angularVelocity = (PublishedTransform.rotation.eulerAngles - previousRotation.eulerAngles)/deltaTime;

            // message.linear = GetGeometryVector3(linearVelocity.Unity2Ros()); ;
            // message.angular = GetGeometryVector3(- angularVelocity.Unity2Ros());

            // previousRealTime = Time.realtimeSinceStartup;
            // previousPosition = PublishedTransform.position;
            // previousRotation = PublishedTransform.rotation;

            Debug.Log("Position:" + cam.transform.position + ", Rotation:" + GetEuler(cam.transform.rotation));

            message.yaw = -Mathf.Rad2Deg * GetEuler(cam.transform.rotation).y;
            message.pitch = Mathf.Rad2Deg * GetEuler(cam.transform.rotation).x;

            if(message.yaw > 50) message.yaw = 50;
            if(message.yaw < -50) message.yaw = -50;
            if(message.pitch > 50) message.pitch = 50;
            if(message.pitch < -50) message.pitch = -50;

            if(Mathf.Abs(message.pitch-last_message.pitch) > 5 || Mathf.Abs(message.yaw-last_message.yaw) > 5) {
                last_message.yaw = message.yaw;
                last_message.pitch = message.pitch;

                Debug.Log("aaa"+message);
                Publish(message);
            }
        }
    }
}

I'm using Unity 2019.4.13f1c1 with steamvr and latest ros_sharp from repo.

MartinBischoff commented 3 years ago

Hi @flymaxty !

all your custom messages seem to work fine. The error above is thrown in line 31 of the UnityPublisher base class:

publicationId = rosConnector.RosSocket.Advertise<T>(Topic);

where rosConnector is null. It should have been assigned to a non-null value directly above in line 30. Did you put your HeadController Component in the same GameObject where your RosConnector is in?

I don't understand why this error happens on PC Standalone build only. Do you have any other scripts that might disable or remove your RosConnector? Make sure that all required runtime scripts are included in the build, e.g. dont' put them in folders named Editor.

This might help you debugging: https://assetstore.unity.com/packages/tools/integration/log-viewer-12047 (I didn't test it myself yet, though.)

Best, Martin

flymaxty commented 3 years ago

Hi @MartinBischoff , Thanks for your reply!

Did you put your HeadController Component in the same GameObject where your RosConnector is in? Yes

Do you have any other scripts that might disable or remove your RosConnector? No, but has multiple rosconnector in different GameObject

Make sure that all required runtime scripts are included in the build, e.g. dont' put them in folders named Editor. Yes, I'm sure.

There are also other subscribers in differect GameObject, receiving image and joint_states. All subscriber works well, except this one, which publish message to ROS.

I also tried to rebuild the Libraries on my PC, replace RosBridgeClient.dll, and the result is same.

MartinBischoff commented 3 years ago

Hi @flymaxty

a RosConnector is intended to be used once per scene with all Publishers and Subscribers located in the same GameObject. Why are you using several RosConnectors? Each of them sets up a separate Websocket connection. Does your build work when you disable all but one?

A RosConnector creates a new thread to communicate with ROS asynchronously to Unity's (fixed) update processes. Depending on your machine and cpu load, another reason for above error might be that the thread is not initialized in time. Nevertheless the RosConnector should be non-null?! Can you Debug.Log the relevant objects RosConnector, RosSocket to clarify what is null when it should not be?

MartinBischoff commented 3 years ago

Hi @flymaxty did my suggestions help? Please close this issue if it is resolved.

flymaxty commented 3 years ago

Hi @MartinBischoff , Sorry for the late reply, I was in a hard time to catch up with the project schedule, and forgot this issue after everythings done.

I recreate a new unity project and follow your suggest to create only one RosConnector per scene, and the issue was solved.

I'm not sure which is the key reason, but yes, I use RosConnector in wrong way.

I'll close this issue and thanks for your help!