code-iai / ROSIntegration

Unreal Engine Plugin to enable ROS Support
MIT License
410 stars 132 forks source link

An actor subscribed to a topic is automatically unsubscribed after about a minute #32

Closed jiwoong-choi closed 6 years ago

jiwoong-choi commented 6 years ago

First of all, thank you for sharing the great plugin.

I have slightly modified the C++ publish / subscribe examples in the Readme.md.

After setting up & build the plugin, I have created two C++ Actor classes called, Publisher and Subscriber. In UE4Editor, I have added each class to the level editor by drag & drop. Basically, the idea is that Publisher publishes a string message at each frame to the example_topic, and Subscriber listens to the example_topic and prints out what it heard to the console.

Every time I run the game in UE4Editor, everything works perfectly for the first 1 minute. However, some point after a minute, UE4Editor crashes with the following error message:

.
.
.
Subscriber listened: Message from frame 5035
Subscriber listened: Message from frame 5036
Subscriber listened: Message from frame 5037
Subscriber listened: Message from frame 5039
Subscriber listened: Message from frame 5040
Subscriber listened: Message from frame 5041
Subscriber listened: Message from frame 5042
Subscriber listened: Message from frame 5043
Subscriber listened: Message from frame 5045
Subscriber listened: Message from frame 5046
Subscriber listened: Message from frame 5047
Subscriber listened: Message from frame 5048
Subscriber listened: Message from frame 5049
Subscriber listened: Message from frame 5051
Subscriber listened: Message from frame 5052
Subscriber listened: Message from frame 5053
Subscriber listened: Message from frame 5054
Subscriber listened: Message from frame 5056
Subscriber listened: Message from frame 5057
Subscriber listened: Message from frame 5058
Subscriber listened: Message from frame 5059
Subscriber listened: Message from frame 5060
[ROSBridge] Found CB in UnregisterTopicCallback. Deleting it ... 
[ROSTopic] No callbacks registered anymore - unsubscribe from topic
Signal 11 caught.
Malloc Size=131076 LargeMemoryPoolOffset=131092 
CommonLinuxCrashHandler: Signal=11
Malloc Size=65535 LargeMemoryPoolOffset=196655 
[2018.05.25-09.27.55:775][937]LogLinux: === Critical error: ===
Unhandled Exception: SIGSEGV: invalid attempt to read memory at address 0x00000000e30800a0

[2018.05.25-09.27.55:775][937]LogLinux: Fatal error!

0x00007f9cd4b6a625 FLinuxPlatformStackWalk::CaptureStackBackTrace(unsigned long long*, unsigned int, void*)
0x00007f9cd4a18c75 FGenericPlatformStackWalk::StackWalkAndDump(char*, unsigned long, int, void*)
0x00007f9cd4b1b231 FLinuxCrashContext::CaptureStackTrace()
0x00007f9cca344400 CommonLinuxCrashHandler(FGenericCrashContext const&)
0x00007f9cd4b1d2bd PlatformCrashHandler(int, siginfo_t*, void*)
0x00007f9cd5781390 /lib/x86_64-linux-gnu/libpthread.so.0(+0x11390) [0x7f9cd5781390]
0x00007f9bc6cc3efe rosbridge2cpp::ROSTopic::GeneratePublishID()
0x00007f9bc6cc3048 rosbridge2cpp::ROSTopic::Publish(_bson_t*)
0x00007f9bc6cd7f18 UTopic::Impl::Publish(TSharedPtr<FROSBaseMsg, (ESPMode)0>)
0x00007f9bc6cc98b3 UTopic::Publish(TSharedPtr<FROSBaseMsg, (ESPMode)0>)
0x00007f9bb5d2da58 APublisher::Publish(char const*)
0x00007f9bb5d2d81d APublisher::Tick(float)
0x00007f9cd1243983 FActorTickFunction::ExecuteTick(float, ELevelTick, ENamedThreads::Type, TRefCountPtr<FGraphEvent> const&)
0x00007f9cd25efab6 FTickFunctionTask::DoTask(ENamedThreads::Type, TRefCountPtr<FGraphEvent> const&)
0x00007f9cd25ef41f TGraphTask<FTickFunctionTask>::ExecuteTask(TArray<FBaseGraphTask*, FDefaultAllocator>&, ENamedThreads::Type)
0x00007f9cd4a4443f FNamedTaskThread::ProcessTasksNamedThread(int, bool)
0x00007f9cd4a43903 FNamedTaskThread::ProcessTasksUntilQuit(int)
0x00007f9cd25e9813 FTickTaskSequencer::ReleaseTickGroup(ETickingGroup, bool)
0x00007f9cd25e2694 FTickTaskManager::RunTickGroup(ETickingGroup, bool)
0x00007f9cd1c2635f UWorld::RunTickGroup(ETickingGroup, bool)
0x00007f9cd1c303ee UWorld::Tick(ELevelTick, float)
0x00007f9ccb4888a2 UEditorEngine::Tick(float, bool)
0x00007f9ccbeb93e6 UUnrealEdEngine::Tick(float, bool)
0x00000000004255f3 FEngineLoop::Tick() [/home/jchoi/UnrealEngine/Engine/Source/Runtime/Launch/Private/LaunchEngineLoop.cpp:3339]
0x000000000042fed3 GuardedMain(wchar_t const*) [/home/jchoi/UnrealEngine/Engine/Source/Runtime/Launch/Private/Launch.cpp:62]
0x00007f9cca345227 CommonLinuxMain(int, char**, int (*)(wchar_t const*))
0x00007f9cc9d90830 /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0) [0x7f9cc9d90830]
0x00000000004169c9 /home/jchoi/UnrealEngine/Engine/Binaries/Linux/UE4Editor(_start+0x29) [0x4169c9]

[2018.05.25-09.27.55:785][937]LogExit: Executing StaticShutdownAfterError
Malloc Size=772626 LargeMemoryPoolOffset=969298 
LogPlatformFile: Not using cached read wrapper
LogInit: Display: RandInit(1644944209) SRandInit(1644944209).
LogTaskGraph: Started task graph with 4 named threads and 7 total threads with 1 sets of task threads.
LogInit: Build: ++UE4+Release-4.19-CL-0
LogInit: Engine Version: 4.19.2-0+++UE4+Release-4.19
LogInit: Compatible Engine Version: 4.19.0-0+++UE4+Release-4.19
LogInit: Net CL: 0
LogInit: Compiled (64-bit): May 10 2018 13:38:33
LogInit: Compiled with Clang: 3.8.0 (tags/RELEASE_380/final)
LogInit: Build Configuration: Shipping
LogInit: Branch Name: ++UE4+Release-4.19
LogInit: Command Line:  -Abslog=/home/jchoi/Documents/Unreal Projects/ROSIntegrationTest/Saved/Logs/ROSIntegrationTest-CRC.log /home/jchoi/Documents/Unreal Projects/ROSIntegrationTest/Saved/Crashes/crashinfo-ROSIntegrationTest-pid-26649-13C1CCC037051219001B0312620BBC7F/
LogInit: Base Directory: /home/jchoi/UnrealEngine/Engine/Binaries/Linux/
LogInit: Installed Engine Build: 1
LogInit: Presizing for max 100000 objects, including 0 objects not considered by GC, pre-allocating 0 bytes for permanent pool.
LogInit: Object subsystem initialized
[2018.05.25-09.27.55:863][  0]LogInit: Linux hardware info:
[2018.05.25-09.27.55:863][  0]LogInit:  - we are the first instance of this executable
[2018.05.25-09.27.55:863][  0]LogInit:  - this process' id (pid) is 5484, parent process' id (ppid) is 26649
[2018.05.25-09.27.55:863][  0]LogInit:  - we are not running under debugger
[2018.05.25-09.27.55:863][  0]LogInit:  - machine network name is 'jchoi-desktop'
[2018.05.25-09.27.55:863][  0]LogInit:  - user name is 'jchoi' (jchoi)
[2018.05.25-09.27.55:863][  0]LogInit:  - we're logged in locally
[2018.05.25-09.27.55:863][  0]LogInit:  - we're running with rendering
[2018.05.25-09.27.55:863][  0]LogInit:  - CPU: GenuineIntel 'Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz' (signature: 0x906E9)
[2018.05.25-09.27.55:863][  0]LogInit:  - Number of physical cores available for the process: 4
[2018.05.25-09.27.55:863][  0]LogInit:  - Number of logical cores available for the process: 8
[2018.05.25-09.27.55:863][  0]LogInit:  - Cache line size: 64
[2018.05.25-09.27.55:863][  0]LogInit:  - Memory allocator used: binned2
[2018.05.25-09.27.55:863][  0]LogLinux: Skipped benchmarking clocks because the engine is running in a standalone program mode - CLOCK_REALTIME will be used.
[2018.05.25-09.27.55:863][  0]LogInit: Linux-specific commandline switches:
[2018.05.25-09.27.55:863][  0]LogInit:  -nodwarf (currently OFF): suppress parsing of DWARF debug info (callstacks will be generated faster, but won't have line numbers)
[2018.05.25-09.27.55:863][  0]LogInit:  -ansimalloc - use malloc()/free() from libc (useful for tools like valgrind and electric fence)
[2018.05.25-09.27.55:863][  0]LogInit:  -jemalloc - use jemalloc for all memory allocation
[2018.05.25-09.27.55:863][  0]LogInit:  -binnedmalloc - use binned malloc  for all memory allocation
[2018.05.25-09.27.55:863][  0]LogInit:  -httpproxy=ADDRESS:PORT - redirects HTTP requests to a proxy (only supported if compiled with libcurl)
[2018.05.25-09.27.55:863][  0]LogInit:  -reuseconn - allow libcurl to reuse HTTP connections (only matters if compiled with libcurl)
[2018.05.25-09.27.55:863][  0]LogInit:  -virtmemkb=NUMBER - sets process virtual memory (address space) limit (overrides VirtualMemoryLimitInKB value from .ini)
[2018.05.25-09.27.55:863][  0]LogInit:  - Physical RAM available (not considering process quota): 16 GB (16004 MB, 16388412 KB, 16781733888 bytes)
[2018.05.25-09.27.55:864][  0]LogUObjectArray: 149 objects as part of root set at end of initial load.
[2018.05.25-09.27.55:864][  0]LogUObjectAllocator: 22184 out of 0 bytes used by permanent object pool.
[2018.05.25-09.27.55:864][  0]LogUObjectArray: CloseDisregardForGC: 0/0 objects in disregard for GC pool
[2018.05.25-09.27.55:864][  0]LogInit: Using OS detected language ().
[2018.05.25-09.27.55:864][  0]LogInit: Using OS detected locale ().
[2018.05.25-09.27.55:864][  0]LogTextLocalizationManager: No localization for '' exists, so 'en' will be used for the language.
[2018.05.25-09.27.55:864][  0]LogTextLocalizationManager: No localization for '' exists, so 'en' will be used for the locale.
[2018.05.25-09.27.55:866][  0]CrashReportClientLog: CrashReportClientVersion=1.0
[2018.05.25-09.27.55:866][  0]CrashReportClientLog: CrashReportReceiver disabled
[2018.05.25-09.27.55:866][  0]CrashReportClientLog: DataRouterUrl: https://datarouter.ol.epicgames.com/datarouter/api/v1/public/data
[2018.05.25-09.27.55:866][  0]LogExit: Preparing to exit.
[2018.05.25-09.27.55:866][  0]LogExit: Object subsystem successfully closed.
[2018.05.25-09.27.55:867][  0]LogModuleManager: Shutting down and abandoning module CoreUObject (4)
[2018.05.25-09.27.55:867][  0]LogModuleManager: Shutting down and abandoning module SandboxFile (2)
[2018.05.25-09.27.55:867][  0]LogExit: Exiting.
Engine crash handling finished; re-raising signal 11 for the default handler. Good bye.

The crash occurs at different frame number every time I try.

I was able to prevent UE4Editor from crashing by setting

bPublish = false;

in the Publisher.h below. (i.e. by not publishing any message) But I still get the following message

[ROSBridge] Found CB in UnregisterTopicCallback. Deleting it ... 
[ROSTopic] No callbacks registered anymore - unsubscribe from topic

I've never called ROSBridge::UnregisterTopicCallback in my code, but somehow it is called and causes the Subscriber to unsubscribe from the topic. So I tried to modify some parts of the plugin code, but it didn't go anywhere.

I've been fighting with this more than 6 hours but have no idea to fix it. Please help me!

Here are my codes.

Publisher.h:

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Publisher.generated.h"

UCLASS()
class ROSINTEGRATIONTEST_API APublisher : public AActor
{
    GENERATED_BODY()

public: 
    // Sets default values for this actor's properties
    APublisher();

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

public: 
    // Called every frame
    virtual void Tick(float DeltaTime) override;

    class UTopic *ExampleTopic;

    void Publish(const char* Content);

    int nFrames;
    bool bPublish = true;
};

Publisher.cpp:

// Fill out your copyright notice in the Description page of Project Settings.

#include "Publisher.h"
#include "ROSIntegration/Classes/RI/Topic.h"
#include "ROSIntegration/Classes/ROSIntegrationGameInstance.h"
#include "ROSIntegration/Public/std_msgs/String.h"

#include <sstream>

// Sets default values
APublisher::APublisher()
{
    // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void APublisher::BeginPlay()
{
    Super::BeginPlay();

    ExampleTopic = NewObject<UTopic>(UTopic::StaticClass());
    UROSIntegrationGameInstance* rosinst = Cast<UROSIntegrationGameInstance>(GetGameInstance());
    ExampleTopic->Init(rosinst->ROSIntegrationCore, TEXT("/example_topic"), TEXT("std_msgs/String"));
}

// Called every frame
void APublisher::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    nFrames++;
    if(bPublish)
    {
        std::ostringstream oss;
        oss << "Message from frame " << nFrames;
        Publish(oss.str().c_str());
    }
}

void APublisher::Publish(const char *Content)
{
    TSharedPtr<ROSMessages::std_msgs::String> StringMessage(new ROSMessages::std_msgs::String(Content));
    ExampleTopic->Publish(StringMessage);
}

Subscriber.h:

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Subscriber.generated.h"

UCLASS()
class ROSINTEGRATIONTEST_API ASubscriber : public AActor
{
    GENERATED_BODY()

public: 
    // Sets default values for this actor's properties
    ASubscriber();

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

public: 
    // Called every frame
    virtual void Tick(float DeltaTime) override;

    class UTopic *ExampleTopic;

    static void SubscribeCallbackImpl(TSharedPtr<class FROSBaseMsg> msg);
};

Subscriber.cpp:

// Fill out your copyright notice in the Description page of Project Settings.

#include "Subscriber.h"
#include "ROSIntegration/Classes/RI/Topic.h"
#include "ROSIntegration/Classes/ROSIntegrationGameInstance.h"
#include "ROSIntegration/Public/std_msgs/String.h"

#include <iostream>

// Sets default values
ASubscriber::ASubscriber()
{
    // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void ASubscriber::BeginPlay()
{
    Super::BeginPlay();

    ExampleTopic = NewObject<UTopic>(UTopic::StaticClass());
    UROSIntegrationGameInstance* rosinst = Cast<UROSIntegrationGameInstance>(GetGameInstance());
    ExampleTopic->Init(rosinst->ROSIntegrationCore, TEXT("/example_topic"), TEXT("std_msgs/String"));

    std::function<void(TSharedPtr<FROSBaseMsg>)> SubscribeCallback = ASubscriber::SubscribeCallbackImpl;
    ExampleTopic->Subscribe(SubscribeCallback);
}

// Called every frame
void ASubscriber::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

}

void ASubscriber::SubscribeCallbackImpl(TSharedPtr<FROSBaseMsg> msg)
{
    auto Concrete = StaticCastSharedPtr<ROSMessages::std_msgs::String>(msg);
    if (Concrete.IsValid())
    {
        std::cout << "Subscriber listened: " << TCHAR_TO_UTF8(*(Concrete->_Data)) << std::endl;
    }
    return;
}
Hemofektik commented 6 years ago

Your topics are getting garbage collected and thus unsubscribe automatically. Put UPROPERTY() before class UTopic *ExampleTopic; and it should no longer happen.

jiwoong-choi commented 6 years ago

Now it works perfectly fine. Thank you so much!

xgwang commented 4 years ago

Your topics are getting garbage collected and thus unsubscribe automatically. Put UPROPERTY() before class UTopic *ExampleTopic; and it should no longer happen.

may i know the GC rules here? why this member pointer is GCed?

thanks.