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.