1
0
Fork 0
mirror of https://github.com/iNavFlight/inav.git synced 2025-07-16 21:05:32 +03:00

Merge pull request #8797 from iNavFlight/MrD_Extended-PF-docs

Update Programming Framework.md
This commit is contained in:
Darren Lines 2023-02-13 10:29:37 +00:00 committed by GitHub
commit eba9413d92
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 351 additions and 37 deletions

View file

@ -11,7 +11,7 @@ INAV Programming Framework coinsists of:
* Global Variables - variables that can store values from and for LogiC Conditions and servo mixer
* Programming PID - general purpose, user configurable PID controllers
IPF can be edited using INAV Configurator user interface, of via CLI
IPF can be edited using INAV Configurator user interface, or via CLI
## Logic Conditions
@ -46,16 +46,16 @@ IPF can be edited using INAV Configurator user interface, of via CLI
| 10 | NAND | `false` if `Operand A` and `Operand B` are both `true`|
| 11 | NOR | `true` if `Operand A` and `Operand B` are both `false` |
| 12 | NOT | The boolean opposite to `Operand A` |
| 13 | STICKY | `Operand A` is activation operator, `Operand B` is deactivation operator. After activation, operator will return `true` until Operand B is evaluated as `true`|
| 13 | STICKY | `Operand A` is the activation operator, `Operand B` is the deactivation operator. After the activation is `true`, the operator will return `true` until Operand B is evaluated as `true`|
| 14 | ADD | Add `Operand A` to `Operand B` and returns the result |
| 15 | SUB | Substract `Operand B` from `Operand A` and returns the result |
| 16 | MUL | Multiply `Operand A` by `Operand B` and returns the result |
| 17 | DIV | Divide `Operand A` by `Operand B` and returns the result |
| 18 | GVAR SET | Store value from `Operand B` into the Global Variable addressed by `Operand B`. Bear in mind, that operand `Global Variable` means: Value stored in Global Variable of an index! To store in GVAR 1 use `Value 1` not `Global Variable 1` |
| 19 | GVAR INC | Increase the GVAR indexed by `Operand A` with value from `Operand B` |
| 20 | GVAR DEC | Decrease the GVAR indexed by `Operand A` with value from `Operand B` |
| 19 | GVAR INC | Increase the GVAR indexed by `Operand A` (use `Value 1` for Global Variable 1) with value from `Operand B` |
| 20 | GVAR DEC | Decrease the GVAR indexed by `Operand A` (use `Value 1` for Global Variable 1) with value from `Operand B` |
| 21 | IO PORT SET | Set I2C IO Expander pin `Operand A` to value of `Operand B`. `Operand A` accepts values `0-7` and `Operand B` accepts `0` and `1` |
| 22 | OVERRIDE_ARMING_SAFETY | Allows to arm on any angle even without GPS fix |
| 22 | OVERRIDE_ARMING_SAFETY | Allows the craft to arm on any angle even without GPS fix. WARNING: This bypasses all safety checks, even that the throttle is low, so use with caution. If you only want to check for certain conditions, such as arm without GPS fix. You will need to add logic conditions to check the throttle is low. |
| 23 | OVERRIDE_THROTTLE_SCALE | Override throttle scale to the value defined by operand. Operand type `0` and value `50` means throttle will be scaled by 50%. |
| 24 | SWAP_ROLL_YAW | basically, when activated, yaw stick will control roll and roll stick will control yaw. Required for tail-sitters VTOL during vertical-horizonral transition when body frame changes |
| 25 | SET_VTX_POWER_LEVEL | Sets VTX power level. Accepted values are `0-3` for SmartAudio and `0-4` for Tramp protocol |
@ -73,17 +73,17 @@ IPF can be edited using INAV Configurator user interface, of via CLI
| 37 | MAP_OUTPUT | Scales `Operand A` from [`0` : `1000`] to [`0` : `Operand B`]. Note: input will be constrained and then scaled |
| 38 | RC_CHANNEL_OVERRIDE | Overrides channel set by `Operand A` to value of `Operand B` |
| 39 | SET_HEADING_TARGET | Sets heading-hold target to `Operand A`, in degrees. Value wraps-around. |
| 40 | MOD | Divide `Operand A` by `Operand B` and returns the remainder |
| 40 | MOD | Modulo. Divide `Operand A` by `Operand B` and returns the remainder |
| 41 | LOITER_RADIUS_OVERRIDE | Sets the loiter radius to `Operand A` [`0` : `100000`] in cm. If the value is lower than the loiter radius set in the **Advanced Tuning**, that will be used. |
| 42 | SET_PROFILE | Sets the active config profile (PIDFF/Rates/Filters/etc) to `Operand A`. `Operand A` must be a valid profile number, currently from 1 to 3. If not, the profile will not change |
| 43 | MIN | Finds the lowest value of `Operand A` and `Operand B` |
| 44 | MAX | Finds the highest value of `Operand A` and `Operand B` |
| 45 | FLIGHT_AXIS_ANGLE_OVERRIDE | Sets the target attitude angle for axis. In other words, when active, it enforces Angle mode (Heading Hold for Yaw) on this axis (Angle mode does not have to be active). `Operand A` defines the axis: `0` - Roll, `1` - Pitch, `2` - Yaw. `Operand B` defines the angle in degrees |
| 46 | FLIGHT_AXIS_RATE_OVERRIDE | Sets the target rate (rotation speed) for axis. `Operand A` defines the axis: `0` - Roll, `1` - Pitch, `2` - Yaw. `Operand B` defines the rate in degrees per second |
| 47 | EDGE | `Operand A` is activation operator [`boolean`], `Operand B` _(Optional)_ is the time for the edge to stay active [ms]. After activation, operator will return `true` until the time in Operand B is reached. If a pure momentary edge is wanted. Just leave `Operand B` as the default `Value: 0` setting. |
| 48 | DELAY | This will return `true` when `Operand A` is true, and the delay time in `Operand B` [ms] has been exceeded. |
| 49 | TIMER | `true` for the duration of `Operand A` [ms]. Then `false` for the duration of `Operand B` [ms]. |
| 50 | DELTA | This returns `true` when the value of `Operand A` has changed by the value of `Operand B` or greater. |
| 47 | EDGE | Momentarily true when triggered by `Operand A`. `Operand A` is the activation operator [`boolean`], `Operand B` _(Optional)_ is the time for the edge to stay active [ms]. After activation, operator will return `true` until the time in Operand B is reached. If a pure momentary edge is wanted. Just leave `Operand B` as the default `Value: 0` setting. |
| 48 | DELAY | Delays activation after being triggered. This will return `true` when `Operand A` _is_ true, and the delay time in `Operand B` [ms] has been exceeded. |
| 49 | TIMER | A simple on - off timer. `true` for the duration of `Operand A` [ms]. Then `false` for the duration of `Operand B` [ms]. |
| 50 | DELTA | This returns `true` when the value of `Operand A` has changed by the value of `Operand B` or greater within 100ms. |
| 51 | APPROX_EQUAL | `true` if `Operand B` is within 1% of `Operand A`. |
### Operands
@ -143,43 +143,45 @@ IPF can be edited using INAV Configurator user interface, of via CLI
#### FLIGHT_MODE
The flight mode operands return `true` when the mode is active. These are modes that you will see in the **Modes** tab. Note: the `USER*` modes are used by camera switchers, PINIO etc. They are not the Waypoint User Actions. See the [Waypoints](#waypoints) section to access those.
| Operand Value | Name | Notes |
|---------------|-------------------|-------|
| 0 | FAILSAFE | |
| 1 | MANUAL | |
| 2 | RTH | |
| 3 | POSHOLD | |
| 4 | CRUISE | |
| 5 | ALTHOLD | |
| 6 | ANGLE | |
| 7 | HORIZON | |
| 8 | AIR | |
| 9 | USER1 | |
| 10 | USER2 | |
| 11 | COURSE_HOLD | |
| 12 | USER3 | |
| 13 | USER4 | |
| 14 | ACRO | |
| 15 | WAYPOINT_MISSION | |
| 0 | FAILSAFE | `true` when a **Failsafe** state has been triggered. |
| 1 | MANUAL | `true` when you are in the **Manual** flight mode. |
| 2 | RTH | `true` when you are in the **Return to Home** flight mode. |
| 3 | POSHOLD | `true` when you are in the **Position Hold** or **Loiter** flight modes. |
| 4 | CRUISE | `true` when you are in the **Cruise** flight mode. |
| 5 | ALTHOLD | `true` when you the **Altitude Hold** flight mode modifier is active. |
| 6 | ANGLE | `true` when you are in the **Angle** flight mode. |
| 7 | HORIZON | `true` when you are in the **Horizon** flight mode. |
| 8 | AIR | `true` when you the **Airmode** flight mode modifier is active. |
| 9 | USER1 | `true` when the **USER 1** mode is active. |
| 10 | USER2 | `true` when the **USER 21** mode is active. |
| 11 | COURSE_HOLD | `true` when you are in the **Course Hold** flight mode. |
| 12 | USER3 | `true` when the **USER 3** mode is active. |
| 13 | USER4 | `true` when the **USER 4** mode is active. |
| 14 | ACRO | `true` when you are in the **Acro** flight mode. |
| 15 | WAYPOINT_MISSION | `true` when you are in the **WP Mission** flight mode. |
#### WAYPOINTS
| Operand Value | Name | Notes |
|---------------|-------------------------------|-------|
| 0 | Is WP | boolean `0`/`1` |
| 0 | Is WP | Boolean `0`/`1` |
| 1 | Current Waypoint Index | Current waypoint leg. Indexed from `1`. To verify WP is in progress, use `Is WP` |
| 2 | Current Waypoint Action | Action active in current leg. See ACTIVE_WAYPOINT_ACTION table |
| 3 | Next Waypoint Action | Action active in next leg. See ACTIVE_WAYPOINT_ACTION table |
| 2 | Current Waypoint Action | `true` when Action active in current leg. See ACTIVE_WAYPOINT_ACTION table |
| 3 | Next Waypoint Action | `true` when Action active in next leg. See ACTIVE_WAYPOINT_ACTION table |
| 4 | Distance to next Waypoint | Distance to next WP in metres |
| 5 | Distance from Waypoint | Distance from the last WP in metres |
| 6 | User Action 1 | User Action 1 is active on this waypoint leg [boolean `0`/`1`] |
| 7 | User Action 2 | User Action 2 is active on this waypoint leg [boolean `0`/`1`] |
| 8 | User Action 3 | User Action 3 is active on this waypoint leg [boolean `0`/`1`] |
| 9 | User Action 4 | User Action 4 is active on this waypoint leg [boolean `0`/`1`] |
| 10 | Next Waypoint User Action 1 | User Action 1 is active on the next waypoint leg [boolean `0`/`1`] |
| 11 | Next Waypoint User Action 2 | User Action 2 is active on the next waypoint leg [boolean `0`/`1`] |
| 12 | Next Waypoint User Action 3 | User Action 3 is active on the next waypoint leg [boolean `0`/`1`] |
| 13 | Next Waypoint User Action 4 | User Action 4 is active on the next waypoint leg [boolean `0`/`1`] |
| 6 | User Action 1 | `true` when User Action 1 is active on this waypoint leg [boolean `0`/`1`] |
| 7 | User Action 2 | `true` when User Action 2 is active on this waypoint leg [boolean `0`/`1`] |
| 8 | User Action 3 | `true` when User Action 3 is active on this waypoint leg [boolean `0`/`1`] |
| 9 | User Action 4 | `true` when User Action 4 is active on this waypoint leg [boolean `0`/`1`] |
| 10 | Next Waypoint User Action 1 | `true` when User Action 1 is active on the next waypoint leg [boolean `0`/`1`] |
| 11 | Next Waypoint User Action 2 | `true` when User Action 2 is active on the next waypoint leg [boolean `0`/`1`] |
| 12 | Next Waypoint User Action 3 | `true` when User Action 3 is active on the next waypoint leg [boolean `0`/`1`] |
| 13 | Next Waypoint User Action 4 | `true` when User Action 4 is active on the next waypoint leg [boolean `0`/`1`] |
#### ACTIVE_WAYPOINT_ACTION

312
src/utils/draft_rn_settings.rb Executable file
View file

@ -0,0 +1,312 @@
#!/usr/bin/env ruby
# coding: utf-8
##
## This file is part of INAV.
##
## INAV is free software. You can redistribute this software
## and/or modify this software under the terms of the
## GNU General Public License as published by the Free Software
## Foundation, either version 3 of the License, or (at your option)
## any later version.
##
## INAV is distributed in the hope that they will be
## useful, but WITHOUT ANY WARRANTY; without even the implied
## warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
## See the GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this software.
##
## If not, see <http://www.gnu.org/licenses/>.
##
#########################################################################
#
# Generates a formatted (Markdown) report of CLI settings differences
# between two INAV branches or tags. Primarily intended for inclusion
# in release notes.
#
# Note that the report will require review / editing before inclusing
# in the RN, but it will jabe done the vast majority of the work for
# you.
#
# Example:
#
# draft_rn_settings.rb -f 5.1.0 -t release_6.0.0 > /tmp/draft-set6.0RN.md
# # now review /tmp/draft-set6.0RN.md for inclusion in the offical RN
#
# Requirments:
# * ruby (v3 recommended)
# * git
#
#########################################################################
require 'yaml'
require 'optparse'
require 'tmpdir'
base = File.join(ENV["HOME"], "Projects/fc/inav")
ntag = nil
otag = nil
ARGV.options do |opt|
opt.banner = "#{File.basename($0)} [options]"
opt.on('-t','--tag=TAG', 'New tag or branch') {|o|ntag=o}
opt.on('-f','--from-tag=TAG', 'previous release tag or branch'){|o|otag=o}
opt.on('-b','--base=DIR', "Base of the inav repo [#{base}]" ) {|o|base=o}
opt.on('-?', "--help", "Show this message") {puts opt.to_s; exit}
begin
opt.parse!
rescue
puts opt
exit
end
end
abort 'New tag / branch is mandatory' unless ntag
abort 'Old tag / branch is mandatory' unless otag
begin
Dir.chdir(base)
rescue
abort "Cannot chdir to #{base}"
end
oldyaml = File.join(Dir.tmpdir, ".setting_old.yaml")
newyaml = File.join(Dir.tmpdir, ".setting_new.yaml")
system "> #{oldyaml} git show #{otag}:src/main/fc/settings.yaml"
system "> #{newyaml} git show #{ntag}:src/main/fc/settings.yaml"
h_old = {}
begin
h_old = YAML.load_file(oldyaml)
rescue
abort "Error reading old settings yaml"
end
h_new = {}
begin
h_new = YAML.load_file(newyaml)
rescue
abort "Error reading new settings yaml"
end
ot_names = []
h_old["tables"].each do |t|
ot_names << t["name"]
end
nt_names = []
h_new["tables"].each do |t|
nt_names << t["name"]
end
puts "# Draft Rel Notes -- settings helper"
puts
puts "The following should make a reasonable first pass at new / changed / removed settings"
puts "Will require manual checking / refining / formatting."
d = nt_names.difference(ot_names).sort
unless d.empty?
puts
puts "# New (Tables) -- to update group values"
puts
puts "| Name | Values |"
puts "| ---- | ------ |"
d.each do |dn|
t = h_new["tables"].select{|k| k["name"] == dn}.first
unless t.nil?
vals = t["values"]
if vals[0].class == String
vals.map!{|a| "`#{a}`"}
end
vs = vals.join(", ")
puts "| #{dn} | #{vs} |"
end
end
end
puts
d= ot_names.difference(nt_names).sort
unless d.empty?
puts
puts "## Removed (tables -- check for group value later)"
puts
puts "| Name | Comment |"
puts "| ---- | ------ |"
d.each do |dn|
t = h_old["tables"].select{|k| k["name"] == dn}.first
unless t.nil?
puts "| #{dn} | |"
end
end
end
d=ot_names.intersection(nt_names).sort
unless d.empty?
puts
puts "## Changed (table values -- check for group value later)"
puts
puts "| Name | Values |"
puts "| ---- | ------ |"
d.each do |dn|
tnew = h_new["tables"].select{|k| k["name"] == dn}.first
told = h_old["tables"].select{|k| k["name"] == dn}.first
unless told.nil? && tnew.nil?
if told["values"] != tnew["values"]
vals = tnew["values"].difference(told["values"])
if !vals.empty?
if vals[0].class == String
vals.map!{|a| "`#{a}`"}
end
newvals = vals.join(", ")
puts "| #{dn} | New: #{newvals} |"
end
vals = told["values"].difference(tnew["values"])
if !vals.empty?
if vals[0].class == String
vals.map!{|a| "`#{a}`"}
end
remvals = vals.join(", ")
puts "| #{dn} | Removed: #{remvals} |"
end
end
end
end
end
og_names = []
h_old["groups"].each do |h|
h["members"].each do |m|
og_names << m["name"]
end
end
ng_names = []
h_new["groups"].each do |h|
h["members"].each do |m|
ng_names << m["name"]
end
end
d = ng_names.difference(og_names).sort
unless d.empty?
puts
puts "## New Items"
puts
puts "| Name | Description |"
puts "| ---- | ------ |"
d.each do |dn|
t=nil
h_new["groups"].each do |hh|
t = hh["members"].select{|k| k["name"] == dn}.first
unless t.nil?
desc = t["description"]||""
minmax = []
if t.has_key?("min")
case t["min"]
when Integer
minmax[0] = t["min"]
when "INT16_MIN"
minmax[0] = -32768
when "INT8_MIN"
minmax[0] = -128
end
end
if t.has_key?("max")
case t["max"]
when Integer
minmax[1] = t["max"]
when "UINT16_MAX"
minmax[1] = 65535
when "INT16_MAX"
minmax[1] = 32767
when "INT8_MAX"
minmax[1] = 127
when "UINT8_MAX"
minmax[1] = 255
end
minmax[0] = 0 if !minmax[1].nil? && minmax[0].nil?
end
if minmax.size == 2
desc = [desc," Values: #{minmax[0]} - #{minmax[1]}"].join
end
default = nil
if t.has_key?("default_value")
default = t["default_value"].to_s.upcase
unless default.nil?
desc = "#{desc} Default: #{default}"
end
end
desc.gsub!('|',',')
# default_value max min
puts "| #{dn} | #{desc} |"
break
end
end
end
end
d = og_names.difference(ng_names).sort
unless d.empty?
puts
puts "## Removed Items"
puts
puts "| Name | Description |"
puts "| ---- | ------ |"
d.each do |dn|
puts "| #{dn} | |"
end
end
d=ot_names.intersection(nt_names).sort
unless d.empty?
puts
puts "## Changed Items (desc, range, default -- requires checking)"
puts
puts "Most of the content here will be indicated by a change at the table level"
puts
puts "| Name | Values |"
puts "| ---- | ------ |"
d.each do |dn|
tnew = told = nil
h_new["groups"].each do |hh|
tnew = hh["members"].select{|k| k["name"] == dn}.first
break unless tnew.nil?
end
h_old["groups"].each do |hh|
told = hh["members"].select{|k| k["name"] == dn}.first
break unless told.nil?
end
# in the following tests we discard just the addtion of an attribute
unless (told.nil? && tnew.nil?)
diffs = []
if told["default_value"] && told["default_value"] != tnew["default_value"]
diffs << "Default: #{tnew["default_value"]}"
end
if told["description"] && told["description"] != tnew["description"]
diffs << tnew["description"]
end
unless diffs.empty?
diffstr = diffs.join(" ")
puts "| #{dn} | #{diffstr} |"
end
end
end
end
puts "Last updated: #{Time.now.utc.strftime("%FT%T%Z")}"
begin
File.unlink(oldyaml, newyaml)
rescue
end