Python(rospy)到C ++(roscpp)struct.unpack

时间:2015-07-01 13:46:59

标签: python c++ ros code-translation

我目前正在将rospy IMU驱动程序翻译成roscpp,并且难以确定这段代码的作用以及我如何翻译它。

def ReqConfiguration(self):
    """Ask for the current configuration of the MT device.
    Assume the device is in Config state."""
    try:
        masterID, period, skipfactor, _, _, _, date, time, num, deviceID,\
                length, mode, settings =\
                struct.unpack('!IHHHHI8s8s32x32xHIHHI8x', config)
    except struct.error:
        raise MTException("could not parse configuration.")
    conf = {'output-mode': mode,
            'output-settings': settings,
            'length': length,
            'period': period,
            'skipfactor': skipfactor,
            'Master device ID': masterID,
            'date': date,
            'time': time,
            'number of devices': num,
            'device ID': deviceID}
    return conf

我必须承认,我之前从未使用过ros或python。 这不是来自源代码的1:1代码,我删除了我认为我知道他们做了什么的行,但特别是try-block是我不明白的。我真的很感激帮助,因为我非常珍惜时间。

如果有人好奇(背景原因):我要翻译的文件是mtdevice.py,mtnode.py和mtdef.py,可以找到googleing的文件名+关键字ROS IMU Driver

提前多多感谢。

2 个答案:

答案 0 :(得分:2)

这段代码解包C结构的字段,即masterID,句点,跳过因子,_,_,_,日期,时间,数字,设备ID,长度,模式,设置,将它们存储在Python字典中并返回那个词典作为通话结果。下划线是结构中未使用的部分的占位符。

另请参阅:https://docs.python.org/2/library/struct.html,例如有关格式字符串('!IHHHHI8s8s32x32xHIHHI8x')的描述,它告诉解包函数结构是什么样的。

语法a,b,c,d = f()意味着该函数在Python中返回一个名为元组的东西。通过将元组分配给多个变量,它将被分割为其字段。

示例:

 t = (1, 2, 3, 4)

 a, b, c, d = t

 # At this point a == 1, b == 2, c == 3, d == 4

用C ++替换这段代码不应该太难,因为C ++的结构很像C.所以requestConfiguration最简单的C ++实现就是返回那个结构。如果您想更接近Python功能,您的函数可以将结构的字段放入C ++ STL映射并返回。格式字符串+链接指向的文档,告诉您结构中的数据类型以及位置。

请注意,它是保存数据的第二个解包参数,第一个参数只包含有关第二个参数布局(格式)的信息,如链接中所述。第二个参数看起来像Python它是一个字符串,但它实际上是一个C结构。第一个参数告诉Python在哪里找到该结构中的内容。

因此,如果您阅读格式字符串上的文档,则可以找到第二个参数(C struct)的布局。但也许你不需要。这取决于你的函数的调用者。它可能只是期望普通的C结构。

根据您添加的评论,我了解您的功能中的代码比您显示的代码多。结构的字段分配给类的属性。

如果您知道C struct(config)的字段名称,那么可以将它们直接分配给C ++类的属性。

// Pointer 'this' isn't needed but inserted for clarity

this->mode = config.mode;
this->settings = config.settings;
this->length = config.length;

我认为配置结构的字段名称确实是模式,设置,长度等,但您必须验证它。可能在某些C头文件(或文档)中声明了此结构的布局。

答案 1 :(得分:1)

要使用C ++执行相同的操作,您需要使用各种参数声明struct

struct DeviceRecord {
    uint32_t masterId;
    uint16_t period, skipfactor, _a, _b;
    uint32_t _c;
    char date[8];
    char time[8];
    char padding[64];
    uint16_t num;
    uint32_t deviceID;
    uint16_t length, mode;
    uint32_t settings;
    char padding[8];
};

(可能这个结构已经在某处被声明;它也可能使用" unsigned int"而不是" uint32_t"和" unsigned short"而不是" uint16_t"和_a,_b,_c可能有实名。)

获得结构后,问题是如何获取数据。这取决于数据的位置。如果它在文件中,您可以执行以下操作:

DeviceRecord rec; // An instance of the struct, whatever it's called
std::ifstream fin("yourfile.txt", std::ios::binary);
fin.read(reinterpret_cast<char*>(&rec), sizeof(rec));
// Now you can access rec.masterID etc

另一方面,如果它在内存中的某个地方(即你有一个char *或void *),那么你只需要施放它:

void* data_source = get_data(...); // You'd get this from somewhere
DeviceRecord* rec_ptr = reinterpret_cast<DeviceRecord*>(stat_source);
// Now you can access rec_ptr->masterID etc

如果您有std::vector,则可以轻松获得指针:

std::vector<uint8_t> data_source = get_data(...); // As above
DeviceRecord* rec_ptr = reinterpret_cast<DeviceRecord*>(data_source.data());
// Now you can access rec_ptr->masterID etc, provided data_source remains in scope. You should probably also avoid modifying data_source.

这里还有一个问题。您收到的数据是big-endian,但除非您有PowerPC或其他不寻常的处理器,否则您可能使用的是小端机器。因此,在访问数据之前,需要进行一些字节交换。您可以使用以下功能执行此操作。

template<typename Int>
Int swap_int(Int n) {
    if(sizeof(Int) == 2) {
        union {char c[2]; Int i;} swapper;
        swapper.i = n;
        std::swap(swapper.c[0], swapper.c[1]);
        n = swapper.i;
    } else if(sizeof(Int) == 4) {
        union {char c[4]; Int i;} swapper;
        swapper.i = n;
        std::swap(swapper.c[0], swapper.c[3]);
        std::swap(swapper.c[1], swapper.c[2]);
        n = swapper.i;
    }
    return n;
}

这些返回交换的值而不是就地更改它,因此现在您可以使用swap_int(rec->num)之类的内容访问您的数据。注意:上面的字节交换代码未经测试;我稍后会尝试编译它并在必要时修复它。

如果没有更多信息,我无法为您提供明确的方法,但这可能足以帮助您自己解决问题。