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

В настоящее время я перевожу изящный 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 — это то, чего я не понимаю. Я был бы очень признателен за помощь, потому что я нахожусь под большим запасом времени.

Если кому-то интересно (контекстные причины): я должен перевести файлы mtdevice.py, mtnode.py и mtdef.py, и их можно найти в поиске имен файлов + ключевое слово ROS IMU Driver

Заранее большое спасибо.

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.

Здесь есть еще одна проблема. Данные, которые вы получили, находятся в порядке с прямым порядком байтов, но если у вас нет 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), NB. Вышеупомянутый код замены байтов не проверен; Я постараюсь скомпилировать его чуть позже и исправить при необходимости.

Без дополнительной информации я не могу дать вам точный способ сделать это, но, возможно, этого будет достаточно, чтобы помочь вам решить это самостоятельно.

1

Другие решения

Этот фрагмент кода распаковывает поля структуры C, а именно masterID, period, skipfactor, _, _, _, date, time, num, deviceID, length, mode, settings, сохраняет их в словаре 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 и вернуть ее. Строка формата + документы, на которые указывает ссылка, сообщают вам, какие типы данных есть в вашей структуре и где.

Обратите внимание, что это второй параметр unpack, который содержит ваши данные, первый параметр просто содержит информацию о компоновке (формате) второго параметра, как описано в ссылке. Второй параметр выглядит для Python, как будто это строка, но на самом деле это структура C. Первый параметр сообщает Python, где найти что в этой структуре.

Поэтому, если вы читаете документы по форматным строкам, вы можете узнать структуру вашего второго параметра (структура C). Но, может быть, вам не нужно. Это зависит от абонента вашей функции. Это может просто ожидать простую структуру Си.

Из ваших добавленных комментариев я понимаю, что в вашей функции больше кода, чем вы показываете. Поля структур присваиваются атрибутам класса.

Если вы знаете имена полей вашей структуры C (config), то вы можете назначить их непосредственно атрибутам вашего класса C ++.

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

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

Я предположил, что имена полей структуры конфигурации действительно являются режимом, настройками, длиной и т. Д., Но вы должны это проверить. Вероятно, макет этой структуры объявлен в некотором заголовочном файле C (или в документах).

2

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector