czech english

vESC

open source BLDC motor driver

Výkonný driver pro jeden motor se spoustou nastaveni …

  • https://www.vandaelectronics.com/collections/electronic-speed-controls/products/vesc
  • zdrojáky na GitHubu
  • vESC moduly jsou 4 použity na Kloubákovi
  • na CAN používají rozšířenou adresaci 23 bitů (?), tj. nefunguje s tím naše stará verze CAN bridge
  • zpráva 0x90n, kde n je ID motoru obsahuje eRPM (32bit), proud v 0.1A (16bit) a Duty Cycle v tisícinách (16bit)
  • řízení je možné proudové (0x10n zprávy, 4 bajty v miliampérech) nebo s regulací otáček (0x30n, opět 4 bajty požadovaných eRPM).
  • brzda nefunguje, pokud není povolená rekuperace
  • brzdící příkazy jsou 0x20n, co ale znamenají 4 bajty nevíme jistě
  • je třeba mít poměrně vysoký cut off current, protože při jeho dosažení se proud srazí na nulu a samotný regulátor je nepoužitelný (teď nastaveno na 75A pro BLDC motory z howerboardu)

Vyčítání stavu tachometru/odometrie

CAN_PACKET_PROCESS_SHORT_BUFFER=8 — tj. na 0x8FF poslat [rx_buffer_last_id=0, commands_send=0, COMM_FW_VERSION=0] tj. [0, 0, 0]
Problém je, že jednotlivé vESCy se nedají rozlišit a odpovídají 0x5nn, kde nn je číslo posledního příkazu. Je ale možné poslat 0x801, 0x802, 0x803 a 0x804 a jako rx_buffer_last_id použít stejný index. Na 0x801 poslat [1, 0, 0].
Výsledná zpráva má 19 bajtů: [0, 3, 40, 52, 49, 48, 0, 37, 0, 44, 0, 22, 71, 55, 48, 51, 53, 56, 48] kde 3.40 je verze firmware.
Odometrie (resp. tacho motoru) lze získat vyčtením aktuálního stavu, který se ale pro různé verze firmware liší! V našem případě FW 3.40 ma 59 bajtů a zajímají nás 4 bajty od indexu=45.
Celý buffer je rozkouskován do osmibajtových zpráv, kde první bajt je index ve velkém bufferu a zbylých až sedm bajtů je obsah.

Verze

VESC verze co jsme zatím ve verzi 3.40 viděli měla 19 bajtů. V odpovídajícím command.c to tedy vypada, že HW_NAME byl definovaný a zpráva se skládá z:
send_buffer[ind + +] = COMM_FW_VERSION;
send_buffer[ind + +] = FW_VERSION_MAJOR;
send_buffer[ind + +] = FW_VERSION_MINOR;
strcpy((char*)(send_buffer + ind), HW_NAME);
ind += strlen(HW_NAME) + 1;
memcpy(send_buffer + ind, STM32_UUID_8, 12);
ind += 12;
[COMM_FW_VERSION=0, FW_VERSION_MAJOR=3, FW_VERSION_MINOR=40], pak je string ukončený nulou: [52, 49, 48, 0] = b'410\x00' a konečně unikátní 12 bajtový UUID … předpokládám něco jako seriové číslo?? 3 + 4 + 12 = 19, OK.
Ještě pro pořádek verze všech 4 motorů na Kloubákovi (K1):
[0, 3, 40,  52, 49, 48, 0,  37, 0, 44, 0, 22, 71, 55, 48, 51, 53, 56, 48]
[0, 3, 40,  52, 49, 48, 0,  35, 0, 30, 0, 22, 71, 55, 48, 51, 53, 56, 48]
[0, 3, 40,  52, 49, 48, 0,  36, 0, 52, 0, 22, 71, 55, 48, 51, 53, 56, 48]
[0, 3, 40,  52, 49, 48, 0,  53, 0, 36, 0,  4, 71, 55, 48, 51, 54, 56, 56]

Tacho

case COMM_GET_VALUES:
ind = 0;
send_buffer[ind + +] = COMM_GET_VALUES;
buffer_append_float16(send_buffer, mc_interface_temp_fet_filtered(), 1e1, &ind);
buffer_append_float16(send_buffer, mc_interface_temp_motor_filtered(), 1e1, &ind);
buffer_append_float32(send_buffer, mc_interface_read_reset_avg_motor_current(), 1e2, &ind);
buffer_append_float32(send_buffer, mc_interface_read_reset_avg_input_current(), 1e2, &ind);
buffer_append_float32(send_buffer, mc_interface_read_reset_avg_id(), 1e2, &ind);
buffer_append_float32(send_buffer, mc_interface_read_reset_avg_iq(), 1e2, &ind);
buffer_append_float16(send_buffer, mc_interface_get_duty_cycle_now(), 1e3, &ind);
buffer_append_float32(send_buffer, mc_interface_get_rpm(), 1e0, &ind);
buffer_append_float16(send_buffer, GET_INPUT_VOLTAGE(), 1e1, &ind);
buffer_append_float32(send_buffer, mc_interface_get_amp_hours(false), 1e4, &ind);
buffer_append_float32(send_buffer, mc_interface_get_amp_hours_charged(false), 1e4, &ind);
buffer_append_float32(send_buffer, mc_interface_get_watt_hours(false), 1e4, &ind);
buffer_append_float32(send_buffer, mc_interface_get_watt_hours_charged(false), 1e4, &ind);
buffer_append_int32(send_buffer, mc_interface_get_tachometer_value(false), &ind);
buffer_append_int32(send_buffer, mc_interface_get_tachometer_abs_value(false), &ind);
send_buffer[ind + +] = mc_interface_get_fault();
buffer_append_float32(send_buffer, mc_interface_get_pid_pos_now(), 1e6, &ind);
send_buffer[ind + +] = app_get_configuration()->controller_id;
commands_send_packet(send_buffer, ind);
break;
1 + 2*2 + 4*4 + 2 + 4 + 2 + 4*4 + 2*4 + 1 + 4 + 1 = 59, takže velikost zprávy sedí.
Nás primárně zajímá int32 mc_interface_get_tachometer_value, který je na pozici 45, hmm to bohužel nesedí. Co mi zatím dávalo smysl byl následující mc_interface_get_tachometer_abs_value — že by to byl „absolutní encoder” a nikoli nasčítané absolutní hodnoty (míněno, pokud jede motor tam a zpět, tak v prvním případě dostane nulu a ve druhém se započtou obě ujeté vzálenosti).
mcpwm.c
int tacho_diff = (step - last_step) % 6;
…
tachometer_abs += tacho_diff;

if (direction) {
  tachometer += tacho_diff;
} else {
  tachometer -= tacho_diff;
}
… to skoro vypada, že „tachometer” je celková ujetá vzdálenost a „tachometer_abs” je celkový znamínkový součet.