rusefi_documentation/Lua-Scripting.md

367 lines
9.9 KiB
Markdown
Raw Normal View History

2021-04-29 10:57:27 -07:00
# Basics
2021-07-16 14:13:19 -07:00
A proper ECU has to offer users as much flexibility as possible, meaning a completely user-defined control strategy for both primary and auxiliary actuators. For many years rusEFI had FSIO to do just that.
As of 2021, rusEFI is replacing FSIO with a popular open source [Lua scripting engine](https://en.wikipedia.org/wiki/Lua_(programming_language))
2021-10-21 12:16:40 -07:00
We use Lua https://www.lua.org/ version 5.4.3
2021-07-16 14:13:19 -07:00
2021-04-29 10:57:27 -07:00
## Conventions
- The Lua interpreter will trigger an error if there is a mistake in the program, check the rusEFI console to see errors and script output.
2021-05-04 02:38:24 -07:00
- Unless otherwise mentioned, all `index` parameters start with the first element at index at 0.
2021-04-29 10:57:27 -07:00
## Writing Your Script
The entire Lua script is read at startup, then a function called `onTick` is called periodically by rusEFI.
Here is a simple script you can run to illustrate this behavior:
```
print('Hello Lua startup!')
function onTick()
print('Hello onTick()')
end
```
### Controlling the Tick Rate
2021-04-29 11:43:57 -07:00
The function `setTickRate(hz)` can be used to configure how often rusEFI calls the `onTick` function. If your script does a lot of work in the `onTick()` function it may run slower than the desired rate. Since the Lua virtual machine runs at low priority compared to other functions of the ECU, it is impossible to swamp the ECU with too much Lua work, so set the tick rate to whatever is necessary.
2021-04-29 10:40:07 -07:00
2021-04-29 11:51:56 -07:00
```
n = 0
setTickRate(5) --set tick rate to 5hz
function onTick()
print('Hello Lua: ' ..n)
n = n + 1
end
```
2021-04-29 10:40:07 -07:00
# Function Reference
2021-11-14 08:43:12 -08:00
## User Settings
2021-12-15 17:28:29 -08:00
### `getOutput(name)`
For example ``getOutput("clutchUpState")`` ``getOutput("brakePedalState")``
See https://github.com/rusefi/rusefi/blob/master/firmware/controllers/lua/generated/output_lookup_generated.cpp for output names.
2021-12-15 17:31:41 -08:00
### `setClutchUpState(value)`
2021-12-15 17:31:23 -08:00
### `setBrakePedalState(value)`
2021-12-15 10:15:05 -08:00
### `getCalibration(name)`
Gets current calibration value for specified scalar setting. For example ``getCalibration("cranking.rpm")``
2021-12-15 17:28:29 -08:00
See https://github.com/rusefi/rusefi/blob/master/firmware/controllers/lua/generated/value_lookup_generated.cpp for field names.
2021-12-15 10:15:05 -08:00
### `setCalibration(name, value, needEvent)`
Sets specified calibration setting to specified value. Fires calibration change event depending on needEvent parameter.
For example ``setCalibration("cranking.rpm", 900, false)``
### `findSetting(name, defaultValue)`
2021-11-14 08:43:12 -08:00
Find User Setting with specified name and returns numeric value. Useful when script developer and script consumer are
different people, also useful while Lua script editing is available only in TS.
- Parameters
- `name`: Variable name, as in corresponding 'name' field in configuration
- `dataultValue`: value to use if specified setting not located by name
2021-09-24 06:40:26 -07:00
## Engine Control
2021-11-26 06:29:55 -08:00
### `stopEngine`
2021-11-29 19:33:12 -08:00
### `setSparkSkipRatio`
setSparkSkipRatio(0) to skip 0% of the ignition events, i.e. no skipping
setSparkSkipRatio(0.5) would skip half of ignition events. We never skip two consecutive ignitions.
### `setTimingAdd(angle)`
2021-09-24 06:40:26 -07:00
todo add details but ready to test!
### `setTimingMult(coeff)`
2021-09-24 06:40:26 -07:00
todo add details but ready to test!
2021-12-02 06:20:53 -08:00
### `setEtbAdd(extraEtb)`
extraEtb `10` for 10%
## CAN bus
### `enableCanTx(isEnabled)`
enabled by default
use enableCanTx(false) to suppress CAN TX
2021-04-29 10:40:07 -07:00
## Utility
### `print(msg)`
Print a line of text to the ECU's log.
- Parameters
- `msg`: The message to print. Pass a string or number and it will be printed to the log.
- Returns
- none
#### Usage example
Program:
```
n = 5.5
print('Hello Lua, number is: ' ..n)
```
Output:
`Hello Lua, number is 5.5`
2021-04-29 10:57:27 -07:00
### `setTickRate(hz)`
2021-11-23 11:21:45 -08:00
Sets the rate at which rusEFI calls your `onTick` function, in hz. On reset default is 10hz.
2021-04-29 10:57:27 -07:00
- Parameters
- `hz`: Desired tick rate, in hz. Values passed will be clamped to a minimum of 1hz, and maximum of 100hz.
- Returns
- none
2021-12-13 14:49:11 -08:00
### `mcu_stop`
Stops MCU.
2021-04-29 10:40:07 -07:00
### `table3d(tableIdx, x, y)`
Looks up a value from the specified Script Table.
2021-04-29 10:40:07 -07:00
- Parameters
- `tableIdx`: Index of the table to use. Currently 4 tables are supported, so indices 1, 2, 3, and 4 are valid.
2021-04-29 10:40:07 -07:00
- `x`: X-axis value to look up in the table (this is often RPM)
- `y`: Y-axis value to look up in the table (this is often load)
- Returns
- A number representing the value looked up from the table.
### `curve(curveIdx, x)`
Looks up a value from the specified Script Curve.
- Parameters
- `tableIdx`: Index of the script to use, starting from 1.
- `x`: Axis value to look up in the table
2021-05-04 02:22:58 -07:00
### `setDebug(index, value)`
Sets a debug channel to the specified value. Note: this only works when the ECU debug mode is set to `Lua`.
- Parameters
- `index`: the index of the debug channel to set, 1 thru 7 inclusive.
- `value`: the value to set the channel to
- Returns
- none
2021-04-29 10:40:07 -07:00
## Input
2021-10-21 16:38:02 -07:00
### `getSensor(name)`
Reads the specified sensor.
- Parameters
- `name`: Name of the sensor to read. [A list of sensor indices can be found here.](https://github.com/rusefi/rusefi/blob/master/firmware/controllers/sensors/sensor_type.h)
- Returns
- A reading from the sensor, or `nil` if the sensor has a problem or isn't configured.
### `getSensorByIndex(index)`
2021-04-29 10:40:07 -07:00
Reads the specified sensor.
- Parameters
- `index`: Index of the sensor to read. [A list of sensor indices can be found here.](https://github.com/rusefi/rusefi/blob/master/firmware/controllers/sensors/sensor_type.h)
- Returns
- A reading from the sensor, or `nil` if the sensor has a problem or isn't configured.
### `getSensorRaw(index)`
Reads the raw value from the specified sensor. For most sensors, this means the analog voltage on the relevant input pin.
- Parameters
- `index`: Index of the sensor to read. [A list of sensor indices can be found here.](https://github.com/rusefi/rusefi/blob/master/firmware/controllers/sensors/sensor_type.h)
- Returns
- The raw value that yielded the sensor reading, or 0 if the sensor doesn't support raw readings, isn't configured, or has failed.
2021-09-18 14:13:52 -07:00
### `getAuxAnalog(index)`
More or less like getSensorRaw but always voltage of aux analog input.
- Parameters
- `index`: Index of aux analog sensor to read. From 0 to 3
- Returns
- Voltage of sensor reading, or nil if sensor isn't configured.
2021-04-29 10:57:27 -07:00
### `hasSensor(index)`
Checks whether a particular sensor is configured (whether it is currently valid or not).
- Parameters
- `index`: Index of the sensor to check. [A list of sensor indices can be found here.](https://github.com/rusefi/rusefi/blob/master/firmware/controllers/sensors/sensor_type.h)
- Returns
- A boolean value, `true` if the sensor is configured, and `false` if not.
2021-04-29 10:40:07 -07:00
### `getDigital(index)`
Reads a digital input from the specified channel.
- Parameters
- `index`: The index of the digital channel to read. See table below for values.
- Returns
- A boolean value representing the state of the input pin. `true` = high voltage (above ~2 volts), `false` = low voltage (below ~3 volts)
Valid `index` parameter values:
| Index | Channel Name |
| --- | ---:|
| 0 | Clutch down switch |
| 1 | Clutch up switch |
| 2 | Brake switch |
| 3 | AC switch |
2021-08-31 09:36:40 -07:00
### `readPin(pinName)`
2021-08-31 09:08:30 -07:00
Reads physical value of arbitrary MCU pin
- Parameters
- `pinName`: string name of MCU pin, for examples "PD15"
2021-04-29 10:40:07 -07:00
## Output
2021-05-20 11:43:48 -07:00
### `startPwm(index, frequency, duty)`
Initializes PWM on the specified index, starting at the specified frequency and duty cycle. The index selects which config field pin to use, see "Lua PWM Outputs" page in TunerStudio.
- Parameters
- `index`: The index of the PWM channel to start. Valid values are 0 through 7, one for each of the 8 channels.
- `frequency`: Initial frequency of the output, in hertz (cycles per second). Valid values are between 1 and 1000hz.
- `duty`: Initial duty cycle of the output. `0.0` = fully off, and `1.0` = fully on. `0.25` = on 25% of the time, off 75% of the time.
- Returns
- none
### `setPwmDuty(index, duty)`
Set the duty cycle of the specified PWM channel.
- Parameters
- `index`: The index of the PWM channel to set.
- `duty`: Desired duty cycle of the output. `0.0` = fully off, and `1.0` = fully on. `0.25` = on 25% of the time, off 75% of the time.
- Returns
- none
### `setPwmFreq(index, frequency)`
- Parameters
- `index`: The index of the PWM channel to set.
- `frequency`: Initial frequency of the output, in hertz (cycles per second). Valid values are between 1 and 1000hz.
- Returns
2021-10-19 07:46:10 -07:00
- none
## Misc console commands
``luamemory``
2021-10-19 07:50:40 -07:00
``luareset``
## Examples
2021-11-26 06:11:41 -08:00
# timer
2021-10-19 07:50:40 -07:00
```
t = Timer.new();
2021-10-19 08:03:19 -07:00
timingAdd = 0;
2021-10-19 07:50:40 -07:00
function onTick()
auxV = getAuxAnalog(0)
2021-10-25 19:06:24 -07:00
tps = getSensor("TPS")
2021-10-19 08:00:56 -07:00
-- todo: check for NIL value which is a sign of analog input not assigned in TS
2021-10-19 07:50:40 -07:00
if auxV > 2 then
t:reset();
end
2021-10-19 08:03:19 -07:00
2021-10-19 07:50:40 -07:00
val = t:getElapsedSeconds();
2021-10-19 08:03:19 -07:00
if t:getElapsedSeconds() < 3 then
timingAdd = 10;
else
timingAdd = 0;
end
setTimingAdd(timingAdd)
2021-10-19 07:50:40 -07:00
print('Hello analog ' .. auxV .. " " .. val)
end
```
2021-10-21 16:38:02 -07:00
2021-11-26 06:11:41 -08:00
# PWM
2021-10-21 16:38:02 -07:00
```
-- index 0, 100Hz, zero duty inititally
startPwm(0, 100, 0)
function onTick()
enable_pump = getSensor("RPM") > 700 and getSensor("BatteryVoltage") > 13 and getSensor("VehicleSpeed") <60
2021-11-27 16:40:08 -08:00
-- lua does not have ternary ? : operator, this here means "1 if enable_pump and 0 otherwise"
setPwmDuty(0, enable_pump and 1 or 0)
2021-10-21 16:38:02 -07:00
2021-10-30 13:48:49 -07:00
end
```
2021-11-26 06:11:41 -08:00
# CAN transmit
2021-10-30 13:48:49 -07:00
```
function onTick()
tps = getSensor("CLT")
print('TPS ' .. tps)
voltage0 = getSensor("aux0")
txPayload = {}
// first byte: integer part, would be autoboxed to int
txPayload[1] = voltage0
// second byte: fractional part, would be autoboxed to int, overflow would be ignored
txPayload[2] = voltage0 * 256;
txCan(1, 0x600, 1, txPayload)
2021-10-21 16:38:02 -07:00
end
2021-11-11 15:21:59 -08:00
```
2021-11-26 06:11:41 -08:00
# CAN receive
```
2021-11-26 06:18:59 -08:00
canRxAdd(0x500)
2021-11-26 06:11:41 -08:00
canRxAdd(0x570)
function onCanRx(bus, id, dlc, data)
print('got CAN id=' .. id .. ' dlc=' .. dlc)
id11 = id % 2048
if id11 == 0x500 then --Check can state of BCM
canState = data[1]
end
end
```
2021-11-26 06:09:42 -08:00
2021-11-26 06:11:41 -08:00
# table
2021-11-26 06:09:42 -08:00
```
tableIndex = findTableIndex("duty")
TurbochargerSpeed = getSensor("TurbochargerSpeed")
2021-11-26 12:23:31 -08:00
tps = getSensor("Tps1")
2021-11-26 06:09:42 -08:00
dutyCycle = table3d(tableIndex, TurbochargerSpeed, tps)
```
2021-11-11 15:21:59 -08:00
## See also
http://lua-users.org/wiki/TernaryOperator