STorM32 Scripts: Difference between revisions
No edit summary |
|||
(115 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
<span style="font-size:88%">'' | <span style="font-size:88%">''The information on this page refers to firmware v2.69a and higher.''</span> | ||
With firmware version v0.51 the possibility of | With firmware version v0.51 the possibility of uploading scripts to the STorM32 controller, which are then executed on-board, without connection to a PC, has been introduced. It allows you to programmatically affect the behavior of the controller in order to achieve user specific needs and tasks with unprecedented flexibility. The STorM32 controller was the first of its kind to offer this innovative feature, which was when later adopted by others. | ||
The on-board scripts bring great possibilities, but | The on-board scripts bring great possibilities, but need some understanding to avoid doing nonsense. This article gives some background, and presents the concepts by means of examples. | ||
== Overview of Script Types == | == Overview of Script Types == | ||
<!-- | |||
The STorM32 on-board scripts should not be confused with other types of scripts, thus a short overview: | |||
* '''''On-board Scripts''''': These scripts are uploaded and stored into the controller, and are executed permanently by the controller. They are programmed by the user via the GUI's {{GUI|Scripts}} tab. | |||
* ''''' | * '''''Motion Control Scripts''''': In older firmware versions, the GUI did incorporate a dedicated Motion Control processor. These scripts were executed on the PC, sending commands to the STorM32 controller via e.g. USB, Bluetooth, or any other serial connection between the PC and the controller. | ||
* '''''Mission Planner Scripts''''': ArduPilot's [http://planner.ardupilot.com/ Mission Planner] allows to run Python scripts, which, similar to Motion Control scripts, are executed on the PC, sending messages to the autopilot. | |||
* '''''Mission Planner Scripts''''': | |||
For all these scripts, the source code is stored in plain ASCII text files (and could hence be edited by any text editor), but the script type can be determined from the default file extension: | For all these scripts, the source code is stored in plain ASCII text files (and could hence be edited by any text editor), but the script type can be determined from the default file extension: | ||
.scr = STorM32 on-board script | .scr = STorM32 on-board script | ||
.mcs = | .mcs = Motion Control script | ||
.py = Mission Planner Python script | .py = Mission Planner Python script | ||
When using the respective tools for handling the scripts, only correct scripts, i.e. files with the correct file extension, should be accessible, | When using the respective tools for handling the scripts, only the correct scripts, i.e. files with the correct file extension, should be accessible with the tools, avoiding confusion. | ||
This article focuses exclusively on the on-board scripts. | This article focuses exclusively on the STorM32 on-board scripts. | ||
--> | |||
The STorM32 on-board scripts should not be confused with other types of scripts. | |||
These on-board scripts are uploaded and stored into the controller, and are executed permanently by the controller. They are programmed by the user via the GUI's {{GUI|Scripts}} tab. The source code is stored in plain ASCII text files (and could hence be edited by any text editor), with default file extension: | |||
.scr = STorM32 on-board script | |||
== Technical Background == | == Technical Background == | ||
Line 29: | Line 35: | ||
Since the code space on the STorM32 controller is very limited (currently only 128 bytes in total are available for the on-board scripts), and especially because of performance reasons the scripts are stored in the controller as binary pseudo code. | Since the code space on the STorM32 controller is very limited (currently only 128 bytes in total are available for the on-board scripts), and especially because of performance reasons the scripts are stored in the controller as binary pseudo code. | ||
The workflow is thus | The workflow is thus as follows: The scripts written in the '''''STorM32 on-board scripting language''''' | ||
are translated into | are translated into pseudo code with a home-brewed compiler, which is integrated into the GUI. The pseudo code is then stored into the STorM32 controller board with a {{GUIFIELD|Write}}. The pseudo code is permanently executed online by the STorM32 controller using an internal pseudo-code processor. | ||
For understanding the internal working one should realize | For understanding the internal working one should realize that the STorM32 controller code is essentially an endless loop, which is triggered and repeated every 1.5 ms. This is called a cycle. Two situations can hence occur in the execution of the pseudo code, namely - first - the next pseudo command should be executed in the same cycle as the previous one, or - second - the next pseudo command should be postponed and executed in the next cycle. Generally, the function commands are of the first kind, while for the control flow commands it depends. | ||
== Usage == | == Usage == | ||
In total four scripts can be run | In total four scripts, named Script1 to Script4, can be run concurrently and independently. For each script, two fields are available in the {{GUI|Scripts}} tab, e.g. for Script1 these are: | ||
* {{PARAMNAME|Script1 Control}} | * {{PARAMNAME|Script1 Control}} | ||
* {{PARAMNAME|Script1}} | * {{PARAMNAME|Script1}} | ||
The first parameter field allows to select | The first parameter field allows us to select the input channel, to which the script should "listen", i.e., which input value is used in the script for e.g. triggering one of the up to five cases (see below). | ||
The second parameter field holds the code. It can be edited via the {{GUIFIELD|Edit Script1}} button. It opens the script editor window, which allows you to write, load and save code. Its syntactic correctness may be checked by doing a {{GUIFIELD|Compile}}. For accepting the code use {{GUIFIELD|Accept and Exit}}. | |||
Script1 is the master script in the sense that it allows us to modify the {{PARAMNAME|Script2 Control}}, {{PARAMNAME|Script3 Control}}, and {{PARAMNAME|Script4 Control}} parameters and hence to affect the behavior of the other scripts, while the other three scripts cannot modify any of script control parameters. | |||
{{COMMENT|The four scripts are actually not run concurrently, but sequentially, and are thus not totally independent on each other. In each cycle, the scripts are processed in the order script1, script2, script3, script4. Therefore, a later script can undo changes made by an earlier script, and an earlier script can make changes which are seen by the later scripts.}} | |||
== Scripting Language == | == Scripting Language == | ||
The on-board scripting language has a relatively rich set of commands, which allows | The on-board scripting language has a relatively rich set of commands, which allows us to modify the controller behavior in reaction to inputs, as well as to control the camera for motion control. | ||
'''''Control flow commands:''''' | '''''Control flow commands:''''' | ||
Line 54: | Line 64: | ||
CASE#2 | CASE#2 | ||
CASE#3 | CASE#3 | ||
CASE#4 | |||
STOP | STOP | ||
REPEAT | REPEAT | ||
WAIT time(int, in 0.1secs) | WAIT time(int, in 0.1secs) | ||
RESTART | |||
The cases are determined by the value of the input selected with the {{PARAMNAME|Scriptx Control}} parameter (where x stands for 1,2,3,4). The value ranges for the CASE statements are (see also [[Inputs_and_Functions#Overview_Diagram|Inputs and Functions: Overview Diagram]]): | |||
* CASE#DEFAULT: -166 ... +166 | |||
* CASE#1: +333 ... +500 | |||
* CASE#2: -500 ... -333 | |||
* CASE#3: +216 ... +277 | |||
* CASE#4: -277 ... -216 | |||
Note that the ranges for CASE#1 and CASE#2 start at +333 and -333, respectively, which corresponds to ca 1833 us and 1167 us (roughly, this is very transmitter dependent). Default transmitter settings may not reach these values. Note also that the ranges for CASE#3 and CASE#4 are relatively narrow, and thus can easily be missed. | |||
'''''Parameter value commands:''''' | '''''Parameter value commands:''''' | ||
SETP parametername(string) option(int, float or string) | |||
SETPMINMAX parametername(string) option(int, float or string) option(int, float or string) | |||
RESTORE | |||
RESTOREALL | |||
SET parametername(string) value(int) | SET parametername(string) value(int) | ||
SETMINMAX parametername(string) minvalue(int) maxvalue(int) | SETMINMAX parametername(string) minvalue(int) maxvalue(int) | ||
The commands {{BOX|SETP}} and {{BOX|SET}} are identical function-wise, namely set a parameter to a value, but differ in the second argument: In {{BOX|SETP}} the set-to value of the parameter is specified as it is displayed in the GUI (except of the unit in value fields), while in {{BOX|SET}} the new value is specified by its internal integer representation. For instance, if the parameter {{PARAMNAME|Camera Model}} should be set to {{PARAMVALUE|GoPro Hero5}}, then the {{BOX|SETP}} command would be {{BOX|SETP "Camera Model" "GoPro Hero5"}}, and the {{BOX|SET}} command would be {{BOX|SET "Camera Model" 10}} (since the option "GoPro Hero5" is internally represented by the integer 10) (you can check this with {{GUI|Share Settings}}). | |||
Similar holds for the second and third parameters in the {{BOX|SETPMINMAX}} and {{BOX|SETMINMAX}} commands. | |||
The {{BOX|SET}} and {{BOX|SETMINMAX}} commands are still existing for compatibility, but should not be used in new scripts (in fact, the script compiler replaced them with the newer {{BOX|SETP}} and {{BOX|SETPMINMAX}} commands). | |||
'''''Function commands:''''' | '''''Function commands:''''' | ||
Line 69: | Line 99: | ||
SETANGLEYAW angle(float, in degree°) | SETANGLEYAW angle(float, in degree°) | ||
SETANGLE pitchangle(float, in degree°) rollangle(float, in degree°) yawangle(float, in degree°) | SETANGLE pitchangle(float, in degree°) rollangle(float, in degree°) yawangle(float, in degree°) | ||
SETANGLEPITCH_W angle(float, in degree°) time(int, in 0.1secs) | |||
SETANGLEROLL_W angle(float, in degree°) time(int, in 0.1secs) | |||
SETANGLEYAW_W angle(float, in degree°) time(int, in 0.1secs) | |||
SETSTANDBY 0/1 | SETSTANDBY 0/1 | ||
SETRETRACT 0/1 | |||
DOCAMERA 0/1/2/3/4 | DOCAMERA 0/1/2/3/4 | ||
DORECENTER | DORECENTER | ||
DORECENTERPITCH | |||
DORECENTERROLL | |||
DORECENTERYAW | |||
DORECENTER_W time(int, in 0.1secs) | |||
DORECENTERPITCH_W time(int, in 0.1secs) | |||
DORECENTERROLL_W time(int, in 0.1secs) | |||
DORECENTERYAW_W time(int, in 0.1secs) | |||
SETPWM pwmvalue(int) | SETPWM pwmvalue(int) | ||
SETPANOWAITS pitchtime(int, in 0.1secs) yawtime(int, in 0.1secs) shottime(int, in 0.1secs) | |||
SETPANORANGE yawangle(int, in degree°) | |||
SETPANOALLOWEXIT | |||
DOPANO pitchangle(int, in degree°) steps(int) | |||
BEEP | |||
Most function commands mirror serial RC commands (both in fact call the same internal functions). For further info thus please see [[Serial_Communication#Serial_Communication_-_RC_Commands|Serial Communication - RC Commands]]. | |||
'''''Additional commands:''''' | |||
REMOTEENABLE | |||
REMOTEDISABLE | |||
The script function commands modify the very same set of internal variables which are also modified by the serial RC commands and MAVLink messages. This can lead to conflicts when the latter are used in combination with scripts, which can be resolved with the {{BOX|REMOTEDISABLE}}/{{BOX|REMOTEENABLE}} script commands. With {{BOX|REMOTEDISABLE}} the scripts are given priority over the serial RC and MAVLink commands. With {{BOX|REMOTEENABLE}} the default behavior is restored. | |||
SENDMAVTEXT text(string) | |||
SENDCAMTEXT text(string) | |||
The {{BOX|SENDMAVTEXT}} command triggers the emission of a MAVLink [https://mavlink.io/en/messages/common.html#STATUSTEXT STATUSTEXT] message. The text is the specified string, prepended by a label "STorM32:". The text string can be 24 characters long, and contain the characters '0'-'9', 'a'-'z', 'A'-'Z', ' '. | |||
The {{BOX|SENDCAMTEXT}} command sends the specified string, appended by a '\n' char, on the {{PARAMNAME|Camera ComPort}}. The text string can be 24 characters long, and contain the characters '0'-'9', 'a'-'z', 'A'-'Z', ' '. Only for {{PARAMNAME|Camera Model}} = {{PARAMVALUE|Serial Api}}. | |||
Prefer short text strings, in order to not exhaust the limited code space for scripts. | |||
== Examples == | == Examples == | ||
Line 78: | Line 141: | ||
=== Changing a Parameter via the Transmitter === | === Changing a Parameter via the Transmitter === | ||
Adjusting the value of a parameter during operation by e.g. tuning a knob on a transmitter is probably the most basic use-case of the scripts. | |||
Let's consider GekoCH's application (see [http://www.rcgroups.com/forums/showpost.php?p=29667070&postcount=19 here]): He's using | Let's consider GekoCH's application as an example (see [http://www.rcgroups.com/forums/showpost.php?p=29667070&postcount=19 here]): He's using a gimbal on a copter, and asked for the possibility to change the speed by which the camera turns upon a rc signal via another rc signal. He used a poti on the transmitter and the absolute mode to adjust the pitch orientation of the camera. It's obviously not possible to simultaneously fly the copter and to move the poti that precisely that a smooth camera motion is obtained, hence the {{PARAMNAME|Speed Limit}} feature was used. That is, the poti is quickly moved to the target orientation, and thanks to the speed limiter a smooth turn of the camera results. However, only one speed was possible before. Three solutions shall be discussed: | ||
'''''Method A''''' | '''''Method A''''' | ||
CASE#DEFAULT | CASE#DEFAULT | ||
SETP "Rc Pitch Speed Limit" 40.0 | |||
STOP | STOP | ||
CASE#1 | CASE#1 | ||
SETP "Rc Pitch Speed Limit" 5.0 | |||
STOP | STOP | ||
When the input specified in the {{PARAMNAME|Script Control}} parameter field yields "default" value, then the pitch speed limit is set to | When the input specified in the {{PARAMNAME|Script Control}} parameter field yields a "default" value, then the pitch speed limit is set to 40.0 °/s, respectively, while when the input value is such to trigger {{BOX|CASE#1}}, then the speed limit is set to 5.0 °/s. Every CASE statement needs to be finished with either a {{BOX|STOP}} or {{BOX|REPEAT}}. Here the {{BOX|STOP}} command is used, which means that the preceding {{BOX|SETP}} command is executed only once when the input value changes, and not every cycle again. | ||
At this point one may ask, which input values triggers which case? The full answer isn't trivial and needs a familiarity with the STorM32 controller. In the given example, the default case is selected then the poti is below ca. 33% (< 1633 us), and case #1 is triggered then the switch is above ca. 83% (> 1830 us). | |||
At this point one | |||
'''''Method B''''' | '''''Method B''''' | ||
SETPMINMAX "Rc Pitch Speed Limit" 5.0 40.0 | |||
REPEAT | REPEAT | ||
The | The {{BOX|SETPMINMAX}} command linearly interpolates between the minimum value (5.0 °/s) and maximum value (40.0 °/s), depending on the input value. For instance, for an input value of 200 the pitch speed limit is set to 200 * (40.0-5.0)/1000 + (40.0+5.0)/2 = 29.5°/s. Hence, method B allows us to adjust the speed limit continuously in the range of 5.0 °/s to 40.0 °/s. The {{BOX|REPEAT}} command at the end ensures, that the {{BOX|SETPMINMAX}} command is executed at every cycle anew, and not just once, so that any change in the input value is quickly tracked. | ||
A video by GekoCH | A video by GekoCH using this feature is [http://www.rcgroups.com/forums/showpost.php?p=30246328&postcount=2723 here]. | ||
'''''Method C''''' | '''''Method C''''' | ||
Line 112: | Line 173: | ||
STOP | STOP | ||
CASE#1 | CASE#1 | ||
SETP "Rc Pitch Speed Limit" 5.0 | |||
STOP | STOP | ||
This example is | This example is essentially method A, but overcomes a minor yet potentially annoying issue. In method A, the parameter value specified in the {{PARAMVALUE|Rc Pitch Speed Limit}} field of the GUI is overwritten immediately by the script, and hence becomes obsolete. In most cases one would however prefer that the default value is determined by the entry in the GUI, and not by that in the script. This issue is resolved by the {{BOX|RESTORE}} command, which sets the {{PARAMVALUE|Rc Pitch Speed Limit}} parameter to the value stored in the EEPROM. | ||
A similar command | A similar {{BOX|RESTOREALL}} command exists, which sets all parameters to their values stored in the EEPROM. However, for efficiency reasons it should not be used, except then it is really absolutely needed. Using several {{BOX|RESTORE}} commands is much preferred over using {{BOX|RESTOREALL}}. In short, avoid {{BOX|RESTOREALL}} if you can. | ||
''''' | '''''Concluding Remarks''''' | ||
Of course, one is not limited to only the {{PARAMNAME|Rc Pitch Speed Limit}} parameter. ANY other available parameter | Of course, one is not limited to only the {{PARAMNAME|Rc Pitch Speed Limit}} parameter. ANY other available parameter (except of the {{PARAMNAME|Script Control}} parameters as discussed before), can be used in the {{BOX|SET}} and {{BOX|SETPMINMAX}} commands and hence be modified by the scripts. Furthermore, any case statement can of course be followed by more than one command, such that complex situations can be tackled (it is though not possible to have another case statement within a case statement). | ||
Up to four cases can be distinguished, via the {{BOX|CASE#DEFAULT}}, {{BOX|CASE#1}}, {{BOX|CASE#2}}, and {{BOX|CASE#3}} statements. A case is chosen dependent on the value of the input selected by the {{PARAMNAME|Script Control}} parameter, in close analogy to all the other available functions such as the Rc Inputs, Pan Control or IR Camera Control, see also [[Inputs and Functions]]. | |||
=== Running a Motion Control Sequence === | === Running a Motion Control Sequence === | ||
Line 152: | Line 213: | ||
This short sequence consumes already 62 of the 128 bytes, which shows that only relatively short motion control sequences are possible with the on-board scripts. | This short sequence consumes already 62 of the 128 bytes, which shows that only relatively short motion control sequences are possible with the on-board scripts. | ||
=== Running a Pano Sequence === | |||
The previous motion control sequence allows to record a pano, which however is severely limited by the maximal possible script code size. Thus, more powerful commands were introduced, which allow quite extensive pano shots. | |||
CASE#DEFAULT | |||
DORECENTER | |||
STOP | |||
CASE#1 | |||
SETANGLEYAW_W 45 30 | |||
SETPANOWAITS 30 30 10 | |||
SETPANORANGE 90 | |||
DOPANO 30 -8 | |||
DOPANO 0 8 | |||
DOPANO -30 -8 | |||
STOP | |||
The {{BOX|SETANGLEYAW_W}} command sets the yaw angle to 45°, and waits 3.0 secs in addition to the predicted time for the turn. | |||
The {{BOX|SETPANOWAITS}} and {{BOX|SETPANORANGE}} commands set some "global" parameters of the pano, namely the time to wait after each pitch movement, the time to wait after each yaw step, the time to wait before each shot, and the total yaw angle range which shall be covered. | |||
The {{BOX|DOPANO}} commands finally run the pano sequence. The first {{BOX|DOPANO}} command, e.g., sets the pitch angle to 30°, and then does 8 yaw steps in counterclockwise direction. In each step the yaw axis is progressed by 90°/8 = 11.25°. Similarly for the next two {{BOX|DOPANAO}} commands. | |||
In the above example, the pano cannot be terminated during execution. That is, the script is executed command by command until it reaches the {{BOX|STOP}} command, and only then it is tested if the input has changed and whether it should jump to CASE#DEFAULT. Often this is the desired behavior, e.g. when the pano is triggered with a momentary push button. Often it is however desired that the pano runs for as long as the input is set but is terminated then it is cleared. A typical use case would be when the pano is triggered with a transmitter switch, there one might want it to run when the switch is flipped but be stopped when the switch is cleared, even if the pano is not yet completed. This can be accomplished with the {{BOX|SETPANOALLOWEXIT}} command. An example script would be | |||
CASE#DEFAULT | |||
STOP | |||
CASE#1 | |||
SETANGLEYAW_W 45 30 | |||
SETPANOWAITS 30 30 10 | |||
SETPANORANGE 90 | |||
SETPANOALLOWEXIT | |||
DOPANO 30 -8 | |||
WAIT 10 | |||
DOPANO -30 8 | |||
DORECENTER | |||
STOP | |||
Note that here only the {{BOX|DOPANO}} commands are cut short if the input becomes different from CASE#1, but that the other commands are still executed until the {{BOX|STOP}} command is reached. That is, in the example, if the input changes while the first {{BOX|DOPANO}} command is executed, the {{BOX|WAIT}} and {{BOX|DORECENTER}} commands would be still executed. | |||
=== Running a Script in Combination with Serial and MAVLink Commands === | |||
The serial RC commands and the MAVLink messages all set the very same internal variables which are also set by the scripts, and conflicts can accordingly occur. | |||
Such a situation occurs, e.g., when the STorM32 controller is connected to an ArduPilot flight controller via MAVLink, and a continuous stream of DO_MOUNT_CONTROL (or similar) MAVLink commands is sent to the STorM32 controller. In this case a pano script for instance would appear to not work since the commands for setting the angle of the gimbal emitted by the script would be nearly instantaneously overwritten by the DO_MOUNT_CONTROL (or similar) MAVLink commands received from the flight controller. | |||
Such situations can be resolved by using the {{BOX|REMOTEDISABLE}} and {{BOX|REMOTEENABLE}} script commands. {{BOX|REMOTEDISABLE}} gives the script priority, and essentially disables the serial and MAVLink commands. With {{BOX|REMOTEENABLE}} the default behavior is restored. | |||
A script using this mechanism would typically look like | |||
CASE#DEFAULT | |||
STOP | |||
CASE#1 | |||
REMOTEDISABLE | |||
... | |||
REMOTEENABLE | |||
STOP | |||
or | |||
CASE#DEFAULT | |||
REMOTEDISABLE | |||
STOP | |||
CASE#1 | |||
REMOTEENABLE | |||
... | |||
STOP | |||
The two script do not exactly work the same and which one to use depends on the actual script. The behavior of the second example could also be achieved as | |||
REMOTEENABLE | |||
CASE#DEFAULT | |||
REMOTEDISABLE | |||
STOP | |||
CASE#1 | |||
... | |||
STOP | |||
which might be easier to write. | |||
== User Examples == | |||
=== Switching Between Two Alternate Functions of a Continuous RC Channel Using a "Shift Key" === | |||
''by Hb121280, see also [https://www.rcgroups.com/forums/showthread.php?2262624-STorM32-BGC-Scripts-Discussion-and-Development-Thread/page2&perpage=50#post39876923]'' | |||
Imagine you want to control gimbal pitch and gimbal yaw using an analog dial on the remote control, but only one analog dial is available. This example uses a button channel to switch between alternate functions of one continuous channel. | |||
CASE#DEFAULT | |||
SETP "Rc Pitch" "Virtual-8" | |||
SETP "Rc Yaw" "off" | |||
STOP | |||
CASE#1 | |||
SETP "Rc Pitch" "Virtual-8" | |||
SETP "Rc Yaw" "off" | |||
STOP | |||
CASE#2 | |||
SETP "Rc Pitch" "Virtual-8" | |||
SETP "Rc Yaw" "off" | |||
STOP | |||
CASE#3 | |||
SETP "Rc Pitch" "off" | |||
SETP "Rc Yaw" "Virtual-8" | |||
STOP | |||
The {{PARAMNAME|Script Control}} variable is set to the button channel, e.g. {{PARAMVALUE|Virtual-8}}. In the present case the button channel delivers a value 0 in case it is not pressed and 254 if it is pressed. According to [[Inputs_and_Functions#Overview_Diagram|Inputs and Functions: Overview Diagram]], the value ranges for the CASE statements are: | |||
* CASE#DEFAULT: -166 ... +166 | |||
* CASE#1: +333 ... +500 | |||
* CASE#2: -500 ... -333 | |||
* CASE#3: +216 ... +277 | |||
Thus, the cases CASE#DEFAULT and CASE#3 have to be used, because the button values 0 (not pressed) and 254 (pressed) fall into their value ranges. The script language does not allow 'missing' case statements, and CASE#1 and CASE#2 need also to be specified (they can be filled with any commands, since they never would be triggered). | |||
In the above script, the standard behavior (button not pressed) uses the analog channel, or input {{PARAMVALUE|Virtual-8}}, for {{PARAMNAME|Rc Pitch}}. {{PARAMNAME|Rc Yaw}} is accordingly set to {{PARAMVALUE|off}}. Pressing the button reverses the assignments: The analog channel on input {{PARAMVALUE|Virtual-8}} is now used for {{PARAMNAME|Rc Yaw}}, and the control of pitch is deactivated. |
Latest revision as of 12:16, 18 November 2023
The information on this page refers to firmware v2.69a and higher.
With firmware version v0.51 the possibility of uploading scripts to the STorM32 controller, which are then executed on-board, without connection to a PC, has been introduced. It allows you to programmatically affect the behavior of the controller in order to achieve user specific needs and tasks with unprecedented flexibility. The STorM32 controller was the first of its kind to offer this innovative feature, which was when later adopted by others.
The on-board scripts bring great possibilities, but need some understanding to avoid doing nonsense. This article gives some background, and presents the concepts by means of examples.
Overview of Script Types
The STorM32 on-board scripts should not be confused with other types of scripts.
These on-board scripts are uploaded and stored into the controller, and are executed permanently by the controller. They are programmed by the user via the GUI's [GUI:Scripts] tab. The source code is stored in plain ASCII text files (and could hence be edited by any text editor), with default file extension:
.scr = STorM32 on-board script
Technical Background
Since the code space on the STorM32 controller is very limited (currently only 128 bytes in total are available for the on-board scripts), and especially because of performance reasons the scripts are stored in the controller as binary pseudo code.
The workflow is thus as follows: The scripts written in the STorM32 on-board scripting language are translated into pseudo code with a home-brewed compiler, which is integrated into the GUI. The pseudo code is then stored into the STorM32 controller board with a [Write]. The pseudo code is permanently executed online by the STorM32 controller using an internal pseudo-code processor.
For understanding the internal working one should realize that the STorM32 controller code is essentially an endless loop, which is triggered and repeated every 1.5 ms. This is called a cycle. Two situations can hence occur in the execution of the pseudo code, namely - first - the next pseudo command should be executed in the same cycle as the previous one, or - second - the next pseudo command should be postponed and executed in the next cycle. Generally, the function commands are of the first kind, while for the control flow commands it depends.
Usage
In total four scripts, named Script1 to Script4, can be run concurrently and independently. For each script, two fields are available in the [GUI:Scripts] tab, e.g. for Script1 these are:
- Script1 Control
- Script1
The first parameter field allows us to select the input channel, to which the script should "listen", i.e., which input value is used in the script for e.g. triggering one of the up to five cases (see below).
The second parameter field holds the code. It can be edited via the [Edit Script1] button. It opens the script editor window, which allows you to write, load and save code. Its syntactic correctness may be checked by doing a [Compile]. For accepting the code use [Accept and Exit].
Script1 is the master script in the sense that it allows us to modify the Script2 Control, Script3 Control, and Script4 Control parameters and hence to affect the behavior of the other scripts, while the other three scripts cannot modify any of script control parameters.
Comment: The four scripts are actually not run concurrently, but sequentially, and are thus not totally independent on each other. In each cycle, the scripts are processed in the order script1, script2, script3, script4. Therefore, a later script can undo changes made by an earlier script, and an earlier script can make changes which are seen by the later scripts.
Scripting Language
The on-board scripting language has a relatively rich set of commands, which allows us to modify the controller behavior in reaction to inputs, as well as to control the camera for motion control.
Control flow commands:
CASE#DEFAULT CASE#1 CASE#2 CASE#3 CASE#4 STOP REPEAT WAIT time(int, in 0.1secs) RESTART
The cases are determined by the value of the input selected with the Scriptx Control parameter (where x stands for 1,2,3,4). The value ranges for the CASE statements are (see also Inputs and Functions: Overview Diagram):
- CASE#DEFAULT: -166 ... +166
- CASE#1: +333 ... +500
- CASE#2: -500 ... -333
- CASE#3: +216 ... +277
- CASE#4: -277 ... -216
Note that the ranges for CASE#1 and CASE#2 start at +333 and -333, respectively, which corresponds to ca 1833 us and 1167 us (roughly, this is very transmitter dependent). Default transmitter settings may not reach these values. Note also that the ranges for CASE#3 and CASE#4 are relatively narrow, and thus can easily be missed.
Parameter value commands:
SETP parametername(string) option(int, float or string) SETPMINMAX parametername(string) option(int, float or string) option(int, float or string) RESTORE RESTOREALL SET parametername(string) value(int) SETMINMAX parametername(string) minvalue(int) maxvalue(int)
The commands SETP and SET are identical function-wise, namely set a parameter to a value, but differ in the second argument: In SETP the set-to value of the parameter is specified as it is displayed in the GUI (except of the unit in value fields), while in SET the new value is specified by its internal integer representation. For instance, if the parameter Camera Model should be set to “GoPro Hero5”, then the SETP command would be SETP "Camera Model" "GoPro Hero5", and the SET command would be SET "Camera Model" 10 (since the option "GoPro Hero5" is internally represented by the integer 10) (you can check this with [GUI:Share Settings]).
Similar holds for the second and third parameters in the SETPMINMAX and SETMINMAX commands.
The SET and SETMINMAX commands are still existing for compatibility, but should not be used in new scripts (in fact, the script compiler replaced them with the newer SETP and SETPMINMAX commands).
Function commands:
SETANGLEPITCH angle(float, in degree°) SETANGLEROLL angle(float, in degree°) SETANGLEYAW angle(float, in degree°) SETANGLE pitchangle(float, in degree°) rollangle(float, in degree°) yawangle(float, in degree°) SETANGLEPITCH_W angle(float, in degree°) time(int, in 0.1secs) SETANGLEROLL_W angle(float, in degree°) time(int, in 0.1secs) SETANGLEYAW_W angle(float, in degree°) time(int, in 0.1secs) SETSTANDBY 0/1 SETRETRACT 0/1 DOCAMERA 0/1/2/3/4 DORECENTER DORECENTERPITCH DORECENTERROLL DORECENTERYAW DORECENTER_W time(int, in 0.1secs) DORECENTERPITCH_W time(int, in 0.1secs) DORECENTERROLL_W time(int, in 0.1secs) DORECENTERYAW_W time(int, in 0.1secs) SETPWM pwmvalue(int) SETPANOWAITS pitchtime(int, in 0.1secs) yawtime(int, in 0.1secs) shottime(int, in 0.1secs) SETPANORANGE yawangle(int, in degree°) SETPANOALLOWEXIT DOPANO pitchangle(int, in degree°) steps(int) BEEP
Most function commands mirror serial RC commands (both in fact call the same internal functions). For further info thus please see Serial Communication - RC Commands.
Additional commands:
REMOTEENABLE REMOTEDISABLE
The script function commands modify the very same set of internal variables which are also modified by the serial RC commands and MAVLink messages. This can lead to conflicts when the latter are used in combination with scripts, which can be resolved with the REMOTEDISABLE/REMOTEENABLE script commands. With REMOTEDISABLE the scripts are given priority over the serial RC and MAVLink commands. With REMOTEENABLE the default behavior is restored.
SENDMAVTEXT text(string) SENDCAMTEXT text(string)
The SENDMAVTEXT command triggers the emission of a MAVLink STATUSTEXT message. The text is the specified string, prepended by a label "STorM32:". The text string can be 24 characters long, and contain the characters '0'-'9', 'a'-'z', 'A'-'Z', ' '.
The SENDCAMTEXT command sends the specified string, appended by a '\n' char, on the Camera ComPort. The text string can be 24 characters long, and contain the characters '0'-'9', 'a'-'z', 'A'-'Z', ' '. Only for Camera Model = “Serial Api”.
Prefer short text strings, in order to not exhaust the limited code space for scripts.
Examples
Changing a Parameter via the Transmitter
Adjusting the value of a parameter during operation by e.g. tuning a knob on a transmitter is probably the most basic use-case of the scripts.
Let's consider GekoCH's application as an example (see here): He's using a gimbal on a copter, and asked for the possibility to change the speed by which the camera turns upon a rc signal via another rc signal. He used a poti on the transmitter and the absolute mode to adjust the pitch orientation of the camera. It's obviously not possible to simultaneously fly the copter and to move the poti that precisely that a smooth camera motion is obtained, hence the Speed Limit feature was used. That is, the poti is quickly moved to the target orientation, and thanks to the speed limiter a smooth turn of the camera results. However, only one speed was possible before. Three solutions shall be discussed:
Method A
CASE#DEFAULT SETP "Rc Pitch Speed Limit" 40.0 STOP CASE#1 SETP "Rc Pitch Speed Limit" 5.0 STOP
When the input specified in the Script Control parameter field yields a "default" value, then the pitch speed limit is set to 40.0 °/s, respectively, while when the input value is such to trigger CASE#1, then the speed limit is set to 5.0 °/s. Every CASE statement needs to be finished with either a STOP or REPEAT. Here the STOP command is used, which means that the preceding SETP command is executed only once when the input value changes, and not every cycle again.
At this point one may ask, which input values triggers which case? The full answer isn't trivial and needs a familiarity with the STorM32 controller. In the given example, the default case is selected then the poti is below ca. 33% (< 1633 us), and case #1 is triggered then the switch is above ca. 83% (> 1830 us).
Method B
SETPMINMAX "Rc Pitch Speed Limit" 5.0 40.0 REPEAT
The SETPMINMAX command linearly interpolates between the minimum value (5.0 °/s) and maximum value (40.0 °/s), depending on the input value. For instance, for an input value of 200 the pitch speed limit is set to 200 * (40.0-5.0)/1000 + (40.0+5.0)/2 = 29.5°/s. Hence, method B allows us to adjust the speed limit continuously in the range of 5.0 °/s to 40.0 °/s. The REPEAT command at the end ensures, that the SETPMINMAX command is executed at every cycle anew, and not just once, so that any change in the input value is quickly tracked.
A video by GekoCH using this feature is here.
Method C
CASE#DEFAULT RESTORE "Rc Pitch Speed Limit" STOP CASE#1 SETP "Rc Pitch Speed Limit" 5.0 STOP
This example is essentially method A, but overcomes a minor yet potentially annoying issue. In method A, the parameter value specified in the “Rc Pitch Speed Limit” field of the GUI is overwritten immediately by the script, and hence becomes obsolete. In most cases one would however prefer that the default value is determined by the entry in the GUI, and not by that in the script. This issue is resolved by the RESTORE command, which sets the “Rc Pitch Speed Limit” parameter to the value stored in the EEPROM.
A similar RESTOREALL command exists, which sets all parameters to their values stored in the EEPROM. However, for efficiency reasons it should not be used, except then it is really absolutely needed. Using several RESTORE commands is much preferred over using RESTOREALL. In short, avoid RESTOREALL if you can.
Concluding Remarks
Of course, one is not limited to only the Rc Pitch Speed Limit parameter. ANY other available parameter (except of the Script Control parameters as discussed before), can be used in the SET and SETPMINMAX commands and hence be modified by the scripts. Furthermore, any case statement can of course be followed by more than one command, such that complex situations can be tackled (it is though not possible to have another case statement within a case statement).
Up to four cases can be distinguished, via the CASE#DEFAULT, CASE#1, CASE#2, and CASE#3 statements. A case is chosen dependent on the value of the input selected by the Script Control parameter, in close analogy to all the other available functions such as the Rc Inputs, Pan Control or IR Camera Control, see also Inputs and Functions.
Running a Motion Control Sequence
CASE#DEFAULT STOP CASE#1 SETANGLE -22.5 0 31.5 WAIT 20 DOCAMERA 1 SETANGLEYAW 0 WAIT 20 DOCAMERA 1 SETANGLEYAW -31.5 WAIT 20 DOCAMERA 1 SETANGLE 22.5 0 -31.5 WAIT 20 DOCAMERA 1 SETANGLEYAW 0 WAIT 20 DOCAMERA 1 SETANGLEYAW 31.5 WAIT 20 DOCAMERA 1 DORECENTER STOP
This short sequence consumes already 62 of the 128 bytes, which shows that only relatively short motion control sequences are possible with the on-board scripts.
Running a Pano Sequence
The previous motion control sequence allows to record a pano, which however is severely limited by the maximal possible script code size. Thus, more powerful commands were introduced, which allow quite extensive pano shots.
CASE#DEFAULT DORECENTER STOP CASE#1 SETANGLEYAW_W 45 30 SETPANOWAITS 30 30 10 SETPANORANGE 90 DOPANO 30 -8 DOPANO 0 8 DOPANO -30 -8 STOP
The SETANGLEYAW_W command sets the yaw angle to 45°, and waits 3.0 secs in addition to the predicted time for the turn.
The SETPANOWAITS and SETPANORANGE commands set some "global" parameters of the pano, namely the time to wait after each pitch movement, the time to wait after each yaw step, the time to wait before each shot, and the total yaw angle range which shall be covered.
The DOPANO commands finally run the pano sequence. The first DOPANO command, e.g., sets the pitch angle to 30°, and then does 8 yaw steps in counterclockwise direction. In each step the yaw axis is progressed by 90°/8 = 11.25°. Similarly for the next two DOPANAO commands.
In the above example, the pano cannot be terminated during execution. That is, the script is executed command by command until it reaches the STOP command, and only then it is tested if the input has changed and whether it should jump to CASE#DEFAULT. Often this is the desired behavior, e.g. when the pano is triggered with a momentary push button. Often it is however desired that the pano runs for as long as the input is set but is terminated then it is cleared. A typical use case would be when the pano is triggered with a transmitter switch, there one might want it to run when the switch is flipped but be stopped when the switch is cleared, even if the pano is not yet completed. This can be accomplished with the SETPANOALLOWEXIT command. An example script would be
CASE#DEFAULT STOP CASE#1 SETANGLEYAW_W 45 30 SETPANOWAITS 30 30 10 SETPANORANGE 90 SETPANOALLOWEXIT DOPANO 30 -8 WAIT 10 DOPANO -30 8 DORECENTER STOP
Note that here only the DOPANO commands are cut short if the input becomes different from CASE#1, but that the other commands are still executed until the STOP command is reached. That is, in the example, if the input changes while the first DOPANO command is executed, the WAIT and DORECENTER commands would be still executed.
Running a Script in Combination with Serial and MAVLink Commands
The serial RC commands and the MAVLink messages all set the very same internal variables which are also set by the scripts, and conflicts can accordingly occur.
Such a situation occurs, e.g., when the STorM32 controller is connected to an ArduPilot flight controller via MAVLink, and a continuous stream of DO_MOUNT_CONTROL (or similar) MAVLink commands is sent to the STorM32 controller. In this case a pano script for instance would appear to not work since the commands for setting the angle of the gimbal emitted by the script would be nearly instantaneously overwritten by the DO_MOUNT_CONTROL (or similar) MAVLink commands received from the flight controller.
Such situations can be resolved by using the REMOTEDISABLE and REMOTEENABLE script commands. REMOTEDISABLE gives the script priority, and essentially disables the serial and MAVLink commands. With REMOTEENABLE the default behavior is restored.
A script using this mechanism would typically look like
CASE#DEFAULT STOP CASE#1 REMOTEDISABLE ... REMOTEENABLE STOP
or
CASE#DEFAULT REMOTEDISABLE STOP CASE#1 REMOTEENABLE ... STOP
The two script do not exactly work the same and which one to use depends on the actual script. The behavior of the second example could also be achieved as
REMOTEENABLE CASE#DEFAULT REMOTEDISABLE STOP CASE#1 ... STOP
which might be easier to write.
User Examples
Switching Between Two Alternate Functions of a Continuous RC Channel Using a "Shift Key"
by Hb121280, see also [1]
Imagine you want to control gimbal pitch and gimbal yaw using an analog dial on the remote control, but only one analog dial is available. This example uses a button channel to switch between alternate functions of one continuous channel.
CASE#DEFAULT SETP "Rc Pitch" "Virtual-8" SETP "Rc Yaw" "off" STOP CASE#1 SETP "Rc Pitch" "Virtual-8" SETP "Rc Yaw" "off" STOP CASE#2 SETP "Rc Pitch" "Virtual-8" SETP "Rc Yaw" "off" STOP CASE#3 SETP "Rc Pitch" "off" SETP "Rc Yaw" "Virtual-8" STOP
The Script Control variable is set to the button channel, e.g. “Virtual-8”. In the present case the button channel delivers a value 0 in case it is not pressed and 254 if it is pressed. According to Inputs and Functions: Overview Diagram, the value ranges for the CASE statements are:
- CASE#DEFAULT: -166 ... +166
- CASE#1: +333 ... +500
- CASE#2: -500 ... -333
- CASE#3: +216 ... +277
Thus, the cases CASE#DEFAULT and CASE#3 have to be used, because the button values 0 (not pressed) and 254 (pressed) fall into their value ranges. The script language does not allow 'missing' case statements, and CASE#1 and CASE#2 need also to be specified (they can be filled with any commands, since they never would be triggered).
In the above script, the standard behavior (button not pressed) uses the analog channel, or input “Virtual-8”, for Rc Pitch. Rc Yaw is accordingly set to “off”. Pressing the button reverses the assignments: The analog channel on input “Virtual-8” is now used for Rc Yaw, and the control of pitch is deactivated.