Files
motor_params/docs/TELEMETRY_PROTOCOL.md

16 KiB
Raw Permalink Blame History

Протокол телеметрии

Документ описывает текущий бинарный пакет телеметрии из прошивки AD_Keil_Project.

Основные файлы реализации:

Файл Назначение
Core/Inc/simulink_interface.h Формат пакета, версия, размеры, API
Core/Src/simulink_interface.c Заполнение пакета и CRC16
Core/Inc/ad_binary_transport.h Выбор протокола и транспорта
Core/Src/ad_binary_transport.c Отправка готового пакета
Core/Src/ad_usb_cdc.c USB FS CDC ACM транспорт
Core/Src/ad_can_telemetry.c FDCAN1 classic CAN транспорт
Core/Src/ad_modbus.c Modbus-регистры включения бинарной телеметрии

Кратко

Прошивка формирует один бинарный пакет SimulinkTelemetryPacket_t. Пакет можно отдавать через USB CDC, через FDCAN1 classic CAN или одновременно через оба транспорта.

По умолчанию бинарный поток выключен:

AD_HOST_PROTOCOL_DEFAULT = 0
AD_BINARY_TELEMETRY_TRANSPORT_DEFAULT = 0

То есть после старта активен режим 0 - Modbus-контроль без бинарной телеметрии. Чтобы включить поток, нужно через Modbus записать:

0x001D / 29 = транспорт
0x001C / 28 = 1

Где транспорт:

Значение Транспорт
0 USB CDC
1 CAN/FDCAN1
2 USB CDC и CAN/FDCAN1 одновременно

Чтобы выключить бинарный поток:

0x001C / 28 = 0

Частота

Пакет обновляется в SimulinkInterface_StepSlow(), который вызывается из AD_Board_Loop() раз в AD_BOARD_SLOW_PERIOD_MS = 10 мс.

Отправка из AD_BinaryTransport_Loop() также ограничена периодом:

AD_BINARY_TELEMETRY_PERIOD_MS = 10

Итого штатная частота телеметрии - около 100 Гц, если главный цикл успевает обслуживать транспорт.

Кодирование данных

Параметр Значение
Порядок байт little-endian, как у STM32 Cortex-M
float IEEE-754 binary32, 4 байта
Выравнивание обычное C-выравнивание ARMCLANG, без packed
Текущий размер заголовка 16 байт
Текущий размер payload 136 байт
Текущий размер полного пакета 152 байта
Максимум, разрешенный кодом SIMULINK_TELEMETRY_MAX_BYTES = 256

Если структура в C будет изменена, PC-парсер должен проверять header.version и header.payload_size.

Заголовок пакета

Тип: SimulinkTelemetryHeader_t.

Смещения указаны от начала пакета.

Offset Размер Тип Поле Значение / описание
0 4 uint32_t magic 0x41444944
4 2 uint16_t version 3
6 2 uint16_t payload_size 136 для текущей версии
8 4 uint32_t sequence Увеличивается при каждой упаковке
12 2 uint16_t crc16 CRC16-CCITT по payload
14 2 uint16_t reserved 0

magic сравнивать как uint32_t little-endian. На проводе байты идут так:

44 49 44 41

CRC16

CRC считается только по payload, без заголовка.

Параметры:

Параметр Значение
Алгоритм CRC16-CCITT
Начальное значение 0xFFFF
Полином 0x1021
Reflection нет
Final XOR нет

Проверка на стороне ПК:

crc16_ccitt(packet[16 : 16 + payload_size]) == header.crc16

Payload

Тип: SimulinkTelemetryPayload_t.

Смещения в таблице указаны от начала payload. Чтобы получить смещение от начала пакета, прибавь 16.

Измерения

Блок measurements, тип AD_Measurements_t, размер 64 байта.

Payload offset Тип Поле Единицы
0 float measurements.ia_A A
4 float measurements.ib_A A
8 float measurements.ic_A A
12 float measurements.ia_rms_A A RMS
16 float measurements.ib_rms_A A RMS
20 float measurements.ic_rms_A A RMS
24 float measurements.vdc_V V
28 float measurements.va_V V
32 float measurements.vb_V V
36 float measurements.vc_V V
40 float measurements.speed_rpm rpm
44 float measurements.torque_Nm N*m
48 float measurements.temperature_C град C
52 uint32_t measurements.timestamp_us us
56 uint32_t measurements.status_flags AD_MEAS_STATUS_*
60 float measurements.slip_percent %

measurements.status_flags:

Бит Маска Флаг
0 0x00000001 AD_MEAS_STATUS_OVERCURRENT
1 0x00000002 AD_MEAS_STATUS_OVERVOLTAGE
2 0x00000004 AD_MEAS_STATUS_UNDERVOLTAGE
3 0x00000008 AD_MEAS_STATUS_OVERTEMPERATURE
4 0x00000010 AD_MEAS_STATUS_DRIVER_FAULT
5 0x00000020 AD_MEAS_STATUS_EMERGENCY_STOP

Параметры двигателя

Блок motor_parameters, тип AD_MotorParameters_t, размер 60 байт.

Payload offset Тип Поле Единицы
64 float motor_parameters.Rs_ohm Ohm
68 float motor_parameters.Rr_ohm Ohm
72 float motor_parameters.Ls_H H
76 float motor_parameters.Lr_H H
80 float motor_parameters.Lm_H H
84 float motor_parameters.Ll_H H
88 float motor_parameters.J_kg_m2 kg*m2
92 float motor_parameters.B_Nm_s Nms
96 float motor_parameters.pole_pairs пары полюсов
100 float motor_parameters.nominal_voltage_V V
104 float motor_parameters.nominal_current_A A
108 float motor_parameters.nominal_frequency_Hz Hz
112 float motor_parameters.nominal_power_W W
116 float motor_parameters.nominal_speed_rpm rpm
120 uint32_t motor_parameters.valid_mask AD_MOTOR_PARAM_VALID_*

valid_mask:

Бит Маска Флаг Поле
0 0x00000001 AD_MOTOR_PARAM_VALID_RS Rs_ohm
1 0x00000002 AD_MOTOR_PARAM_VALID_RR Rr_ohm
2 0x00000004 AD_MOTOR_PARAM_VALID_LS Ls_H
3 0x00000008 AD_MOTOR_PARAM_VALID_LR Lr_H
4 0x00000010 AD_MOTOR_PARAM_VALID_LM Lm_H
5 0x00000020 AD_MOTOR_PARAM_VALID_LL Ll_H
6 0x00000040 AD_MOTOR_PARAM_VALID_J J_kg_m2
7 0x00000080 AD_MOTOR_PARAM_VALID_B B_Nm_s
8 0x00000100 AD_MOTOR_PARAM_VALID_NOMINALS nominal fields
9 0x00000200 AD_MOTOR_PARAM_VALID_POLE_PAIRS pole_pairs

Перед использованием результата идентификации обязательно проверять соответствующий бит valid_mask.

Статус идентификации и команда

Payload offset Тип Поле Описание
124 uint32_t param_id_status AD_PARAM_ID_STATUS_*
128 uint32_t param_id_faults AD_PARAM_ID_FAULT_*
132 uint8_t param_id_mode Текущий режим AD_PARAM_ID_MODE_*
133 uint8_t command_enable Последняя команда enable
134 uint8_t command_test_mode Последняя команда test mode
135 uint8_t reserved 0

param_id_status:

Бит Маска Флаг
0 0x00000001 AD_PARAM_ID_STATUS_ACTIVE
1 0x00000002 AD_PARAM_ID_STATUS_POWER_TEST_BLOCKED
2 0x00000004 AD_PARAM_ID_STATUS_POWER_STAGE_ARMED
3 0x00000008 AD_PARAM_ID_STATUS_FAULT_LATCHED
4 0x00000010 AD_PARAM_ID_STATUS_TIMEOUT
5 0x00000020 AD_PARAM_ID_STATUS_LOCKED_ROTOR_BLOCKED
6 0x00000040 AD_PARAM_ID_STATUS_SAFETY_LIMITS_UNKNOWN
7 0x00000080 AD_PARAM_ID_STATUS_DATA_VALID
8 0x00000100 AD_PARAM_ID_STATUS_COMPLETE

param_id_faults:

Бит Маска Флаг
0 0x00000001 AD_PARAM_ID_FAULT_OVERCURRENT
1 0x00000002 AD_PARAM_ID_FAULT_OVERVOLTAGE
2 0x00000004 AD_PARAM_ID_FAULT_UNDERVOLTAGE
3 0x00000008 AD_PARAM_ID_FAULT_OVERTEMPERATURE
4 0x00000010 AD_PARAM_ID_FAULT_DRIVER
5 0x00000020 AD_PARAM_ID_FAULT_EMERGENCY_STOP
6 0x00000040 AD_PARAM_ID_FAULT_TIMEOUT
7 0x00000080 AD_PARAM_ID_FAULT_NULL_INPUT

Режимы param_id_mode и command_test_mode:

Значение Режим
0 AD_PARAM_ID_MODE_IDLE
1 AD_PARAM_ID_MODE_STATOR_RESISTANCE
2 AD_PARAM_ID_MODE_NO_LOAD_MAGNETIZING
3 AD_PARAM_ID_MODE_LOCKED_ROTOR_LEAKAGE
4 AD_PARAM_ID_MODE_INERTIA_FRICTION
5 AD_PARAM_ID_MODE_DATA_LOGGING
6 AD_PARAM_ID_MODE_PWM_TEST_UH
7 AD_PARAM_ID_MODE_PWM_TEST_UL
8 AD_PARAM_ID_MODE_PWM_TEST_VH
9 AD_PARAM_ID_MODE_PWM_TEST_VL
10 AD_PARAM_ID_MODE_PWM_TEST_WH
11 AD_PARAM_ID_MODE_PWM_TEST_WL
12 AD_PARAM_ID_MODE_PWM_TEST_ALL
13 AD_PARAM_ID_MODE_AUTO_IDENTIFICATION
14 AD_PARAM_ID_MODE_ROTATION_3HZ

USB CDC транспорт

USB реализован как CDC ACM устройство на USB FS:

Параметр Значение
Линии PA11 USB_DM, PA12 USB_DP
Тактирование HSI48
VID/PID 0x0483 / 0x5740
Product string AD Telemetry CDC
Data IN endpoint 0x81, bulk, 64 байта
Data OUT endpoint 0x01, bulk, 64 байта
CMD endpoint 0x82, interrupt, 8 байт

Код вызывает HAL_PCD_EP_Transmit() на весь пакет сразу, но CDC на стороне ПК нужно считать потоком байт. Один read() на ПК не обязан совпадать с одним пакетом прошивки.

Рекомендуемый парсер:

  1. Искать в потоке magic bytes 44 49 44 41.
  2. Дочитать 16-байтный заголовок.
  3. Проверить version == 3.
  4. Проверить payload_size == 136 или обработать совместимую новую версию.
  5. Дочитать payload_size байт.
  6. Проверить CRC16.
  7. Передать payload в декодер.

CAN/FDCAN транспорт

CAN реализован через FDCAN1 в режиме classic CAN, кадры по 8 байт.

Параметр Значение
Периферия FDCAN1
RX/TX PB8 / PB9
Frame format Classic CAN
Bit rate switch Off
Default base standard ID 0x5A0
Payload одного CAN-кадра до 8 байт

Базовый ID задается:

AD_CAN_TELEMETRY_STD_ID_BASE = 0x5A0

Полный бинарный пакет режется последовательно:

CAN ID Данные
0x5A0 bytes 0..7
0x5A1 bytes 8..15
0x5A2 bytes 16..23
... ...

Для текущего пакета 152 байта нужно 19 CAN-кадров:

ceil(152 / 8) = 19
IDs: 0x5A0..0x5B2

Последний кадр несет полный 8-байтный блок.

Рекомендация для приемника CAN:

  1. Считать кадр с base_id.
  2. Начать буфер нового пакета.
  3. Добавлять кадры base_id + index.
  4. После первых 16 байт прочитать payload_size.
  5. Ждать 16 + payload_size байт.
  6. Проверить magic, version, sequence, crc16.
  7. При пропуске ID или смене sequence сбросить сборку пакета.

Включение через Modbus

Modbus RTU остается каналом управления.

Параметр Значение
UART USART2
TX/RX PA2 / PA3
Скорость 115200
Формат 8N1
Slave address 1

Регистры:

Адрес hex / dec Имя Доступ Значение
0x001C / 28 control_host_protocol R/W 0 = Modbus, 1 = binary telemetry
0x001D / 29 control_binary_transport R/W 0 = USB, 1 = CAN, 2 = USB + CAN

Пример включения USB CDC:

write 0x001D / 29 = 0
write 0x001C / 28 = 1

Пример включения CAN:

write 0x001D / 29 = 1
write 0x001C / 28 = 1

Пример одновременной отправки USB и CAN:

write 0x001D / 29 = 2
write 0x001C / 28 = 1

Остановка бинарной телеметрии:

write 0x001C / 28 = 0

Состояние транспорта в отладчике

Основной debug-view:

g_ad_debug.binary_transport
g_ad_debug.modbus

g_ad_debug.binary_transport.status_flags:

Бит Маска Флаг
0 0x00000001 AD_BINARY_TRANSPORT_STATUS_INITIALIZED
1 0x00000002 AD_BINARY_TRANSPORT_STATUS_USB_READY
2 0x00000004 AD_BINARY_TRANSPORT_STATUS_CAN_READY
3 0x00000008 AD_BINARY_TRANSPORT_STATUS_USB_CONFIGURED
4 0x00000010 AD_BINARY_TRANSPORT_STATUS_USB_TX_BUSY
5 0x00000020 AD_BINARY_TRANSPORT_STATUS_CAN_TX_BUSY
6 0x00000040 AD_BINARY_TRANSPORT_STATUS_LAST_DROPPED

Полезные счетчики:

Поле Значение
tx_packets Сколько пакетов успешно поставлено хотя бы в один транспорт
usb_packets Сколько пакетов принято USB TX
can_packets Сколько пакетов принято CAN TX
dropped_packets Сколько пакетов сброшено из-за busy/error/size
last_size_bytes Последний размер пакета, сейчас должен быть 152
last_tx_tick_ms HAL_GetTick() последней успешной постановки

API прошивки

void SimulinkInterface_PackTelemetry(void);
const SimulinkTelemetryPacket_t* SimulinkInterface_GetTelemetryPacket(void);
const uint8_t* SimulinkInterface_GetTelemetryBytes(void);
size_t SimulinkInterface_GetTelemetrySize(void);

void AD_BinaryTransport_Init(void);
void AD_BinaryTransport_Loop(void);
uint8_t AD_BinaryTransport_SetProtocol(uint16_t protocol);
uint8_t AD_BinaryTransport_SetTransport(uint16_t transport);
const AD_BinaryTransportState_t* AD_BinaryTransport_GetState(void);

Минимальный Python-декодер CRC

def crc16_ccitt(data: bytes) -> int:
    crc = 0xFFFF
    for value in data:
        crc ^= value << 8
        for _ in range(8):
            if crc & 0x8000:
                crc = ((crc << 1) ^ 0x1021) & 0xFFFF
            else:
                crc = (crc << 1) & 0xFFFF
    return crc

Поля unpack для текущей версии:

HEADER_FMT = "<IHHIHH"
PAYLOAD_SIZE_V3 = 136
PACKET_SIZE_V3 = 16 + PAYLOAD_SIZE_V3
MAGIC = 0x41444944
VERSION = 3