Work ID test
This commit is contained in:
parent
e80f04d857
commit
207b889fef
4 changed files with 164 additions and 89 deletions
|
@ -4,13 +4,19 @@
|
||||||
#include "flash.h"
|
#include "flash.h"
|
||||||
#include "reg_cah.h"
|
#include "reg_cah.h"
|
||||||
|
|
||||||
|
#define CAN_TIMEOUT 50
|
||||||
|
#define CAN_SILENCE_TIMEOUT 500
|
||||||
|
#define MAX_CAN_READS 2
|
||||||
extern FLASH_RECORD *flash_rec;
|
extern FLASH_RECORD *flash_rec;
|
||||||
extern volatile uint16_t msg_id;
|
extern volatile uint16_t msg_id;
|
||||||
extern volatile uint16_t id_x;
|
extern volatile uint16_t id_x;
|
||||||
extern volatile uint8_t msg_ch;
|
extern volatile uint8_t msg_ch;
|
||||||
extern volatile uint8_t crc_h;
|
extern volatile uint8_t crc_h;
|
||||||
extern volatile uint8_t crc_l;
|
extern volatile uint8_t crc_l;
|
||||||
|
extern volatile bool send_blocked;
|
||||||
|
|
||||||
|
static volatile bool need_send_angle = false;
|
||||||
|
static volatile bool need_send_velocity = false;
|
||||||
|
|
||||||
void send_velocity();
|
void send_velocity();
|
||||||
void send_angle();
|
void send_angle();
|
||||||
|
@ -19,10 +25,12 @@ void send_motor_enabled();
|
||||||
void send_id();
|
void send_id();
|
||||||
void firmware_update();
|
void firmware_update();
|
||||||
void send_pid_angle(uint8_t param_pid);
|
void send_pid_angle(uint8_t param_pid);
|
||||||
void send_torque();
|
void send_with_confirmation(void (*send_func)(void));
|
||||||
|
// void send_torque();
|
||||||
void send_pid(uint8_t param_pid);
|
void send_pid(uint8_t param_pid);
|
||||||
void setup_id(uint8_t my_id);
|
void setup_id(uint8_t my_id);
|
||||||
void setup_angle(float target_angle);
|
void setup_angle(float target_angle);
|
||||||
void setup_velocity(float target_velocity);
|
void setup_velocity(float target_velocity);
|
||||||
|
void process_can_messages();
|
||||||
|
|
||||||
void listen_can(const CAN_message_t &msg);
|
void listen_can(const CAN_message_t &msg);
|
||||||
|
|
|
@ -30,7 +30,7 @@ uint8_t flag_can = 0;
|
||||||
uint32_t flash_error;
|
uint32_t flash_error;
|
||||||
FLASH_EraseInitTypeDef pEraseInit;
|
FLASH_EraseInitTypeDef pEraseInit;
|
||||||
uint32_t SectorError;
|
uint32_t SectorError;
|
||||||
|
uint32_t timeout;
|
||||||
|
|
||||||
/* bool for test CAN */
|
/* bool for test CAN */
|
||||||
volatile bool CAN_GET = false;
|
volatile bool CAN_GET = false;
|
||||||
|
@ -95,26 +95,22 @@ MotorControlInputs motor_control_inputs;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_can_busy() {
|
||||||
|
return (CAN2->TSR & (CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2)) != 0x07;
|
||||||
void loop() {
|
|
||||||
__enable_irq();
|
|
||||||
send_angle();
|
|
||||||
send_velocity();
|
|
||||||
foc_step(&motor);
|
|
||||||
CAN_message_t msg;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Process incoming CAN messages
|
|
||||||
while (Can.read(msg)) {
|
|
||||||
listen_can(msg);
|
|
||||||
CAN_GET = true;
|
|
||||||
}
|
|
||||||
/* If receive data from CAN */
|
|
||||||
if(CAN_GET) {
|
|
||||||
|
|
||||||
CAN_GET = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
process_can_messages();
|
||||||
|
|
||||||
|
static uint32_t last_send = 0;
|
||||||
|
if(!send_blocked && !is_can_busy() && (HAL_GetTick() - last_send >= 50)) {
|
||||||
|
send_angle();
|
||||||
|
send_velocity();
|
||||||
|
last_send = HAL_GetTick();
|
||||||
|
}
|
||||||
|
|
||||||
|
foc_step(&motor);
|
||||||
|
HAL_Delay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
|
|
||||||
static CAN_message_t CAN_TX_msg;
|
static CAN_message_t CAN_TX_msg;
|
||||||
static CAN_message_t CAN_inMsg;
|
static CAN_message_t CAN_inMsg;
|
||||||
|
static uint8_t data_type = DATA_TYPE_ANGLE;
|
||||||
|
volatile bool send_blocked = false;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void send_can_with_id_crc(uint8_t id, uint8_t message_type, T* data) {
|
void send_can_with_id_crc(uint8_t id, uint8_t message_type, T* data) {
|
||||||
// Create CAN message
|
// Create CAN message
|
||||||
|
@ -44,7 +44,7 @@ void send_velocity() {
|
||||||
uint8_t id = flash_rec[addr_id].value;
|
uint8_t id = flash_rec[addr_id].value;
|
||||||
send_can_with_id_crc(id,'V',¤t_velocity);
|
send_can_with_id_crc(id,'V',¤t_velocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_angle() {
|
void send_angle() {
|
||||||
float current_angle = motor.shaftAngle();
|
float current_angle = motor.shaftAngle();
|
||||||
if (flash_rec == nullptr) { // Null check
|
if (flash_rec == nullptr) { // Null check
|
||||||
|
@ -68,13 +68,13 @@ void send_motor_enabled() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void send_torque() {
|
// void send_torque() {
|
||||||
float i_q = motor.current.q; // Q-axis current (A)
|
// float i_q = motor.current.q; // Q-axis current (A)
|
||||||
float torque = 100 * i_q; // Torque calculation
|
// float torque = 100 * i_q; // Torque calculation
|
||||||
if (flash_rec == nullptr) return;
|
// if (flash_rec == nullptr) return;
|
||||||
uint8_t id = flash_rec[addr_id].value;
|
// uint8_t id = flash_rec[addr_id].value;
|
||||||
send_can_with_id_crc(id, 'T', &torque);
|
// send_can_with_id_crc(id, 'T', &torque);
|
||||||
}
|
// }
|
||||||
|
|
||||||
void send_id() {
|
void send_id() {
|
||||||
/* Firmware data reading */
|
/* Firmware data reading */
|
||||||
|
@ -147,6 +147,39 @@ void send_data_type(uint8_t type_d){
|
||||||
send_can_with_id_crc(id,'D',&type_d);
|
send_can_with_id_crc(id,'D',&type_d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Вспомогательные функции
|
||||||
|
void send_with_confirmation(void (*send_func)(void)) {
|
||||||
|
uint32_t t_start = HAL_GetTick();
|
||||||
|
send_func();
|
||||||
|
|
||||||
|
// Ожидание подтверждения отправки
|
||||||
|
while (!(CAN2->TSR & (CAN_TSR_RQCP0 | CAN_TSR_RQCP1 | CAN_TSR_RQCP2))) {
|
||||||
|
if (HAL_GetTick() - t_start > CAN_TIMEOUT) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_can_messages() {
|
||||||
|
static uint32_t last_received = HAL_GetTick();
|
||||||
|
CAN_message_t msg;
|
||||||
|
uint8_t count = 0;
|
||||||
|
|
||||||
|
// block send while data cant
|
||||||
|
send_blocked = true;
|
||||||
|
|
||||||
|
// Чтение сообщений с ограничением
|
||||||
|
while(count < MAX_CAN_READS && Can.read(msg)) {
|
||||||
|
listen_can(msg);
|
||||||
|
last_received = HAL_GetTick();
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверка таймаута молчания
|
||||||
|
if(HAL_GetTick() - last_received > CAN_SILENCE_TIMEOUT) {
|
||||||
|
// Разблокируем отправку при отсутствии сообщений
|
||||||
|
send_blocked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Function for process data from CAN
|
* @brief Function for process data from CAN
|
||||||
* @details Function check your ID deviceю. Compare receive and calculated CRC.
|
* @details Function check your ID deviceю. Compare receive and calculated CRC.
|
||||||
|
@ -160,8 +193,7 @@ void send_data_type(uint8_t type_d){
|
||||||
void listen_can(const CAN_message_t &msg) {
|
void listen_can(const CAN_message_t &msg) {
|
||||||
msg_id = msg.id;
|
msg_id = msg.id;
|
||||||
msg_ch = msg_id & 0xF; // Extract message channel
|
msg_ch = msg_id & 0xF; // Extract message channel
|
||||||
uint16_t id_x = (msg_id >> 4) & 0x7FF; // Extract device address
|
uint16_t id_x = (msg_id >> 4) & 0x7FF; // Extract device address
|
||||||
uint8_t data_type = 1; //type for work with foc
|
|
||||||
/* CRC Calculation */
|
/* CRC Calculation */
|
||||||
uint16_t received_crc = (msg.buf[msg.len - 2]) | (msg.buf[msg.len - 1] << 8);
|
uint16_t received_crc = (msg.buf[msg.len - 2]) | (msg.buf[msg.len - 1] << 8);
|
||||||
uint8_t data[10] = {0}; // Message buffer for CRC verification
|
uint8_t data[10] = {0}; // Message buffer for CRC verification
|
||||||
|
@ -271,7 +303,8 @@ void listen_can(const CAN_message_t &msg) {
|
||||||
switch(data_type) {
|
switch(data_type) {
|
||||||
/* Read after write*/
|
/* Read after write*/
|
||||||
case DATA_TYPE_ANGLE:
|
case DATA_TYPE_ANGLE:
|
||||||
send_angle();
|
send_angle();
|
||||||
|
delay(200);
|
||||||
memcpy(&motor_control_inputs.target_angle, &msg.buf[1], sizeof(float));
|
memcpy(&motor_control_inputs.target_angle, &msg.buf[1], sizeof(float));
|
||||||
setup_angle(motor_control_inputs.target_angle);
|
setup_angle(motor_control_inputs.target_angle);
|
||||||
break;
|
break;
|
||||||
|
@ -285,7 +318,7 @@ void listen_can(const CAN_message_t &msg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case DATA_TYPE_TORQUE:
|
case DATA_TYPE_TORQUE:
|
||||||
send_torque();
|
// send_torque();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -1,12 +1,23 @@
|
||||||
import can
|
import can
|
||||||
import time
|
import time
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
# Конфигурация
|
# Конфигурация
|
||||||
CAN_INTERFACE = 'can0'
|
CAN_INTERFACE = 'can0'
|
||||||
OLD_DEVICE_ID = int(sys.argv[1]) # Текущий ID устройства (по умолчанию)
|
OLD_DEVICE_ID = int(sys.argv[1]) # Текущий ID устройства
|
||||||
REG_READ = 0x7 # Код команды чтения
|
REG_READ = 0x7 # Код команды чтения
|
||||||
REG_ID = 0x01 # Адрес регистра с ID устройства
|
REG_ID = 0x01 # Адрес регистра с ID устройства
|
||||||
|
|
||||||
|
def flush_can_buffer(bus, duration=0.3):
|
||||||
|
"""Очистка входного буфера CAN"""
|
||||||
|
start_time = time.time()
|
||||||
|
flushed_count = 0
|
||||||
|
while time.time() - start_time < duration:
|
||||||
|
msg = bus.recv(timeout=0)
|
||||||
|
if msg:
|
||||||
|
flushed_count += 1
|
||||||
|
print(f"Очищено сообщений из буфера: {flushed_count}")
|
||||||
|
|
||||||
def send_can_message(bus, can_id, data):
|
def send_can_message(bus, can_id, data):
|
||||||
"""Отправка CAN-сообщения"""
|
"""Отправка CAN-сообщения"""
|
||||||
try:
|
try:
|
||||||
|
@ -23,14 +34,14 @@ def send_can_message(bus, can_id, data):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def receive_response(bus, timeout=1.0):
|
def receive_response(bus, timeout=1.0):
|
||||||
"""Ожидание ответа от устройства"""
|
"""Ожидание ответа от устройства (сохраняем вашу оригинальную логику)"""
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
while time.time() - start_time < timeout:
|
while time.time() - start_time < timeout:
|
||||||
msg = bus.recv(timeout=0.1)
|
msg = bus.recv(timeout=0.1)
|
||||||
if msg:
|
if msg:
|
||||||
print(f"[Прием] CAN ID: 0x{msg.arbitration_id:03X}, Данные: {list(msg.data)}")
|
print(f"[Прием] CAN ID: 0x{msg.arbitration_id:03X}, Данные: {list(msg.data)}")
|
||||||
return msg
|
return msg
|
||||||
print("[Ошибка] Таймаут")
|
print("[Ошибка] Таймаут приема")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def validate_crc16(data):
|
def validate_crc16(data):
|
||||||
|
@ -45,64 +56,91 @@ def validate_crc16(data):
|
||||||
crc >>= 1
|
crc >>= 1
|
||||||
return crc
|
return crc
|
||||||
|
|
||||||
# Инициализация CAN-интерфейса
|
def main():
|
||||||
bus = can.interface.Bus(channel=CAN_INTERFACE, bustype='socketcan')
|
# Инициализация CAN-интерфейса
|
||||||
|
try:
|
||||||
|
bus = can.interface.Bus(
|
||||||
|
channel=CAN_INTERFACE,
|
||||||
|
bustype='socketcan',
|
||||||
|
bitrate=1000000 # Совпадает с устройством
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Ошибка инициализации CAN: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
# ======= 1. Запрос текущего ID устройства =======
|
# ======= 1. Подготовка запроса =======
|
||||||
|
can_id_read = (OLD_DEVICE_ID << 4) | REG_READ
|
||||||
|
data_read = [REG_ID, 0x00]
|
||||||
|
|
||||||
|
# Формируем полные данные для расчета CRC:
|
||||||
|
full_data_for_crc = list(can_id_read.to_bytes(2, 'little')) + data_read
|
||||||
|
|
||||||
|
# Рассчитываем CRC
|
||||||
|
crc = validate_crc16(full_data_for_crc)
|
||||||
|
crc_bytes = list(crc.to_bytes(2, 'little'))
|
||||||
|
|
||||||
|
# Собираем итоговый пакет
|
||||||
|
packet_read = data_read + crc_bytes
|
||||||
|
|
||||||
# Формируем CAN ID для чтения: (OLD_DEVICE_ID << 4) | REG_READ
|
# ======= 2. Отправка запроса с повторами =======
|
||||||
can_id_read = (OLD_DEVICE_ID << 4) | REG_READ
|
max_retries = 3
|
||||||
|
response = None
|
||||||
# Данные для запроса: [регистр, резервный байт]
|
|
||||||
data_read = [REG_ID, 0x00]
|
for attempt in range(max_retries):
|
||||||
|
print(f"\nПопытка {attempt+1}/{max_retries}")
|
||||||
# Формируем полные данные для расчета CRC:
|
|
||||||
# - CAN ID разбивается на 2 байта (little-endian)
|
# Очистка буфера перед отправкой
|
||||||
# - Добавляем данные запроса
|
flush_can_buffer(bus, 0.3)
|
||||||
full_data_for_crc = list(can_id_read.to_bytes(2, 'little')) + data_read
|
|
||||||
|
# Отправка запроса
|
||||||
# Рассчитываем CRC и разбиваем на байты (little-endian)
|
print(f"Отправка запроса на чтение ID: {packet_read}")
|
||||||
crc = validate_crc16(full_data_for_crc)
|
if not send_can_message(bus, can_id_read, packet_read):
|
||||||
crc_bytes = list(crc.to_bytes(2, 'little'))
|
print("Ошибка отправки, повтор...")
|
||||||
|
time.sleep(0.2)
|
||||||
# Собираем итоговый пакет: данные + CRC
|
continue
|
||||||
packet_read = data_read + crc_bytes
|
|
||||||
|
# Ожидание ответа
|
||||||
print("Запрос на чтение ID:", packet_read)
|
response = receive_response(bus, timeout=0.5)
|
||||||
send_can_message(bus, can_id_read, packet_read)
|
if response:
|
||||||
|
break
|
||||||
# ======= 2. Получение и проверка ответа =======
|
|
||||||
response = receive_response(bus)
|
print("Ответ не получен, повтор...")
|
||||||
if response:
|
time.sleep(0.2)
|
||||||
|
|
||||||
|
# ======= 3. Обработка ответа =======
|
||||||
|
if not response:
|
||||||
|
print("Устройство не ответило после всех попыток")
|
||||||
|
bus.shutdown()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
data = response.data
|
data = response.data
|
||||||
|
|
||||||
if len(data) < 4:
|
if len(data) < 4:
|
||||||
print("Слишком короткий ответ")
|
print("Слишком короткий ответ")
|
||||||
|
bus.shutdown()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
# Проверяем минимальную длину ответа (данные + CRC)
|
# Проверяем минимальную длину ответа (данные + CRC)
|
||||||
|
id_bytes = response.arbitration_id.to_bytes(1, byteorder='little')
|
||||||
|
full_data = list(id_bytes) + list(data[:-2])
|
||||||
|
print(f"Полные данные для CRC: {full_data}")
|
||||||
|
|
||||||
|
received_crc = int.from_bytes(data[-2:], byteorder='little')
|
||||||
|
calc_crc = validate_crc16(full_data)
|
||||||
|
|
||||||
|
print(f"Расчитанный CRC: 0x{calc_crc:04X}, Полученный CRC: 0x{received_crc:04X}")
|
||||||
|
|
||||||
|
if received_crc == calc_crc:
|
||||||
|
print(f"Текущий ID устройства: 0x{data[1]:02X}")
|
||||||
else:
|
else:
|
||||||
id_bytes = response.arbitration_id.to_bytes(1,byteorder='little')
|
print("Ошибка: CRC не совпадает")
|
||||||
#buff with id and data without CRC
|
|
||||||
full_data = list(id_bytes) + list(data[:-2])
|
# Завершаем работу с шиной
|
||||||
print(f"Received full_data: {list(full_data)}")
|
bus.shutdown()
|
||||||
received_crc = int.from_bytes(data[-2:], byteorder='little')
|
|
||||||
#calc CRC
|
|
||||||
calc_crc = validate_crc16(full_data)
|
|
||||||
|
|
||||||
print(f"Расчитанный CRC PYTHON : 0x{calc_crc:02X}")
|
|
||||||
if received_crc == calc_crc:
|
|
||||||
# Если CRC совпадает, проверяем структуру ответа:
|
|
||||||
print(f"Текущий ID устройства: 0x{data[1]:02X}")
|
|
||||||
else:
|
|
||||||
print("Ошибка: CRC не совпадает")
|
|
||||||
else:
|
|
||||||
print("Устройство не ответило")
|
|
||||||
|
|
||||||
# Завершаем работу с шиной
|
|
||||||
bus.shutdown()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import sys
|
|
||||||
if len(sys.argv) != 2:
|
if len(sys.argv) != 2:
|
||||||
print("Использование: python3 can_flasher.py address")
|
print("Использование: python3 can_flasher.py <адрес_устройства>")
|
||||||
|
print("Пример: python3 can_flasher.py 1")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
main()
|
Loading…
Add table
Add a link
Reference in a new issue