0

I am very very very new to ROS and embedded C++ programming. I hate Python and I wish to convert a node written originally in Python to C++. I won't get into detail on this conversion I am happy with OOP approach I took (put subscriber callback into a class, put publisher as class member), the main issue however is a piece of code in python that deals with byte arrays needed for communication with Arduino. I never worked with bytes and bits in C++, and it turned out that people use Python for its friendly Pyserial library, while the equivalent approach in C++ is very dark, specially on Linux OS.

Python code is:

def function_callback(my_data):
global packet
my_array=my_data.data
print(my_array)
packet = bytearray()
for byte in my_array:
    packet.append(byte+48)
packet.append(0x0A)
packet.append(0x0D)

I understand that this takes my_data which is of ROS std_msgs/ByteMultiArray type, passes the actual data from that message to array my_array, now the elements in this array are being read as ASCI instead as bits, so for loop adds 48 to each element in order to get their decimal value. The last two appends are some special bytes needed in Arduino.

In C++ I have no idea how to this. I found instructions here and created a class SerialComm that in essence mimics that code, the most important method in that class should be:

void SerialComm::write_port(unsigned char* msg)
{ 
  int i=write(serial_port, msg, sizeof(msg));
}

where I am unsure if argument should have unsigned char* data type, but it seems that write function in unistd.h supports this.

Overall, how do I prepare the "packet" and send it to be written to the port?

To be more specific the data I need to write is of std_msgs/ByteMultiArray type in ROS, I checked it and the actual data is std::vector<signed char> type, I attempted this as a solution:

unsigned char* make_byte_array(std::vector<signed char> array) const
{
    unsigned char retval[array.size()+2];
    int i=0;
    while (i<array.size())
    {
       retval[i]=array[i];
       i++;
    }
    retval[i+1]=0x0A;
    retval[i+2]=0x0D;
    return retval;
 }

This function is clearly nonsense, but it compiles, it naturally does not work because address of retval variable is being returned and nothing else, but I was mainly trying to somehow pass unsigned char* to that write function to write data to the port. The main issue of course is how to convert std::vector array obtained from std_msgs/ByteMultiArray into whatever is needed to write to arduino port and essentially mimic the packet being sent in Python solution. I think I struggle here mostly in understanding the chars data types as I never really worked with them, all I recall is that they are important because have unit bit memory size.

khelwood
  • 55,782
  • 14
  • 81
  • 108

1 Answers1

1

Most direct solution:

std::vector<signed char> make_byte_array(std::vector<signed char> array) const
{
    array.push_back('\n');
    array.push_back('\r');
    return array;
}

What's happening: array is passed by value so it's automatically copied. We take advantage of this copy to eliminate the need to manually copy inside the function. Then we append the line feed and carriage return and return the resulting vector.

To get the array stored inside the vector either use vector's data method

signed char * data = result_vector.data();

or in the pre-c++11 world, I've never seen this trick not work:

signed char * data = &result_vector[0];

So... what went wrong? Returning an array in C++ is hard. Unlike everything else in C++, an array defaults to pass by reference thanks to Array Decay. retval decays to a pointer, the pointer is returned, and retval goes out of scope and is destroyed, leaving you with a pointer to invalid memory.

user4581301
  • 33,082
  • 7
  • 33
  • 54