This is the VESC-integration of [lispBM](https://github.com/svenssonjoel/lispBM) written by Joel Svensson. It allows the VESC to run lisp-programs in a sandboxed environment.
### Feature Overview
* Development and testing in VESC Tool with variable live monitoring and plotting as well as CPU and memory monitoring.
* There is a REPL in VESC Tool where code can be executed and tested live. You even have full access to the functions and bindings in the program you have uploaded.
* Sandboxed environment, meaning that the Lisp code (hopefully) cannot freeze or crash the rest of the VESC code when it gets stuck or runs out of heap or stack memory.
* The application runs on the VESC itself without the need for having VESC Tool connected and is stored in flash memory.
* When a lisp-application is written to the VESC it is automatically started on each boot.
This is the work-in-progress programming manual for LispBM. Note that the examples in the manual use the REPL quite a lot. All of them also work in the VESC Tool REPL (which is below the console below the code editor) when you are connected to a VESC and will be executed on the VESC itself. The results of the commands will be printed in the console. From the VESC Tool REPL you also have access to all functions and variables in the program that you have uploaded to the VESC.
The VESC-specific extensions are documented below. If you are reading this on GitHub there is an index in the upper left corner that can be used to navigate this document. It follows you as you scroll around and also includes a search function that filters all the titles in this document.
Note that VESC Tool includes a collection of examples that can be used as a starting point for using LispBM on the VESC.
Reset the timeout that stops the motor. This has to be run on at least every second to keep the motor running. The timeout time can be configured in App Settings->General. The [Motor Set Commands](#motor-set-commands) will also reset the timeout when they are called.
Note that control type can be set to Off in the PPM app to get the input without running the motor automatically, which is useful when running the motor from lisp.
This lets you set BMS-values so that VESC Tool and the BMS limits can see and use them. The same values as described in [get-bms-val](#get-bms-val) can be updated, but with an argument at the end with what the value should be set to.
This is useful if you want to implement communication with a custom BMS and have it show up in VESC Tool.
Example:
```clj
(set-bms-val 'bms-cell-num 12) ; It is a 12s pack
(set-bms-val 'bms-v-cell 2 3.92) ; Set cell 2 voltage to 3.92V
Send BMS-values on CAN-bus. This his useful if a custom BMS-driver is implemented using [set-bms-val](#set-bms-val) in order to make devices on the CAN-bus aware of the BMS-state using the VESC protocol.
Get decoded ADC value on channel ch (0 or 1). Decoded means that the voltage is mapped to the range 0 to 1 according to the configuration in the ADC app. Note that the ADC app must be running for this function to work. No throttle curve is applied to this value, but you can use the [throttle-curve](#throttle-curve) function to apply one if desired.
Get system time in ticks since boot. Every tick is 0.1 ms.
#### secs-since
```clj
(secs-since timestamp)
```
Get seconds elapsed since systime timestamp.
#### set-aux
```clj
(set-aux ch state)
```
Set AUX output ch (1 or 2) to state. Example:
```clj
(set-aux 1 1) ; Set AUX1 to ON.
```
Note: The AUX output mode must be set to Unused in Motor Settings->General->Advanced. Otherwise the firmware will change the AUX state directly after it is set using this function.
Get button and joystick state of connected remote. Note that a remote app such as the VESC remote or nunchuk must be configured and running for this to work. Returns the following list:
Several app-inputs can be detached from the external interfaces and overridden from lisp. This is useful to take advantage of existing throttle curves and control modes from the apps while providing a custom input source.
**Note:** Detach does *not* mean that the app output is disabled, it means that you can provide the input for the app instead of having it read the external peripheral. So if you e.g. detach the app and override the input with 0 the app will keep sending the corresponding command to the motor as usual, even if that command is a stop command. If you want to disable the app output you can have a look at [app-disable-output](#app-disable-output).
; js-y : Joystick Y axis, range -1.0 to 1.0, used for throttle position
; js-x : Joystick X axis, range -1.0 to 1.0, unused by the app
; bt-c : C button pressed state, 0 or 1, used for cruise control
; bt-z : Z button pressed state, 0 or 1, unused by the app
; is-rev : Reverse active, 0 or 1, reverse mode active
```
Send input to the VESC Remote app. Unlike the ADC and PPM apps, input can be sent to this app at any time without detaching it and it will be treated the same as a packet from a VESC Remote. That means the timeout as well as all VESC Remote settings will be used.
Returns the pedal RPM measured by the PAS-app. If you want to implement your own PAS-control based on this RPM you can use [app-disable-output](#app-disable-output) to disable the output of the PAS-app.
The optional optOffDelay argument (in seconds) will delay turning off the modulation when setting 0 current. This is useful when running e.g. a control loop that will end up setting 0 current in some circumstances when turning off the modulation would make the control less smooth. The delay value should be longer than the rate at which the control loop runs.
Set motor current relative to the maximum current. Range -1 to 1. For example, if the maximum current is set to 50A, (set-current-rel 0.5) will set the current to 25A.
Use the motor to play a beep sound at frequency freq for time seconds using voltage excitation voltage. The frequency can be set between 100 Hz and 7500 Hz.
Get motor current. Positive means that current is flowing into the motor and negative means that current is flowing out of the motor (regenerative braking).
Get the distance traveled since start in meters. As with (get-speed) this requires that the number of motor poles, wheel diameter and gear ratio are set up correctly. When the motor spins forwards this counter counts up and when it spins backwards it counts down.
#### get-dist-abs
```clj
(get-dist-abs)
```
Same as get-dist, but will count up when the motors spins in both directions.
Notice that all canget-commands rely on the status messages being active on the VESCs on the CAN-bus. That can be done from App Settings->General->Can status message mode.
Get MOSFET temperature over CAN-bus on VESC with id.
#### canget-temp-motor
```clj
(canget-temp-motor id)
```
Get motor temperature over CAN-bus on VESC with id.
#### canget-speed
```clj
(canget-speed id)
```
Get speed in meters per second over CAN-bus on VESC with id. The gearing, wheel diameter and number of motor poles from the local configuration will be used for converting the RPM to meters per second.
#### canget-dist
```clj
(canget-dist id)
```
Get distance traveled in meters over CAN-bus on VESC with id. As with (canget-speed id), the local configuration will be used to convert the tachometer value to meters.
Get PPM-input from the VESC with id on the CAN-bus. Note that CAN status message 6 as well as the PPM-app must be active on that VESC for this function to work.
#### canget-adc
```clj
(canget-adc id ch)
```
Get ADC channel ch from the VESC with id on the CAN-bus. Note that CAN status message 6 must be active on that VESC for this function to work.
List CAN-devices that have been heard on the CAN-bus since boot. This function is fast as it does not actively scan the CAN-bus, but it relies on the devices sending status message 1.
#### can-scan
```clj
(can-scan)
```
Actively scan the CAN-bus and return a list with devices that responded. This function takes several seconds to run, but also finds devices that do not actively send messages and only respond to a ping message.
Send standard ID CAN-frame with id and data. Data is a list with bytes, and the length of the list (max 8) decides how many data bytes are sent. Example:
Rotate vector x1,x2,x3 around roll, pitch and yaw. optRev (1 or 0) will apply the rotation in reverse (apply the inverse of the rotation matrix) if set to 1.
Apply throttle curve on value. accel (range -1 to 1) is the curve constant for acceleration (when value is greater than 0) and brake (range -1 to 1) is the curve constant for braking (when value is less than 0). mode (0, 1 or 2) is the throttle curve mode. Negative curve constants mean that the throttle will be gentler in the beginning and more aggressive with towards the end and positive curve constants mean the opposite. The modes are 0: Exponential, 1: Natural and 2: Polynomial. You can have a look at the throttle curves in VESC Tool for the PPM, ADC or VESC Remote app and experiment with the mode and curve constants to see a plot of the response.
Put bits of number in initial at offset and return the result. For example, if the bits initial are aaaaaaaa, number is bbb, offset is 2 and bits is 3 the result is aaabbbaa. For reference, the corresponding operation in C is:
Return size bits of value at offset. For example if the bits of value are abcdefgh, offset is 3 and size it 3 a number with the bits cde is returned. The corresponding operation in C is:
Raw data commands useful for debugging hardware issues.
#### raw-adc-current
```clj
(raw-adc-current motor phase useRaw)
```
Get raw current measurements. Motor is the motor index (1 or 2), phase is the phase (1, 2 or 3) and useRaw is whether to convert the measurements to currents or to use raw ADC values.
These samples can come from either V0 or V7 depending on when the function is called (although most likely V7 as less other computations happen then), so when the motor is running this is most likely not going to look good, especially if the hardware does not have phase shunts. This function is intended for debugging hardware and returns just was goes into the ADC without any processing.
Same as (raw-mod-alpha), but derives the modulation from the phase voltage reading and/or dead-time compensation.
#### raw-mod-beta-measured
```clj
(raw-mod-beta-measured)
```
Same as (raw-mod-beta), but derives the modulation from the phase voltage reading and/or dead-time compensation.
#### raw-hall
```clj
(raw-hall motor optSamples)
```
Read hall sensors for motor (1 or 2) and return their states in a list. The optional argument optSamples (max 20) can be used to set how many times the hall sensors are sampled; if it is not supplied the number of samples from the motor configuration will be used.
Start the UART driver at baudrate on the COMM-port on the VESC. optHd is an optional argument that can be set to 'half-duplex to use half-duplex mode. In half-duplex mode only the tx-pin is used. If any app is using the UART pins it will be stopped first. Example:
Write array (see [byte array](#byte-arrays) for details) to the UART. Examples:
```clj
(uart-write "Hello World!") ; Write the string hello world!
```
```clj
(define arr (array-create 6)) ; Create a 6 byte long array
(bufset-i16 arr 0 1123) ; Set byte 0 and 1 to 1123
(bufset-i32 arr 2 424242) ; Set byte 2 to 5 to 424242
(uart-write arr) ; Write arr to the uart
```
#### uart-read
```clj
(uart-read array num optOffset optStopAt)
```
Read num bytes into array at offset optOffset. Stop reading if the character optStopAt is received. The last two arguments are optional. Note that this function returns immediately if there is nothing to be read, so it is not blocking. The return value is the number of bytes read.
#### uart-read-bytes
```clj
(uart-read-bytes array num offset)
```
Read num bytes into buffer at offset. This function is blocking, so it will not return until the specified amount of bytes is read.
#### uart-read-until
```clj
(uart-read-until array num offset end)
```
Same as uart-read-bytes, but will return when the byte end is read.
Start the I2C driver on the COMM-port on the VESC. If any app is using the I2C pins it will be stopped first. optRate is an optional argument for the I2C bitrate. optPinSda and optPinScl are optional arguments for using different SDA and SCL pins. Example:
These functions allow using GPIO-pins from lispBM. The UART and SWD pins can currently be used. NOTE: If you are using the SWD-pins a SWD-programmer won't work after that until the next reset. If you are using the hall sensor pins make sure that sensor port mode is not set to anything that will communicate with encoders using those pins. Leaving the sensor port in hall sensor mode should be fine.
Write state to pin. If the pin is set to an output 1 will set it to VCC and 0 to GND. If the pin is open drain 1 will set it floating and 0 will set it to GND. Example:
```clj
(gpio-write 'pin-rx 1) ; Set pin rx to 1
```
#### gpio-read
```clj
(gpio-read pin)
```
Read state of pin. Returns 1 if the pin is high, 0 otherwise.
Set param to value. This can be done while the motor is running and it will be applied instantly. Note that the parameter won't be stored in flash, so it will be back to the old value on the next boot. To store all parameters that have been changed you can use [conf-store](#conf-store). Example:
```clj
(conf-set 'max-speed (/ 25 3.6)) ; Set the maximum speed to 25 km/h
Get the value of param. optDefLim is an optional argument that can be set to 1 or 2; 1 means get the default value and 2 means get the limit value. Example:
Run the same autodetection as the wizard in VESC Tool does. This function will block the current lispBM-thread until in finishes (other threads will continue running). Arguments:
```clj
canFwd ; Scan CAN-bus and detect on all VESCs found on CAN-bus
maxLoss ; Maximum power loss in W to derive current limit from
minCurrIn ; Minimum input current in A (negative value)
maxCurrIn ; Maximum input current in A
openLoopErpm ; Openlopp ERPM setting
slErpm ; Sensorless ERPM setting
```
Result:
```clj
0 ; OK and no sensors found
1 ; OK and hall sensors found
2 ; OK and AS5047 found
-1 ; Fault code during sensor detection
-10 ; Flux linkage detection failed
-50 ; CAN-detection failed
-51 ; CAN-detection timed out
```
Example:
```clj
; No can detection, 50w losses max, -20 A to 50 A input current, 800 ERPM openloop and 2500 erpm for sensorless in case sensors are found
Set the PID controller offset such that the current angle becomes offset. This can be used in position control applications when e.g. homing against a limit switch. The optional argument optStore can be set to true to store the offset persistently (although that requires stopping the motor).
Measure motor resistance with current. The optional argument optSamples sets the number of samples to use (default 100).
This command is useful to update the configuration before starting the motor as the resistance is the most important when it comes to sensorless low-speed performance. It is also useful to sanity check if the motor is shorted out or if a connector is loose. Such faults cause a relatively significant change in resistance. Changes with more than 50% compared to the detected value are most likely faults.
**NOTE:** Phase filters are required to get accurate resistance measurements, so resistance-based fault detection is not as useful on hardware without phase filters.
Up to 128 variables (int32 or float) can be stored in a nonvolatile memory reserved for LispBM. These variables persist between power cycles and configuration changes, but not between firmware updates. Keep in mind that the motor will be stopped briefly when writing them and that they only can be written a limited number of times (about 100 000 writes) before wear on the flash memory starts to become an issue.
Store float number on emulated eeprom at address addr. Addr range: 0 to 127. Note that this will stop the motor briefly as writing to the flash memory cannot be done at the same time as the motor is running.
For-loop. it is the iterator, start is what it is initialized to, cond is the condition that has the be true for the loop to continue running, update is how to update the iterator after each iteration and body is the code to execute each iteration. The iterator can be accessed from within body. Example:
ForEach-loop. Iterate over every element in the list lst and evaluate body for each iteration. The iterator it can be accessed from within body. Example:
```clj
(loopforeach i '("AB" "C" "dE" "f")
(print i)
)
Output:
AB
C
dE
f
; As with the other loops, multiple statements require a progn
break can be used to break out of a loop and return retval (the result of the loop will be retval, otherwise the result of the loop will be the result of the last expression in it). break works in all of the loops above. Example:
There are a number of lisp functions that can be used from lispBM in the VESC firmware. They will be loaded to the environment the first time they are used, so they do not use up memory before the first use.
Apply function f to every element in list lst. Example:
```clj
(map (lambda (x) (* x 5)) '(1 2 3 4))
> (5 10 15 20)
```
This example creates an anonymous function that takes one argument and returns that argument multiplied by 5. Map then applies it to every element in the list (1 2 3 4), which yields the list (5 10 15 20).
Create a string from the number n. Also takes an optional format argument optFormat that works in the same way as the printf-function in C. The optFormat argument can also be used together with other characters as long as the resulting output string is shorter than 100 characters. Example:
```clj
(str-from-n 10)
> "10"
(str-from-n 2.5)
> "2.500000"
(str-from-n 2.5 "%.1f")
> "2.5"
(str-from-n 10 "0x%04X") ; Here we also append 0x in front of optFormat
Compare strings str1 and str2. Works in the same way as the strcmp-function in C, meaning that equal strings return 0 and different strings return their difference according how they would be sorted.
The optional argument optN can be used to specify how many characters to compare (like strncmp in C). If it is left out all characters will be compared.
Events can be used to execute code for certain events, such as when CAN-frames are received. To use events you must first register an event handler, then enable the events you want to receive. As the event handler blocks until the event arrives it is useful to spawn a thread to handle events so that other things can be done in the main thread at the same time.
This event is sent when standard id CAN-frames are received.
**event-can-eid**
This event is sent when extended id CAN-frames are received.
**event-data-rx**
This event is sent when custom app data is sent from VESC Tool.
**event-shutdown**
This event is sent when the VESC is about to shut down. Note that this event currently only works on hardware with a power switch. If that is not the case you could try to, for example, monitor the input voltage and simulate this event when it drops below a set level.
Byte arrays (and text strings) are allocated in memory as consecutive arrays of bytes (not linked lists). They can be shared with C and are more space and performance efficient than linked lists. Several of the extensions also take byte arrays as input as an alternative to lists and some of the events return byte arrays.
To allocate a byte array with 20 bytes and bind the symbol arr to it you can use
To clear a byte array the function bufclear can be used:
```clj
(bufclear arr optByte optStart optLen)
```
Where arr is the byte array to clear, optByte is the optional argument of what to clear with (default 0), optStart is the optional argument of which position to start clearing (default 0) and optLen is the optional argument of how many bytes to clear after start (default the entire array). Example:
```clj
(bufclear arr) ; Clear all of arr
(bufclear arr 0xFF) ; Fill arr with 0xFF
(bufclear arr 0 5) ; Clear from index 5 to the end
(bufclear arr 0 5 10) ; Clear 10 bytes starting from index 5
(bufclear arr 0xAA 5 10) ; Set 10 bytes to 0xAA starting from index 5
(bufget-f32 arr 0) ; read byte 0 to 3 as float32 (IEEE 754)
```
By default the byte order is big endian. The byte order can also be specified as an extra argument. E.g. to read 4 bytes as int32 from position 6 in little endian you can use
Copy len bytes from arr2 starting at ind2 to arr1 starting at ind1. Len will be truncated to ensure that nothing is read or written outside of the arrays.
Byte arrays will be de-allocated by the garbage collector on a regular basis, but can still use a lot of memory until then and large byte arrays cause a risk of running out of memory. It is possible to manually de-allocate the byte arrays when done with them by calling free
```clj
(free arr)
```
This will clear the allocated memory for arr.
**Note**
Strings in lispBM are treated the same as byte arrays, so all of the above can be done to the characters in strings too.
Import is a special command that is mostly handled by VESC Tool. When VESC Tool sees a line that imports a file it will open and read that file and attach it as binary data to the end of the uploaded code. VESC Tool also generates a table of the imported files that will be allocated as arrays and passed to LispBM at start and bound to bindings.
Every imported file behaves as a byte array that is read-only (so do not try to modify it). These byte arrays can be used as usual from the lisp code to, for example, load native libraries or to load more lisp code at runtime. As they are stored in flash in raw binary format there is significantly more space available than when using e.g. the array syntax. The lisp script and the imported files can use up to 120 KB together.
#### import
```clj
(import filename binding)
```
Load filename as a byte array and bind it to binding. Note that import must be on its own line and that every line can only have one import.
**Example: Load native library**
```clj
(import "ws2812.bin" 'ws2812) ; Import the native ws2812 library. This creates the byte array ws2812 that can be used usual.
(load-native-lib ws2812); Load it to get the extensions it provides
Paths for import can be relative or absolute. Absolute paths are always looked up from the root of the file system, but relative paths need to be resolved. If the lisp-file is saved (e.g. there is a path at the bottom of the editor) paths are looked up relative to the location of that lisp file. If they are not found there they are looked up relative to the location where VESC Tool is started. If the file never has been saved (e.g. you just opened a new tab and started typing) the file path is unknown until save as is used, so only the path relative to VESC Tool is looked up then.
### Special Paths
It is also possible to import files from [VESC Packages](https://github.com/vedderb/vesc_pkg) using a special path syntax. If you want to import the lisp-file from a VESC Package you can use the format
This will import the lisp-file from that VESC Package. It is also possible to import the imports from a lisp-file in a VESC Package. This is a bit confusing as the package itself does not contain the paths anymore, so instead of referring to the path you have to refer to the label. Here is an example of that:
Suppose you have a VESC Package that has a lisp-file that imports a file like this:
```clj
(import "c_lib/ws2812/ws2812.bin" 'ws2812)
```
To import the file that is imported as ws2812 in the lisp-file of that vesc package you can use
This means import the import ws2812 from the lisp file in the VESC Package located at path/to/package.vescpkg.
### Import Official VESC Packages
There is a [github repository](https://github.com/vedderb/vesc_pkg) where official VESC Packages are located. All of the lisp-files and their imports from the packages in this repository can be imported using the special base path **://vesc_packages**. For example, to import the ws2812 import from lib_ws2812 the following import can be used:
This should work for all VESC Packages in that repository. Most examples there use this pattern.
**NOTE:** The path above does not download the repository on demand, but relies on the cached local version. This cached version is not updated automatically, so you have to run the update manually when you want to get the latest version of the repository. To update the cache you can use the **Update Archive**-button from the VESC Packages-page in VESC Tool.
Native libraries can be used when more performance is needed. They can be created by compiling position-independent C code and loaded/unloaded with the functions below. More care has to be taken when developing native libraries as they have far less sandboxing than lispBM-code, so access to a SWD-programmer is recommended while developing them.
Up to 10 native libraries can be loaded simultaneously and the recommended way to configure and interact with them is by providing LispBM-extensions from them.
Currently the documentation for native libraries is limited, but there are some examples [in this diretory](c_libs/examples). The interface that can be used in native libraries can be found [in this file](c_libs/vesc_c_if.h).
### Features
Native libraries get a list of function pointers that can be used to interact with the rest of the VESC code. The following features are currently supported:
* Register LispBM-extensions.
* Os-functions like sleep, print, malloc, free, system time.
* Create one or more threads.
* GPIO-control (ST and abstract).
* The ST standard peripheral library can be used.
* Send and receive CAN-frames and control other VESCs over CAN-bus.
* Motor control using almost everything from mc_interface.
### Cleanup
Every time lispBM is restarted or when new code is uploaded the native libraries are closed and reloaded, so it is important to do proper cleanup in lib_info->stop_fun when resources such as threads are allocated.
#### load-native-lib
```clj
(load-native-lib lib)
```
Load the native library lib. lib is a byte array with the compiled binary that is created after running make on the native library.
#### unload-native-lib
```clj
(unload-native-lib lib)
```
Unload the native library lib. This is done automatically when lispBM is stopped or restarted, so there is no need to do it explicitly. This function is provided in case native libraries need to be explicitly loaded and unloaded while the same program is running.
### Native Library Example
This example creates an extension called ext-test that takes a number as an argument and returns the number multiplied by 3. The code for it can be found [in this diretory](c_libs/examples/extension).
```clj
; When running make in the example directory a file called example.lisp
Get the last raw uavcan-command and its age. Returns a list where the first element is the value and the second element is the age. canInterface is the interface, which can be 1 or 2. Interface 2 is only valid if the hardware has dual CAN-buses. Example:
```clj
(print (ix (uavcan-last-rawcmd 1) 0)) ; Print the value
(print (ix (uavcan-last-rawcmd 1) 1)) ; Print the age in seconds
```
#### uavcan-last-rpmcmd
```clj
(uavcan-last-rpmcmd canInterface)
```
Same as uavcan-last-rawcmd, but for the last rpm-command.
Set how many evaluation steps to run each thread between context switches. Default is 50. A lower value will alter between threads more often, reducing latency between context switches at the cost of overall performance. The default value of 50 has relatively low performance overhead. Setting the quota to the lowest possible value of 1, meaning that each thread gets to run one step at a time, roughly halves the performance.
Lowering this value is useful if there are one or more timing-critical threads (that e.g. read encoders) that cannot wait too long between iterations.
CAN-connected IO-boards can be interfaced using the functions in this section.
#### ioboard-get-adc
```clj
(ioboard-get-adc can-id channel)
```
Read ADC-input channel from IO-board with can-id. Channel range: 1 to 8. If the IO-board with can-id is not present on the CAN-bus or if the channel is missing -1 will be returned.
#### ioboard-get-digital
```clj
(ioboard-get-digital can-id channel)
```
Read digital input channel from IO-board with can-id. Channel range: 1 to 64. If the IO-board with can-id is not present on the CAN-bus or if the channel is missing -1 will be returned.
#### ioboard-set-digital
```clj
(ioboard-set-digital can-id channel state)
```
Write digital output channel to IO-board with can-id. State can be 1 or 0.
#### ioboard-set-pwm
```clj
(ioboard-set-pwm can-id channel duty)
```
Write PWM-output channel to IO-board with can-id. The value duty can be 0.0 to 1.0.
It is possible to log arbitrary data to log-devices such as the VESC Express, which can be connected on the CAN-bus.
Every log field consists of a keyword, name, unit, precision and some flags. Most of these fields control how VESC Tool renders the log. In the csv-file for the log they only show up in the first line as headers for each column.
VESC Tool will look for some special keywords to handle statistics and rendering on the map. If these keywords are missing the log can still be shown, but some of the functionality and statistics in VESC Tool will not be available. The following are the special keywords:
**t_day**
Time of day in seconds. Used for statistics. This field is created by the log module when append-time is set to 1.
**gnss_h_acc**
GNSS horizontal accuracy. Used for outlier filtering. This field is created by the log module when apped-gnss is set to 1.
GNSS latitude. Used for plotting traces on the map and for calculating statistics. This field is created by the log module when apped-gnss is set to 1.
**gnss_lon**
GNSS longitude. Used for plotting traces on the map and for calculating statistics. This field is created by the log module when apped-gnss is set to 1.
**gnss_alt**
GNSS altitude. Used for plotting traces on the map and for calculating statistics. This field is created by the log module when apped-gnss is set to 1.
**trip_vesc**
VESC trip counter in meters. Used for calculating statistics.
**trip_vesc_abs**
Absolute VESC trip counter in meters. Used for calculating statistics.
**trip_gnss**
GNSS trip counter in meters. Used for calculating statistics. This field is automatically generated by VESC Tool from gnss_lat, gnss_lon and gnss_alt if it is missing.
**cnt_wh**
Watt hour counter. Used for calculating statistics.
**cnt_wh_chg**
Watt hour counter charging. Used for calculating statistics.
**cnt_ah**
Amp hour counter. Used for calculating statistics.
**cnt_ah_chg**
Amp hour counter charging. Used for calculating statistics.
**roll**
IMU roll in degrees. Used for the IMU 3D plot.
**pitch**
IMU pitch in degrees. Used for the IMU 3D plot.
**yaw**
IMU yaw in degrees. Used for the IMU 3D plot.
**fault**
Fault code. Converted to a fault string in the VESC Tool log analysis tool.
If set to true the log device will append a GNSS-position to each sample. This requires a GNSS-receiver on the log device and the log will not start until a valid position is available.
Send log samples to log device with can-id. This function takes 1 to 100 samples as arguments which will be applied to the log fields starting from from-field-ind. The samples can be numbers or lists of numbers. Setting the id to -1 will send the data to VESC Tool.
Same as [log-send-f32](#log-send-f32) but uses 64-bit values for higher precision and takes up to 50 samples. Useful for e.g. gnss-positions where 32-bit floats do not give enough precision due to the size of the earth.
The first command might fail if it already is added, but the second one should still work. If there are uncomitted changes you can run **git stash** before the commands and **git stash pop** after them.