Control with Python

We describe the VESC control method using python.

1. Using CAN Custom Control Message

English
Korean
English

โ€‹

Korean

VESC์—์„œ ์‚ฌ์šฉํ•˜๋Š” CAN ํ†ต์‹  ๋ฉ”์‹œ์ง€์ค‘, CAN FORWARD ๊ธฐ๋Šฅ์— ์ด์šฉ๋˜๋Š” CAN PACKET ID๊ฐ€ ์žˆ๋‹ค. ์ด๋Š” ์•„๋ž˜ 'CAN_PACKET_ID' ์ค‘, 5์— ํ•ด๋‹นํ•˜๋Š” 'CAN_PACKET_FILL_RX_BUFFER' ์™€ 7์— ํ•ด๋‹นํ•˜๋Š” 'CAN_PACKET_PROCESS_RX_BUFFER' ๋ฅผ ์ด์šฉํ•˜๋ฉด ๋ชฉ VESC์— ์ž„์˜์˜ ๋ช…๋ น์–ด๋ฅผ ์ „์†กํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ์ด๋Š” ๊ธฐ์กด์— ์ „๋ฅ˜, Duty, ์œ„์น˜, ์†๋„ ๋“ฑ์˜ ์œ„์น˜๋ช…๋ น์„ ์„œ๋กœ ๋‹ค๋ฅธ CAN Message๋กœ ์ฒ˜๋ฆฌํ•˜๋˜ ๋ฐฉ์‹์—์„œ, ํŠน์ • VESC ID์— ์ž„์˜์˜ ๋ช…๋ น์„ ํ•˜๋‚˜์˜ ํ†ต์ผ๋œ CAN Message ํ˜•ํƒœ๋กœ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค. ๋‹จ, ๊ธฐ์กด ๋ฐฉ๋ฒ•์— ๋น„ํ•ด Message์˜ ๊ธธ์ด๊ฐ€ ๋‹ค์†Œ ๋Š˜์–ด๋‚˜๋Š” ๋‹จ์ ์€ ์žˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์šฐ๋ฆฌ๋Š” ์ด๋Ÿฌํ•œ ๋ฐฉ์‹์„ CAN Custom Control Message ์ „์†ก ๋ฐฉ์‹์œผ๋กœ ๋ถ€๋ฅด๋„๋ก ํ•œ๋‹ค.

// CAN commands
typedef enum {
CAN_PACKET_SET_DUTY = 0,
CAN_PACKET_SET_CURRENT,
CAN_PACKET_SET_CURRENT_BRAKE,
CAN_PACKET_SET_RPM,
CAN_PACKET_SET_POS,
CAN_PACKET_FILL_RX_BUFFER,
CAN_PACKET_FILL_RX_BUFFER_LONG,
CAN_PACKET_PROCESS_RX_BUFFER,
CAN_PACKET_PROCESS_SHORT_BUFFER,
CAN_PACKET_STATUS,
CAN_PACKET_SET_CURRENT_REL,
CAN_PACKET_SET_CURRENT_BRAKE_REL,
CAN_PACKET_SET_CURRENT_HANDBRAKE,
CAN_PACKET_SET_CURRENT_HANDBRAKE_REL,
CAN_PACKET_STATUS_2,
CAN_PACKET_STATUS_3,
CAN_PACKET_STATUS_4,
CAN_PACKET_PING,
CAN_PACKET_PONG,
CAN_PACKET_DETECT_APPLY_ALL_FOC,
CAN_PACKET_DETECT_APPLY_ALL_FOC_RES,
CAN_PACKET_CONF_CURRENT_LIMITS,
CAN_PACKET_CONF_STORE_CURRENT_LIMITS,
CAN_PACKET_CONF_CURRENT_LIMITS_IN,
CAN_PACKET_CONF_STORE_CURRENT_LIMITS_IN,
CAN_PACKET_CONF_FOC_ERPMS,
CAN_PACKET_CONF_STORE_FOC_ERPMS,
CAN_PACKET_STATUS_5,
CAN_PACKET_POLL_TS5700N8501_STATUS,
CAN_PACKET_CONF_BATTERY_CUT,
CAN_PACKET_CONF_STORE_BATTERY_CUT,
CAN_PACKET_SHUTDOWN,
CAN_PACKET_IO_BOARD_ADC_1_TO_4,
CAN_PACKET_IO_BOARD_ADC_5_TO_8,
CAN_PACKET_IO_BOARD_ADC_9_TO_12,
CAN_PACKET_IO_BOARD_DIGITAL_IN,
CAN_PACKET_IO_BOARD_SET_OUTPUT_DIGITAL,
CAN_PACKET_IO_BOARD_SET_OUTPUT_PWM,
CAN_PACKET_BMS_V_TOT,
CAN_PACKET_BMS_I,
CAN_PACKET_BMS_AH_WH,
CAN_PACKET_BMS_V_CELL,
CAN_PACKET_BMS_BAL,
CAN_PACKET_BMS_TEMPS,
CAN_PACKET_BMS_HUM,
CAN_PACKET_BMS_SOC_SOH_TEMP_STAT
} CAN_PACKET_ID;

CAN Custom Control Message ์ „์†ก ๋ฐฉ์‹์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค. ์•„๋ž˜๋Š” USBํ†ต์‹ ์„ ํ†ตํ•ด CAN Custom Control Message ์ „์†ก ๋ฐฉ์‹์œผ๋กœ ๋ณด๋‚ด์ง„ ๋ฐ์ดํ„ฐ์˜ ์˜ˆ๋กœ ์ด๋ฅผ ํ•ด์„ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

์ฒซ๋ฒˆ์งธ, ๋‘๋ฒˆ์งธ ๋ฉ”์„ธ์ง€ ํ•ด์„
์„ธ๋ฒˆ์งธ ๋ฉ”์„ธ์ง€ ํ•ด์„

์•ž์„  USB๋ฅผ ํ†ตํ•ด ์ „์†ก๋œ CAN Custom Control Message์˜ ํ•ด์„๊ฒฐ๊ณผ 101๋ฒˆ ๋ชจํ„ฐ์— DPS ์ œ์–ด๋ฅผ ๊ฐ€ํ•˜๋Š” ๋ช…๋ น์–ด์ž„์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ CAN Custom Control Message์˜ ํฌ๋ฉง์„ ์ƒ๊ฐํ•ด๋ณผ ์ˆ˜ ์žˆ๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ˜•ํƒœ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

๋ณ€์ˆ˜

๋‚ด์šฉ

ID

๋ชฉ์ ํ•˜๋Š” VESC ID์˜ Hex ๊ฐ’

CS

์ œ์–ด๋ฐฉ์‹์„ ๋‚˜ํƒ€๋‚ด๋Š” COMM_PACKET_ID ์˜ Hex ๊ฐ’

D1 D2 D3 D4

์ œ์–ด ๋ชฉํ‘œ๊ฐ’์˜ Hex ๊ฐ’.

4Byte๋กœ ์ „์†ก๋˜๊ณ  ์ œ์–ด๋ฐฉ์‹์— ๋”ฐ๋ฅธ ์œ ํšจ์ˆซ์ž ๋ณ€๊ฒฝ์„ ์œ„ํ•ด

์ œ์–ด๋ฐฉ์‹์— 10^n ๋ฐฐ๋ฅผ ํ•˜์—ฌ ๋ณด๋‚ด๊ณ , ๋ฐ›๋Š” ์ชฝ์—์„œ 10^n ๋ฐฐ๋กœ ๋‚˜๋ˆ  ์‚ฌ์šฉ.

CRCH CRCL

CRC Check Sum์˜ Hex๊ฐ’. ์ƒ์œ„ 1Byte(CRCH)์™€ ํ•˜์œ„ 1Byte(CRCL)๋กœ ๊ตฌ์„ฑ๋จ

์ œ์–ด๋ฐฉ์‹(COMM_PACKET_ID)์— ์•„๋ž˜ ๋‚˜์—ด๋œ ์ œ์–ด ๋ช…๋ น์–ด๋“ค์ด ์‚ฌ์šฉ๊ฐ€๋Šฅํ•˜๋‹ค.

COMM_PACKET_ID

๊ฐ’ (Hex)

์œ ํšจ์ˆซ์ž 10^n ๋ฐฐ

COMM_SET_DUTY

5 (0x05)

100000.0

COMM_SET_CURRENT

6 (0x06)

1000.0

COMM_SET_CURRENT_BRAKE

7 (0x07)

1000.0

COMM_SET_RELEASE

100 (0x64)

1

COMM_SET_DPS

101 (0x65)

1000.0

COMM_SET_DPS_VMAX

102 (0x66)

1000.0

COMM_SET_DPS_AMAX

103 (0x67)

1000.0

COMM_SET_SERVO

104 (0x68)

1000.0

COMM_SET_TRAJ

105 (0x69)

1000.0

D1 D2 D3 D4 ์— ์‹ค๋ ค ๋ณด๋‚ด์ง€๋Š” ๊ฐ’์€ ์œ ํšจ์ˆซ์ž 10^n ๋ฐฐ๋ฅผ ๊ณฑํ•œ ๊ฐ’์„ ๋ณด๋‚ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ›๋Š” ์ชฝ์—์„œ ๋™์ผํ•œ ๊ฐ’์œผ๋กœ ๋‚˜๋ˆ ์ค˜์•ผ ๋ฌผ๋ฆฌ์ ์œผ๋กœ ์˜๋ฏธ์žˆ๋Š” ์ˆซ์ž๋กœ ๋ณ€ํ™˜๋จ์„ ์ฃผ์˜ํ•ด์•ผํ•œ๋‹ค.

๋ชจํ„ฐ์˜ ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ์ œ์–ด์ธ Duty์ œ์–ด๋ฅผ ์œ„ํ•ด์„œ๋Š” COMM_SET_DUTY๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์ด๋•Œ Duty๊ฐ’์€ 1์ด 100% ๋“€ํ‹ฐ๋ฅผ, 0์ด 0%๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

์ „๋ฅ˜์ œ์–ด๋ฅผ ์œ„ํ•ด์„œ COMM_SET_CURRENT๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์ด๋•Œ ์ œ์–ด๊ฐ’์˜ ๋‹จ์œ„๋Š” A(์•”ํŽ˜์–ด)๊ฐ’์„ ์ „์†กํ•œ๋‹ค. ์ „๋ฅ˜์ œ์–ด๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ชจํ„ฐ์— Brake๋ฅผ ์ธ๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ ์ด๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด COMM_SET_CURRENT_BRAKE ์ด๋‹ค. A ๋‹จ์œ„๋กœ ๊ฐ’์„ ์ „์†กํ•œ๋‹ค.

๋ชจํ„ฐ์˜ ์†๋„์ œ์–ด๋ฅผ ์œ„ํ•ด์„œ๋Š” COMM_SET_DPS๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. Degree ๋‹จ์œ„์˜ ๊ฐ’์„ ์ „์†กํ•ด์•ผํ•˜๋ฉฐ 100 DPS๋ฅผ ์ „์†กํ•˜๋ฉด ์ดˆ๋‹น 100degree์˜ ์†๋„๋กœ ํšŒ์ „ํ•œ๋‹ค. ์ด๋•Œ ํšŒ์ „ ๊ฐ€์†๋„๋Š” COMM_SET_DPS_AMAX (deg/sec^2)์—์„œ ์„ค์ •ํ•œ ๊ฐ’์„ ๋”ฐ๋ฅด๋ฉฐ ํšŒ์ „ ์ตœ๊ณ  ์†๋„๋Š” COMM_SET_DPS_VMAX (deg/sec)์œผ๋กœ ์ œํ•œ๋œ๋‹ค. ๋ณธ ์†๋„์ œ์–ด๋Š” ๊ฐ•๋ ฅํ•œ Gain์˜ ์œ„์น˜์ œ์–ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์†๋„ Reference๋ฅผ ์‚ฌ๋‹ค๋ฆฌ๊ผด ์†๋„ Profile์— ์˜ํ•ด ์ƒ์„ฑํ•˜์—ฌ ์ œ์–ดํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์ €์†์—์„œ๋„ ๊ณ ํ† ํฌ, ๊ณ ์ •๋ฐ€๋„ ์ œ์–ด๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

๋ชจํ„ฐ์˜ ์ ˆ๋Œ€ ์œ„์น˜์ œ์–ด๋Š” COMM_SET_SERVO๋ฅผ ์ด์šฉํ•˜๊ณ  ์ด๋•Œ ์ „์†กํ•˜๋Š” ๊ฐ’์€ ์—”์ฝ”๋”์˜ ์ ˆ๋Œ€ ์œ„์น˜ ๊ฐ๋„๊ฐ’์„ degree ๋‹จ์œ„๋กœ ์ „์†กํ•œ๋‹ค. COMM_SET_SERVO๋ฅผ ์ด์šฉํ•˜๋ฉด ์ธ๊ฐ€ํ•œ ์ ˆ๋Œ€์œ„์น˜๋ฅผ ๊ธฐ์กด์— ์„ค์ •ํ•œ ์†๋„ ์ตœ๋Œ€๊ฐ’ (COMM_SET_DPS_VMAX )์— ๋”ฐ๋ผ ๋ชฉํ‘œ์œ„์น˜๋กœ ์ด๋™ํ•œ๋‹ค. ํŽŒ์›จ์–ด์ƒ์— ๊ธฐ๋ณธ์ ์œผ๋กœ COMM_SET_DPS_VMAX ๊ฐ’์€ ์ตœ๋Œ€๋กœ ์„ค์ •ํ•ด๋†“์•˜์œผ๋ฏ€๋กœ Application ์ƒํ™ฉ์— ๋”ฐ๋ผ ์ด๋ฅผ ๋ฏธ๋ฆฌ ์กฐ์ ˆ ํ›„, COMM_SET_SERVO์„ ์ธํ•˜ํ•ด์•ผ ์•ˆ์ „ํ•˜๋‹ค.

๋‹จ์ˆœํžˆ, Position Lock ๊ธฐ๋Šฅ์„ ์›ํ•œ๋‹ค๋ฉด COMM_SET_DPS ์— ๋ชฉํ‘œ๊ฐ’์„ 0์œผ๋กœ ์„ค์ •ํ•ด๋†“์œผ๋ฉด ํ˜„์žฌ ์—”์ฝ”๋” ์œ„์น˜์—์„œ Position Lock์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ์ดํ›„ ๋ชจํ„ฐ๋ฅผ Release ํ•˜๊ณ  ์‹ถ์„ ๋•Œ๋Š” COMM_SET_RELEASE ๋ช…๋ น์–ด๋ฅผ ์ด์šฉํ•˜๋ฉด ๋˜๊ณ  ๋ชฉํ‘œ๊ฐ’์€ ๊ธฐ๋ณธ 0์œผ๋กœ ์„ค์ •ํ•˜๋ฉด ๋œ๋‹ค.

COMM_SET_TRAJ ๋Š” ์‚ฌ๋‹ค๋ฆฌ๊ผด ์†๋„ Profile์— ๋”ฐ๋ผ ์œ„์น˜๋ช…๋ น๊ฐ’์„ ์ƒ์„ฑํ•˜์—ฌ ์œ„์น˜์ œ์–ด๋ฅผ ํ•˜๋Š”๋ฐ Manipulator์˜ ์œ„์น˜์ œ์–ด์‹œ ๋ชฉํ‘œ์ง€์ ๊นŒ์ง€ ๋ถ€๋“œ๋Ÿฌ๊ฒŒ ์›€์ง์ด๊ณ  ์‹ถ์„ ๋•Œ ์ฃผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ง€๊ธˆ๊นŒ์ง€ ์„ค๋ช…ํ•œ CAN Custom Control Message ์ „์†ก๋ฐฉ์‹์„ Python Code๋กœ ์•„๋ž˜ ์ž‘์„ฑํ•˜์—ฌ ๋‚˜ํƒ€๋‚ด์—ˆ๋‹ค. CAN ๋ฉ”์„ธ์ง€ ์ „์†ก์„ ์œ„ํ•ด Peak System์‚ฌ์˜ PCAN-USB๋ฅผ ์ด์šฉํ•˜์˜€์œผ๋ฉฐ PCANBasic.py ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•˜์˜€๋‹ค. CRC Check Sum ๊ณ„์‚ฐ์„ ์œ„ํ•ด์„œ๋Š” VESC ํŽŒ์›จ์–ด์—์„œ ์ œ๊ณตํ•˜๋Š” c์–ธ์–ด๋กœ ์ž‘์„ฑ๋œ crc.c, crc.h ์„ dll ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์ปดํŒŒ์ผ ํ•˜์—ฌ ํŒŒ์ด์ฌ์—์„œ importํ•˜์—ฌ ์‚ฌ์šฉํ•˜์˜€๋‹ค. VESC์—์„œ๋Š” crc.c ํŒŒ์ผ์— crc table์ด ์ €์žฅ์ด ๋˜์–ด์žˆ์–ด ์ผ๋ฐ˜์ ์ธ crc ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์•„๋‹Œ VESC ํŽŒ์›จ์–ด์ƒ์— ์žˆ๋Š” crc.c ํŒŒ์ผ์„ ๊ทธ๋Œ€๋กœ ์ด์šฉํ•ด์•ผ ํ•œ๋‹ค. ํŒŒ์ด์ฌ ์ฝ”๋“œ๋Š” ์•„๋ž˜ ์ฃผ์†Œ์—์„œ ํ™•์ธ ๊ฐ€๋Šฅํ•˜๋ฉฐ ๊ด€๋ จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋˜ํ•œ ํ•ด๋‹น Repository์— ์กด์žฌํ•œ๋‹ค..

โ€‹https://github.com/dongilc/PCAN/tree/main/PCAN-Basic%20API/Samples/Pythonโ€‹

from PCANBasic import *
โ€‹
'''
# crc check program from vesc firmware, dll file generated by below command
> gcc -fPIC -c crc.c
> gcc --shared -ocrc_vesc.dll crc.o
'''
import ctypes
crc_vesc = ctypes.cdll.LoadLibrary('./crc_vesc.dll')
โ€‹
can_packet_id = {
'CAN_PACKET_SET_DUTY':0,
'CAN_PACKET_SET_CURRENT':1,
'CAN_PACKET_SET_CURRENT_BRAKE':2,
'CAN_PACKET_SET_RPM':3,
'CAN_PACKET_SET_POS':4,
'CAN_PACKET_FILL_RX_BUFFER':5,
'CAN_PACKET_FILL_RX_BUFFER_LONG':6,
'CAN_PACKET_PROCESS_RX_BUFFER':7,
'CAN_PACKET_PROCESS_SHORT_BUFFER':8,
'CAN_PACKET_STATUS':9
}
โ€‹
comm_set_custom = {
'COMM_SET_DUTY':5,
'COMM_SET_CURRENT':6,
'COMM_SET_CURRENT_BRAKE':7,
'COMM_SET_RELEASE':100,
'COMM_SET_DPS':101,
'COMM_SET_DPS_VMAX':102,
'COMM_SET_DPS_AMAX':103,
'COMM_SET_SERVO':104,
'COMM_SET_TRAJ':105
}
โ€‹
global pc1
โ€‹
time_prev = 0
msg_type = {'0x0':'PCAN_MESSAGE_STANDARD',
'0x00':'PCAN_MESSAGE_STANDARD',
'0x1':'PCAN_MESSAGE_RTR',
'0x01':'PCAN_MESSAGE_RTR',
'0x2':'PCAN_MESSAGE_EXTENDED',
'0x02':'PCAN_MESSAGE_EXTENDED',
'0x4':'PCAN_MESSAGE_FD',
'0x04':'PCAN_MESSAGE_FD',
'0x8':'PCAN_MESSAGE_BRS',
'0x08':'PCAN_MESSAGE_BRS',
'0x10':'PCAN_MESSAGE_ESI',
'0x40':'PCAN_MESSAGE_ERRFRAME',
'0x80':'PCAN_MESSAGE_STATUS'}
โ€‹
โ€‹
def pcan_Open():
result = pc1.Initialize(PCAN_USBBUS1, PCAN_BAUD_1M)
if result != PCAN_ERROR_OK:
# An error occurred, get a text describing the error and show it
#
result = pc1.GetErrorText(result)
print(result[1])
else:
print("PCAN-USB (Ch-1) was initialized")
โ€‹
def pcan_Close():
# The USB Channel is released
#
result = pc1.Uninitialize(PCAN_USBBUS1)
if result != PCAN_ERROR_OK:
# An error occurred, get a text describing the error and show it
#
result = pc1.GetErrorText(result)
print(result[1])
else:
print("PCAN-USB (Ch-1) was released")
โ€‹
def ReadMessage():
# We execute the "Read" function of the PCANBasic
#
result = pc1.Read(PCAN_USBBUS1)
โ€‹
if result[0] == PCAN_ERROR_OK:
# We show the received message
#
ProcessMessage(result[1:])
return result[0]
โ€‹
def ReadMessages():
result = PCAN_ERROR_OK,
while (result[0] & PCAN_ERROR_QRCVEMPTY) != PCAN_ERROR_QRCVEMPTY:
result = pc1.Read(PCAN_USBBUS1)
if result[0] != PCAN_ERROR_QRCVEMPTY:
ProcessMessage(result[1:])
else:
if(result[0] != PCAN_ERROR_QRCVEMPTY): print('ERROR_CODE:{}'.format(hex(result[0])))
โ€‹
def ProcessMessage(*args):
global time_prev
โ€‹
theMsg = args[0][0]
itsTimeStamp = args[0][1]
โ€‹
newMsg = TPCANMsgFD()
newMsg.ID = theMsg.ID
newMsg.DLC = theMsg.LEN
for i in range(8 if (theMsg.LEN > 8) else theMsg.LEN):
newMsg.DATA[i] = theMsg.DATA[i]
newMsg.MSGTYPE = theMsg.MSGTYPE
newTimestamp = TPCANTimestampFD()
newTimestamp.value = (itsTimeStamp.micros + 1000 * itsTimeStamp.millis + 0x100000000 * 1000 * itsTimeStamp.millis_overflow)
โ€‹
time = "Timestamp:{:0.3f}sec".format(newTimestamp.value/1000000)
period = newTimestamp.value - time_prev
cycle_time = "Cycle Time:{:0.3f}msec".format(period/1000)
TYPE = "TYPE:{}".format(msg_type[hex(newMsg.MSGTYPE)])
EID = "EID:{}".format(hex(newMsg.ID))
DLC = "DLC:{}".format(newMsg.DLC)
DATA = ' '.join('{:02x}'.format(newMsg.DATA[i]) for i in range(newMsg.DLC))
โ€‹
if newMsg.MSGTYPE == 0x02: # PCAN_MESSAGE_EXTEND
print(time,"|",TYPE,"|",EID,"|",DLC,"|",DATA,"|",cycle_time)
time_prev = newTimestamp.value
โ€‹
def WriteFrame(id, dlc, data):
CANMsg = TPCANMsg()
โ€‹
CANMsg.ID = id
CANMsg.LEN = dlc
CANMsg.MSGTYPE = PCAN_MESSAGE_EXTENDED
โ€‹
for i in range(CANMsg.LEN):
CANMsg.DATA[i] = data[i]
โ€‹
return pc1.Write(PCAN_USBBUS1, CANMsg)
โ€‹
def GetFormatedError(error):
stsReturn = pc1.GetErrorText(error, 0)
if stsReturn[0] != PCAN_ERROR_OK:
return "An error occurred. Error-code's text ({0:X}h) couldn't be retrieved".format(error)
else:
return stsReturn[1]
โ€‹
def VescCustumControl(target_vesc_id, ctrl_type, ctrl_value):
'''
# Custom Control CAN Msg Frame Structure Example, id=0x53, comm_set_custom=0x65=101=COMM_SET_DPS, data=2000000
WriteFrame(0x00000553,8,[0x00, 0x24, 0x05, 0x01, 0xFF, 0x65, 0x00, 0x1E])
WriteFrame(0x00000553,3,[0x07, 0x84, 0x80])
WriteFrame(0x00000753,6,[0x53, 0x00, 0x00, 0x09, 0xBB, 0x4E])
'''
if ctrl_type == 'COMM_SET_DUTY':
value = int(ctrl_value * 100000.0)
elif ctrl_type == 'COMM_SET_POS':
value = int(ctrl_value * 1000000.0)
elif ctrl_type == 'COMM_SET_RPM' or ctrl_type == 'COMM_SET_RELEASE':
value = int(ctrl_value)
else:
value = int(ctrl_value * 1000.0)
โ€‹
command = comm_set_custom[ctrl_type]
โ€‹
d1 = (value >> 24) & 0xFF
d2 = (value >> 16) & 0xFF
d3 = (value >> 8) & 0xFF
d4 = value & 0xFF
data_arr = [d1, d2, d3, d4]
# Frame1, Frame2 is for 'CAN_PACKET_FILL_RX_BUFFER(0x05)'
eid1 = (can_packet_id['CAN_PACKET_FILL_RX_BUFFER'] << 8) | target_vesc_id
dlc1 = 8
# Frame1 = [0x00(length index), 0x24(COMM_CUSTOM_APP_DATA=36), 0x06(host_model=6=CAN), 0x01(number of vesc), 0xFF(Target_vesc_id=default local=255), command, d1, d2]
Frame1 = [0x00, 0x24, 0x06, 0x01, 0xFF, command, d1, d2]
โ€‹
eid2 = (can_packet_id['CAN_PACKET_FILL_RX_BUFFER'] << 8) | target_vesc_id
dlc2 = 3
# Frame2 = [0x07(length index), d3, d4]
Frame2 = [0x07, d3, d4]
โ€‹
# crc calculation only for 9byte data frame (that is except 0x00, 0x07)
data_arr = Frame1[1:] + Frame2[1:]
arr = (ctypes.c_ubyte * len(data_arr))(*data_arr)
โ€‹
crc = crc_vesc.crc16(arr,9)
crch = (crc >> 8) & 0xFF
crcl = crc & 0xFF
โ€‹
# Frame3 is for 'CAN_PACKET_PROCESS_RX_BUFFER(0x07)'
eid3 = (can_packet_id['CAN_PACKET_PROCESS_RX_BUFFER'] << 8) | target_vesc_id
dlc3 = 6
# Frame2 = [target_vesc_id, send, data_length high, data_length low, crch, crcl]
Frame3 = [target_vesc_id, 0x00, 0x00, 0x09, crch, crcl]
โ€‹
'''
# debug print of can msgs
print('Frame1 - eid:', format(hex(eid1)), '| dlc:', format(hex(dlc1)), '| data:', '[{}]'.format(', '.join(hex(x) for x in Frame1)) )
print('Frame2 - eid:', format(hex(eid2)), '| dlc:', format(hex(dlc2)), '| data:', '[{}]'.format(', '.join(hex(x) for x in Frame2)) )
print('Frame3 - eid:', format(hex(eid3)), '| dlc:', format(hex(dlc3)), '| data:', '[{}]'.format(', '.join(hex(x) for x in Frame3)) )
'''
โ€‹
WriteFrame(eid1, dlc1, Frame1)
WriteFrame(eid2, dlc2, Frame2)
WriteFrame(eid3, dlc3, Frame3)
print('Run VESC CAN Direct Control,', ctrl_type,':',ctrl_value)
โ€‹
โ€‹
if __name__ == '__main__':
pc1 = PCANBasic()
โ€‹
# Open PCAN Device
pcan_Open()
โ€‹
'''
# CAN MSG Read Routine
num = 0
# try~ except ํŠน์ • ์˜ˆ์™ธ
try:
# ๋ฌดํ•œ ๋ฐ˜๋ณต
while True:
ReadMessages()
num += 1
# Ctrl + C๋ฅผ ์ž…๋ ฅํ•  ๊ฒฝ์šฐ
except KeyboardInterrupt:
print('Total Rcv number is {}, Quit to receive'.format(num))
'''
โ€‹
# CAN MSG Write Routine
#VescCustumControl(83, 'COMM_SET_DUTY',0.1)
#VescCustumControl(83, 'COMM_SET_CURRENT',0.5)
#VescCustumControl(83, 'COMM_SET_CURRENT_BRAKE',5)
#VescCustumControl(83, 'COMM_SET_DPS',0) # position lock on current position
#VescCustumControl(83, 'COMM_SET_DPS',1000)
#VescCustumControl(83, 'COMM_SET_DPS_VMAX',2000)
#VescCustumControl(83, 'COMM_SET_SERVO',0)
VescCustumControl(83, 'COMM_SET_RELEASE',0)
โ€‹
# Close PCAN Device
pcan_Close()

์œ„ ์ฝ”๋“œ์—์„œ #(์ฃผ์„)์ฒ˜๋ฆฌ๋œ VescCustumControl(~~~)๋ฅผ ํ•˜๋‚˜์”ฉ ์‹คํ–‰ํ•˜์—ฌ 83๋ฒˆ VESC์— ํ•ด๋‹น ๋ช…๋ น์–ด๋ฅผ CAN ํ†ต์‹ ์„ ํ†ตํ•ด ์ „์†ก๊ฐ€๋Šฅํ•จ์„ ํ™•์ธํ•˜์˜€๋‹ค.

โ€‹

โ€‹

โ€‹

โ€‹

โ€‹

โ€‹