ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
0

Access from C, C++ ROS publisher variable

asked 2023-03-19 05:35:04 -0500

jjrbfi gravatar image

Hello, Hope you are well!

I have a C program from which I want to read the values received by a topic. So, I want to extend the actual program capabilities reading from a C++ (ROS) variable, to do actions. The main problem is that I can’t figure out why I can’t read the value from C using 'extern "C"'...

I tried to use Linux sockets, but seems to be slow for the task. Same with FIFO (Very SLOW)… For that reason I was thinking to read the value directly from a shared variable… ( Probably you have another ideas? :) )

publisher.cpp

#include "ros/ros.h"
#include "std_msgs/String.h"
#include "shared_ros_variable.h"

char* ros_value;

void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO("I heard: [%s]", msg->data.c_str());
  ros_value = const_cast<char*>(msg->data.c_str());
  //ROS_INFO("I heard: [%s]", ros_value);
}
// %EndTag(CALLBACK)%

int main(int argc, char **argv)
{
  ros::init(argc, argv, "listener");
  ros::NodeHandle n;

// %Tag(SUBSCRIBER)%
  ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
// %EndTag(SUBSCRIBER)%

// %Tag(SPIN)%
  ros::spin();
// %EndTag(SPIN)%

  return 0;
}
// %EndTag(FULLTEXT)%

shared_ros_variable.h

#ifndef SHARED_ROS_VARIABLE_H
#define SHARED_ROS_VARIABLE_H

#ifdef __cplusplus
extern "C" {
#endif

extern char* ros_value;

#ifdef __cplusplus
}
#endif

#endif // SHARED_ROS_VARIABLE

val_reader.c

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include "shared_ros_variable.h"

char* ros_value;

int main() {
    // Load the shared library
    void* handle = dlopen("build/liblistener_lib.so", RTLD_LAZY);
    if (!handle) {
        printf("Failed to load shared library: %s\n", dlerror());
        exit(1);
    }

    // Get a pointer to the char variable
    char* my_char_ptr = dlsym(handle, "ros_value");
    if (!my_char_ptr) {
        printf("Failed to get symbol: %s\n", dlerror());
        dlclose(handle);
        exit(1);
    }

    // Print the value of the char variable
    printf("Value of my_char_variable: %c\n", *my_char_ptr);

    // Close the shared library
    dlclose(handle);
    return 0;
}

shared_ros_variable.h

#ifndef SHARED_ROS_VARIABLE_H
#define SHARED_ROS_VARIABLE_H

#ifdef __cplusplus
extern "C" {
#endif

extern char* ros_value; // declaration of the variable from halcmd_main.c

#ifdef __cplusplus
}
#endif

#endif // SHARED_ROS_VARIABLE

CMakeLists.txt

cmake_minimum_required(VERSION 2.8.3)
project(myproject)

# Find the required ROS packages
find_package(roscpp REQUIRED)
find_package(std_msgs REQUIRED)

# Add the include directories for the ROS packages
include_directories(${roscpp_INCLUDE_DIRS})
include_directories(${std_msgs_INCLUDE_DIRS})

# Build the talker executable
add_executable(talker talker.cpp)
target_link_libraries(talker ${roscpp_LIBRARIES} ${std_msgs_LIBRARIES})

# Build the listener executable
add_executable(listener listener.cpp)
target_link_libraries(listener ${roscpp_LIBRARIES} ${std_msgs_LIBRARIES})


# Build the listener library
add_library(listener_lib SHARED listener.cpp)
set_target_properties(listener_lib PROPERTIES
        CXX_STANDARD 11
        CXX_STANDARD_REQUIRED YES
        CXX_EXTENSIONS NO
        POSITION_INDEPENDENT_CODE ON
        )
target_link_libraries(listener_lib ${roscpp_LIBRARIES} ${std_msgs_LIBRARIES})

# Install the executables and the library
install(TARGETS talker listener_lib
        DESTINATION bin)

The .C program is compiled independently, which reads the variable from the .so file.

One thing that “worked”: It takes the variable value if I ADD by hand the variable value in the .CPP file. But of course, the variable never changes.

Thanks and regards!

edit retag flag offensive close merge delete

1 Answer

Sort by » oldest newest most voted
0

answered 2023-03-20 15:36:35 -0500

Mike Scheutzow gravatar image

updated 2023-03-21 07:08:22 -0500

You code is not valid:

char* ros_value;
ros_value = const_cast<char*>(msg->data.c_str());

It is not legal c to use that char pointer after the callback function returns. However, making a full copy of the std::string would be legal:

std::string ros_value;
ros_value = msg->data;

Edit: as @gvdhoorn points out in the comments, a variable declared this way is only visible within the same process. Other processes using the shared library won't see the value that is assigned.

edit flag offensive delete link more

Comments

Hello, Thanks for you interest and the help with this.

I just tried that out, but I can't still receive it from C reading the .so file.

I have even created a function inside the -extern "C"- just to see if doing that I can get something, but not.

Calling that function from listener.cpp works fine and print the changes without an issue. I don't really know from where this problem come from. If I create a random .cpp file (not ROS related) I can change and read the value from C without any problem.

I'm wondering if this issue can be because some ROS libraries.

Thanks again for your time.

jjrbfi gravatar image jjrbfi  ( 2023-03-21 02:30:07 -0500 )edit

I believe the problem is that shared libraries don't work the way you are trying to use them here.

Shared libraries share code, not state. If two executables load the same shared library, they will not automatically also share any state (ie: variables) declared/defined by that shared library.

You are trying to share state here (ie: the ros_value variable).

In essence, every program loading your shared library will get its own copy of ros_value. They won't all share the same instance of that variable.

gvdhoorn gravatar image gvdhoorn  ( 2023-03-21 03:08:13 -0500 )edit

@gvdhoorn Excellent point. I didn't notice he/she was also trying to execute a separate process.

Mike Scheutzow gravatar image Mike Scheutzow  ( 2023-03-21 07:03:06 -0500 )edit

Thanks for your answer @gvdhoorn and @Mike

I just ended up using cros (https://github.com/ros-industrial/cros/). That was what I was looking for for a while!

There is a wrong reference in wiki.ros (Check link below)... For that reason I wanted to find an own way to reach this goal. http://wiki.ros.org/rosc

Thanks again for your time!

jjrbfi gravatar image jjrbfi  ( 2023-03-27 01:03:59 -0500 )edit

rosc != cros and cros != rosc.

Those are two completely disconnected developments.

gvdhoorn gravatar image gvdhoorn  ( 2023-03-27 04:34:48 -0500 )edit

Question Tools

1 follower

Stats

Asked: 2023-03-19 05:28:06 -0500

Seen: 80 times

Last updated: Mar 21 '23