Ask Your Question
1

How to publish a 2 dimensional array of known values

asked 2016-05-10 03:58:33 -0500

beeeeck gravatar image

Hello,

I'm stuck at my program to publish a 2 dimensional array. The array kinda looks like this:

int deptharray[4][5] = { {0, 0, 0, 0}, {0, average11, average21, average31, average41}, {0, average12, average22, average32, average42}, 0, average13, average23, average33, average43}, }; I also read several posts about how to publish an int32MultiArray but unfortunately none of my attemps to publish this array of known values worked. All examples that I have seen have unknown sizes and then use the push_back function in a for loop. I'd be really glad if you could help me. Thank you very much

edit retag flag offensive close merge delete

2 Answers

Sort by ยป oldest newest most voted
4

answered 2016-05-12 16:32:30 -0500

If your data is always going to be a 4x5 array, you could create a custom message that contained an array of 20 integers and then do a little math to determine how to translate (row,col) access to entries in the 1D array (correct way to do this would depend on if you wanted to use column-major or row-major storage). This would work fine, but could definitely be error prone.

An alternative would be to create a custom message containing arrays of, e.g., 5 integers that would represent rows, then create another custom message that contained an array of length 4 of the first message. In C++, this would become a std::vector< std::vector<int> >. This would also work fine.

There is no reason you can't use the Int32MultiArray from std_msgs, and you certainly don't have to use push_back. You could just initialize a std::vector of length 20 for the data field. Here's an example:

#include "ros/ros.h"
#include "std_msgs/Int32MultiArray.h"
#include "std_msgs/MultiArrayDimension.h"
#include <iostream>
#include <vector>
#include <array>

#define H (4)
#define W (5)


int main(int argc, char **argv)
{
    ros::init(argc, argv, "talker");
    ros::NodeHandle n;
    ros::Publisher pub = n.advertise<std_msgs::Int32MultiArray>("matrix_pub", 1);
    ros::Rate loop_rate(10);
    std_msgs::Int32MultiArray dat;
    int array[H][W] = {
        {0, 1, 2, 3, 4},
        {10, 11, 12, 13, 14},
        {20, 21, 22, 23, 24},
        {30, 31, 32, 33, 34}};

    // fill out message:
    dat.layout.dim.push_back(std_msgs::MultiArrayDimension());
    dat.layout.dim.push_back(std_msgs::MultiArrayDimension());
    dat.layout.dim[0].label = "height";
    dat.layout.dim[1].label = "width";
    dat.layout.dim[0].size = H;
    dat.layout.dim[1].size = W;
    dat.layout.dim[0].stride = H*W;
    dat.layout.dim[1].stride = W;
    dat.layout.data_offset = 0;
    std::vector<int> vec(W*H, 0);
    for (int i=0; i<H; i++)
        for (int j=0; j<W; j++)
            vec[i*W + j] = array[i][j];
    dat.data = vec;

    while (ros::ok())
    {
        pub.publish(dat);
        loop_rate.sleep();
    }

    return 0;
}
edit flag offensive delete link more

Comments

Hey, there are two consecutive same lines in the code. Is this done for a reason? Sorry I am not able to understand why that same line is run twice.
dat.layout.dim.push_back(std_msgs::MultiArrayDimension()); dat.layout.dim.push_back(std_msgs::MultiArrayDimension());

Thanks in advance.

aaditya_saraiya gravatar imageaaditya_saraiya ( 2017-10-23 11:15:27 -0500 )edit

It's because this is a two-dimensional array. So the dat.layout.dim array of std_msgs/MultiArrayDimension has one entry for the "width" channel, and one entry for the "height" channel. That's why I access dat.layout.dim[0] and dat.layout.dim[1]. The array starts empty, and I push_back 2x

jarvisschultz gravatar imagejarvisschultz ( 2017-10-23 15:11:10 -0500 )edit

Probably the best example to read is the example provided in comments in the std_msgs/MultiArrayLayout message definition.

jarvisschultz gravatar imagejarvisschultz ( 2017-10-23 15:11:51 -0500 )edit

Thank you so much @jarvisschultz for confirming. I had a similar thought but was asking just for the sake of correctness.

aaditya_saraiya gravatar imageaaditya_saraiya ( 2017-10-26 04:19:00 -0500 )edit

@jarvisschulz Hey. tested it today with few minor changes. Works perfectly. Thanks again

aaditya_saraiya gravatar imageaaditya_saraiya ( 2017-10-26 14:24:02 -0500 )edit

What is stride for? From my reading, it is seems that parameter use when image is involved. What I'm not sending image metadata? Is this parameter must be define or we can skip it if we don't use it? @jarvisschultz

ZazAa gravatar imageZazAa ( 2019-06-12 13:10:50 -0500 )edit
1

@ZazAa also posted on a public gist I made to answer another question. Those interested in this comment discussion may also find that communication thread of interest.

jarvisschultz gravatar imagejarvisschultz ( 2019-06-12 17:54:23 -0500 )edit
0

answered 2016-05-19 01:52:39 -0500

beeeeck gravatar image

updated 2016-05-19 09:13:03 -0500

Thank you very much for the response. I found a much simpler way to do it though. I just converted the array into a matrix and then published the matrix like this:

Mat matrixarray = Mat(11,20,CV_32FC1,deptharray);

diff.PubDepthArray(matrixarray);

where the method to publish the array looks like this:

void GetDiffImg::PubDepthArray(Mat depthArray){

    cv_bridge::CvImage diffImgMsg;
    diffImgMsg.encoding  = sensor_msgs::image_encodings::TYPE_32FC1;
    diffImgMsg.image    = depthArray;

    depthArrayPub.publish(diffImgMsg.toImageMsg());
edit flag offensive delete link more

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

1 follower

Stats

Asked: 2016-05-10 03:58:33 -0500

Seen: 5,203 times

Last updated: May 19 '16