rosserial发布sensor_msgs /来自windows

时间:2016-11-25 23:57:35

标签: c++ windows image kinect ros

我正在开发一个带有windows和kinect v1传感器的sdk的项目。目标是将kinect中的彩色图像发送到ros, using rosserial.

我不确切知道如何处理这件事。现在我正在使用sensor_msgs/Image消息发布RGB值。这是我到目前为止的代码:

    img.header.stamp = nh->now();
    img.header.frame_id = "kinect1_ref";
    img.height = height;
    img.width = width;        
    img.encoding = "rgb8";
    img.is_bigendian = false;
    img.step = width*3;

    BYTE* start = (BYTE*) lockedRect.pBits;
    img.data = new uint8_t[width*3*height];



    long it;
    for (int y = 0; y < height; ++y) {
        for (int x = 0; x < width; ++x) {
            const BYTE* curr = start + (x + width*y)*4;
            for(int n=0; n<3; n++){
                it = y*width*3 + x*3 + n;
                img.data[it] =  (uint8_t) curr[2-n];
            }
        }
    }   
    pub->publish(&img);

在代码中, img 是sensor_msgs / Image, lockedRect.pBits 是指向kinect图像第一个字节的指针。据我所知,来自kinect的图像按行从上到下依次存储,每个像素由4个连续字节表示,表示填充字节,然后是R,G和B.

我实际上能够将此发送给ros,但是当我尝试使用它时,我会收到以下错误:

加载图片时出错:OGRE EXCEPTION。流大小与图像中计算的图像大小不匹配。

我非常喜欢这个,我设置的大小是正确的,考虑到RGB的3个通道。从 BYTE uint8_t 的转换应该是微不足道的,因为它们都是无符号字符。

PD:我知道我可以使用openni_launch来显示来自ubuntu和ros的kinect数据,但由于语音识别引擎,我需要在这种情况下使用windows。

PD2:cv_bridge,通常用于在ros中发布图像,不包含在rosserial库中。因此,我必须从头开始构建图像消息(可能还有另一种方式?)

任何帮助都会得到真正的帮助,请提前谢谢!

编辑: rosserial for windows生成的sensor_msgs / Image消息类仅包含以下代码:

  class Image : public ros::Msg{
public:
  std_msgs::Header header;
  uint32_t height;
  uint32_t width;
  char * encoding;
  uint8_t is_bigendian;
  uint32_t step;
  uint8_t data_length;
  uint8_t st_data;
  uint8_t * data;
  virtual void serialize(unsigned char *outbuffer);
  virtual void deserialize(unsigned char *inbuffer);}

这里没有写入序列化和反序列化的方法,但实际上我不知道它们是如何工作的。

2 个答案:

答案 0 :(得分:0)

我想知道这是如何编译的。 img.datastd::vector<uint8_t>。话虽如此,试试这个:

img.header.stamp = nh->now();
img.header.frame_id = "kinect1_ref";
img.height = height;
img.width = width;        
img.encoding = "rgb8";
img.is_bigendian = false;
img.step = width * 3;

BYTE* start = (BYTE*) lockedRect.pBits;
img.data.resize(img.step * height);

long it;
for (int y = 0; y < height; ++y) {
    for (int x = 0; x < width; ++x) {
        const BYTE* curr = start + (x + width*y)*4;
        for(int n=0; n<3; n++){
            it = y*width*3 + x*3 + n;
            img.data[it] =  (uint8_t) curr[2-n];
        }
    }
}   
pub->publish(&img);

<强>更新

我发现了有关rosserial_windows限制中使用的协议的信息。虽然您指定了高度和宽度以及步长,但序列化对这些消息变量是不可知的。我似乎还必须在data_lendth中指定数组的长度。但这是问题所在。由于某些奇怪的原因,最大数组长度限制为uint8_t

任何数组类型T []的数组长度都需要设置变量T_length。这意味着在不更改协议的情况下,您不能超过uint8_t限制。

一种解决方案,但痛苦而缓慢的是将图像拆分为255字节的自定义消息并对其进行索引。您必须将图像数据放在接收器端,并从数据中创建sensor_msgs :: Image并发布。

答案 1 :(得分:0)

首先,感谢cassinaj,我认为解决方案将是他提出的答案。我将添加一些我在同样情况下为人们找到的信息。

rosserial中数组的限制由uint8_t给出,在大多数ros分布中最多为255个字节。但是,此问题已在此thread中进行了评论,建议将此值增加到uint32_t。变化was done in Jade devel。因此,如果您从Jade中的rosserial生成 ros_lib 库,则数据的长度应为uint32_t。现在,这是Image消息的生成代码:

  class Image : public ros::Msg
  {
  public:
    std_msgs::Header header;
    uint32_t height;
    uint32_t width;
    const char* encoding;
    uint8_t is_bigendian;
    uint32_t step;
    uint32_t data_length;
    uint8_t st_data;
    uint8_t * data;
  Image():
    header(),
    height(0),
    width(0),
    encoding(""),
    is_bigendian(0),
    step(0),
    data_length(0), data(NULL)
{
}
 virtual int serialize(unsigned char *outbuffer) const
 virtual int deserialize(unsigned char *inbuffer)

我期待现在一切正常,但又出现了另一个问题。尽管数组的长度可能很高,但rosserial消息的缓冲区仍然限制在较低的值。我想这是协议本身是有限的。然后,我无法发送480x640xRGB的整个图像信息,但我可以发送一部分图像(8x8xRGB),直到我测试。这终于工作了,我在rviz中可视化了图像,没有任何问题。

因此,正如cassinaj所提出的,一种解决方案是将所有数据分成几部分,然后将它们全部放在接收器端。这应该有效,虽然听起来真的很痛苦(如果我将图像分成8x8部分,那么对于单个图像来说这将是大约4800条消息!)。

出于这个原因,我试图使用win_ros(ros for windows),以便通过ros本身发送来自kinect的所有数据。遗憾的是,rosserial具有这些局限性,因为它非常易于使用和实施。

如果有人要添加任何其他内容,或者我遗失了某些内容,请告知我们。任何帮助都是真正的帮助!