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

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

我目前正在将一个 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 并且可以在谷歌搜索文件名+关键字 ROS 找到IMU 驱动程序

非常感谢。

这段代码将一个C结构的字段,即masterID、period、skipfactor、_、_、_、date、time、num、deviceID、length、mode、settings解包,存储在一个Python 字典和 return 那个字典作为调用结果。下划线是未使用的结构部分的占位符。

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

语法a,b,c,d = f()表示函数return是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++ 实现就是 return 该结构。如果你想更接近 Python 功能,你的函数可以将结构的字段放入 C++ STL 映射和 return 中。格式字符串 + link 指向的文档,告诉您结构中的数据类型以及位置。

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

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

根据您添加的评论,我了解到您的函数中的代码比您显示的要多。结构的字段分配给 class.

的属性

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

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

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

我假设配置结构的字段名称确实是模式、设置、长度等,但您必须验证这一点。可能这个结构的布局是在一些 C 头文件(或文档)中声明的。

要用 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.

这里还有一个问题。您收到的数据是大端数据,但除非您有 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;
}

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

没有更多信息,我无法为您提供明确的方法,但也许这足以帮助您自行解决。