Documentation Index
Fetch the complete documentation index at: https://mintlify.com/vedderb/bldc/llms.txt
Use this file to discover all available pages before exploring further.
The following examples demonstrate common patterns for LispBM scripting on VESC. Each example is a complete, runnable script unless otherwise noted. Copy them into the VESC Tool scripting editor and upload to try them out.
VESC Tool ships with a built-in collection of example scripts accessible from the scripting editor menu. These examples are a good starting point for many common tasks.
Simple loop with status printing
The most basic VESC script structure: an initialization block followed by an infinite loop that periodically prints status and resets the motor timeout.
; Print firmware version and hardware name on startup
(print (sysinfo 'fw-ver))
(print (sysinfo 'hw-name))
; Main loop: print input voltage every 500 ms
(loopwhile t
(progn
(print (str-from-n (get-vin) "Vin: %.2f V"))
(sleep 0.5)))
Blinking AUX output
Toggle the AUX1 output on and off at 1 Hz. This is the VESC equivalent of a “blink LED” example.
; AUX output mode must be set to Unused in motor settings
(define state 0)
(loopwhile t
(progn
(set-aux 1 state)
(setvar 'state (if (= state 0) 1 0))
(sleep 0.5)))
Reading motor RPM and reacting
Read the motor RPM and apply different behavior depending on the speed.
(defun handle-speed (rpm)
(cond
((< (abs rpm) 100)
(print "Motor stopped"))
((< (abs rpm) 2000)
(print (str-from-n rpm "Low speed: %.0f RPM")))
(t
(print (str-from-n rpm "High speed: %.0f RPM")))))
(loopwhile t
(progn
(handle-speed (get-rpm))
(sleep 0.2)))
Controlling motor speed with set-duty
Ramp the motor duty cycle from 0 to 30% over 3 seconds, hold it, then brake.
; Ramp up over 3 seconds
(looprange i 0 30
(progn
(set-duty (/ i 100.0))
(timeout-reset)
(sleep 0.1)))
; Hold at 30% for 2 seconds
(define t-start (systime))
(loopwhile (< (secs-since t-start) 2.0)
(progn
(set-duty 0.3)
(timeout-reset)
(sleep 0.01)))
; Brake
(set-brake 5.0)
(sleep 1.0)
; Release
(set-current 0.0)
(print "Done")
Always call (timeout-reset) at least once per second whenever the motor is running from a script. If the script stops calling it — for example due to a crash — the motor will automatically stop after the timeout period configured in App Settings → General.
RPM control with soft start
Use set-rpm to drive a motor to a target speed, reading configuration to stay within safe limits.
(define max-erpm (conf-get 'l-max-erpm))
(define target-rpm (min 3000.0 max-erpm))
(print (str-from-n max-erpm "Max ERPM from config: %.0f"))
(print (str-from-n target-rpm "Targeting: %.0f RPM"))
(loopwhile t
(progn
(set-rpm target-rpm)
(timeout-reset)
(print (str-from-n (get-rpm) "Current RPM: %.0f"))
(sleep 0.05)))
Reading configuration values
Inspect key motor configuration parameters at startup. Useful for debugging or adapting script behavior to the configured hardware.
(define print-conf (lambda (sym label)
(print (str-merge label (str-from-n (conf-get sym) " %.2f")))))
(print-conf 'l-current-max "Max current (A): ")
(print-conf 'l-current-min "Min current (A): ")
(print-conf 'l-max-erpm "Max ERPM: ")
(print-conf 'l-max-vin "Max voltage (V): ")
(print-conf 'si-motor-poles "Motor poles: ")
(print-conf 'si-gear-ratio "Gear ratio: ")
(print-conf 'si-wheel-diameter "Wheel dia (m): ")
(print-conf 'controller-id "CAN ID: ")
IMU tilt detection
Read the IMU roll angle and print a warning when the board tilts beyond a threshold.
(define tilt-threshold 0.35) ; ~20 degrees in radians
(loopwhile t
(progn
(define rpy (get-imu-rpy))
(define roll (ix rpy 0))
(define pitch (ix rpy 1))
(if (> (abs roll) tilt-threshold)
(print (str-from-n (* roll 57.3) "Warning: roll %.1f deg")))
(if (> (abs pitch) tilt-threshold)
(print (str-from-n (* pitch 57.3) "Warning: pitch %.1f deg")))
(sleep 0.1)))
CAN bus communication
Sending a raw CAN frame
; Send a standard 11-bit CAN frame to ID 0x100
(can-send-sid 0x100 (list 0x01 0x02 0x03 0x04))
Reading motor state from another VESC over CAN
Use can-cmd to execute a LispBM expression on a remote VESC and return the result:
(define remote-id 2) ; CAN ID of the other VESC
(loopwhile t
(progn
(define remote-rpm (can-cmd remote-id '(get-rpm)))
(define remote-vin (can-cmd remote-id '(get-vin)))
(print (str-from-n remote-rpm "Remote RPM: %.0f"))
(print (str-from-n remote-vin "Remote Vin: %.2f V"))
(sleep 0.5)))
Listing CAN devices
; Print all VESC devices visible on the CAN bus
(print (can-list-devs))
Receiving CAN frames with events
Enable events to receive CAN frames asynchronously without polling:
(event-enable 'event-can-sid)
(loopwhile t
(progn
(define evt (recv 0.5)) ; wait up to 0.5 s for an event
(if (eq (type-of evt) type-list)
(match evt
((event-can-sid id data)
(print (str-merge "CAN SID: " (str-from-n id "0x%X")
" data: " (to-str data)))))))
Motor fault monitoring
Check for faults and print them to the console:
(defun check-faults ()
(define fault (get-fault))
(if (not (eq fault 'fault-none))
(print (str-merge "FAULT: " (to-str fault)))))
(loopwhile t
(progn
(check-faults)
(sleep 0.1)))
EEPROM: persisting a value across reboots
Store a trip counter in EEPROM so it survives power cycles:
; Read trip counter from EEPROM slot 0 (default 0.0 if unset)
(define trip-m (eeprom-read-f 0))
(print (str-from-n trip-m "Trip: %.1f m"))
; Accumulate distance every 100 ms and save every 10 seconds
(define last-save (systime))
(loopwhile t
(progn
(setvar 'trip-m (+ trip-m (* (get-speed) 0.1)))
(if (> (secs-since last-save) 10.0)
(progn
(eeprom-store-f 0 trip-m)
(setvar 'last-save (systime))
(print (str-from-n trip-m "Saved trip: %.1f m"))))
(sleep 0.1)))
Spawning a background monitoring thread
Run motor control in the main thread and monitor temperature in a background thread:
; Background thread: monitor temperatures
(spawn (lambda ()
(loopwhile t
(progn
(define fet-temp (get-temp-fet))
(define mot-temp (get-temp-mot))
(if (> fet-temp 80.0)
(print (str-from-n fet-temp "High FET temp: %.1f C")))
(if (> mot-temp 100.0)
(print (str-from-n mot-temp "High motor temp: %.1f C")))
(sleep 1.0)))))
; Main thread: motor control
(loopwhile t
(progn
(set-duty 0.2)
(timeout-reset)
(sleep 0.01)))