Merge branch 'master' into custom-servo-mixers

This commit is contained in:
Dominic Clifton 2015-07-08 12:11:49 +01:00
commit bb0f909e83
26 changed files with 1394 additions and 248 deletions

View File

@ -27,7 +27,7 @@ OPBL ?=no
DEBUG ?=
# Serial port/Device for flashing
SERIAL_DEVICE ?= /dev/ttyUSB0
SERIAL_DEVICE ?= $(firstword $(wildcard /dev/ttyUSB*) no-port-found)
# Flash size (KB). Some low-end chips actually have more flash than advertised, use this to override.
FLASH_SIZE ?=
@ -229,6 +229,7 @@ COMMON_SRC = build_config.c \
flight/imu.c \
flight/mixer.c \
flight/lowpass.c \
flight/filter.c \
drivers/bus_i2c_soft.c \
drivers/serial.c \
drivers/sound_beeper.c \

View File

@ -146,6 +146,8 @@ These chips are also supported:
* Micron/ST M25P16 - 16 Mbit
* Micron N25Q064 - 64 Mbit
* Winbond W25Q64 - 64 Mbit
* Micron N25Q0128 - 128 Mbit
* Winbond W25Q128 - 128 Mbit
## Enabling the Blackbox (CLI)
In the [Cleanflight Configurator][] , enter the CLI tab. Enable the Blackbox feature by typing in `feature BLACKBOX` and
@ -242,4 +244,4 @@ tool:
https://github.com/cleanflight/blackbox-log-viewer
This allows you to scroll around a graphed version of your log and examine your log in detail.
This allows you to scroll around a graphed version of your log and examine your log in detail.

View File

@ -65,4 +65,5 @@ When SOFTSERIAL is enabled, LED_STRIP and CURRENT_METER are unavailable, but two
| |
|O O|
\-------[USB]-------/
```
```

View File

@ -246,6 +246,9 @@ Re-apply any new defaults as desired.
| `p_vel` | | 0 | 200 | 120 | Profile | UINT8 |
| `i_vel` | | 0 | 200 | 45 | Profile | UINT8 |
| `d_vel` | | 0 | 200 | 1 | Profile | UINT8 |
| `dterm_cut_hz` | Lowpass cutoff filter for Dterm for all PID controllers | 0 | 200 | 0 | Profile | UINT8 |
| `pterm_cut_hz` | Lowpass cutoff filter for Pterm for all PID controllers | 0 | 200 | 0 | Profile | UINT8 |
| `gyro_cut_hz` | Lowpass cutoff filter for gyro input | 0 | 200 | 0 | Profile | UINT8 | | 0 | 200 | 0 | Profile | UINT8 |
| `yaw_p_limit` | Limiter for yaw P term. This parameter is only affecting PID controller 3-5. To disable set to 500 (actual default). | 100 | 500 | 500 | Profile | UINT16 |
| `blackbox_rate_num` | | 1 | 32 | 1 | Master | UINT8 |
| `blackbox_rate_denom` | | 1 | 32 | 1 | Master | UINT8 |

View File

@ -2,11 +2,11 @@
## Arming
When armed, the aircraft is ready to fly and the motors will spin when throttle is applied. The motors will
When armed, the aircraft is ready to fly and the motors will spin when throttle is applied. The motors will
spin at a slow speed when armed (this feature may be disabled by setting MOTOR_STOP, but for safety reasons,
that is not recommended).
By default, arming and disarming is done using stick positions. (NOTE: this feature is disabled when using a
By default, arming and disarming is done using stick positions. (NOTE: this feature is disabled when using a
switch to arm.)
## Stick Positions
@ -23,11 +23,11 @@ The stick positions are combined to activate different functions:
| Function | Throttle | Yaw | Pitch | Roll |
| ----------------------------- | -------- | ------- | ------ | ------ |
| ARM | LOW | HIGH | CENTER | CENTER |
| ARM | LOW | HIGH | CENTER | CENTER |
| DISARM | LOW | LOW | CENTER | CENTER |
| Profile 1 | LOW | LOW | CENTER | LOW |
| Profile 2 | LOW | LOW | HIGH | CENTER |
| Profile 3 | LOW | LOW | CENTER | HIGH |
| Profile 1 | LOW | LOW | CENTER | LOW |
| Profile 2 | LOW | LOW | HIGH | CENTER |
| Profile 3 | LOW | LOW | CENTER | HIGH |
| Calibrate Gyro | LOW | LOW | LOW | CENTER |
| Calibrate Acc | HIGH | LOW | LOW | CENTER |
| Calibrate Mag/Compass | HIGH | HIGH | LOW | CENTER |
@ -40,8 +40,9 @@ The stick positions are combined to activate different functions:
| Enable LCD Page Cycling | LOW | CENTER | HIGH | HIGH |
| Save setting | LOW | LOW | LOW | HIGH |
![Stick Positions](assets/images/StickPositions.png)
Download a graphic [cheat sheet](https://multiwii.googlecode.com/svn/branches/Hamburger/MultiWii-StickConfiguration-23_v0-5772156649.pdf) with Tx stick commands (the latest version can always be found
Download a graphic [cheat sheet](https://multiwii.googlecode.com/svn/branches/Hamburger/MultiWii-StickConfiguration-23_v0-5772156649.pdf) with Tx stick commands (the latest version can always be found
[here](https://code.google.com/p/multiwii/source/browse/#svn%2Fbranches%2FHamburger)).
## Yaw control

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

View File

@ -0,0 +1,805 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="2478.5964mm"
height="1086.9835mm"
viewBox="0 0 8782.4284 3851.5164"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="StickPositions.svg"
inkscape:export-filename="C:\Users\stuphi\Dropbox\projects\quad\StickPositions.png"
inkscape:export-xdpi="74.996788"
inkscape:export-ydpi="74.996788">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.08"
inkscape:cx="2990.2403"
inkscape:cy="3041.654"
inkscape:document-units="px"
inkscape:current-layer="g4157"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1137"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
fit-margin-top="1"
fit-margin-left="1"
fit-margin-right="1"
fit-margin-bottom="1"
units="mm"
showborder="true" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Frame"
inkscape:groupmode="layer"
id="layer1"
transform="translate(2203.3186,1653.7717)"
style="display:inline" />
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="StickCentre"
style="display:inline"
transform="translate(2203.3186,1962.0394)" />
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="StickDown"
style="display:inline"
transform="translate(2203.3186,1962.0394)" />
<g
style="display:inline"
inkscape:label="StickDownLeft"
id="g4169"
inkscape:groupmode="layer"
transform="translate(2203.3186,1962.0394)" />
<g
inkscape:groupmode="layer"
id="g4173"
inkscape:label="StickDownRight"
style="display:inline"
transform="translate(2203.3186,1962.0394)" />
<g
style="display:inline"
inkscape:label="StickUpRight"
id="g4177"
inkscape:groupmode="layer"
transform="translate(2203.3186,1962.0394)" />
<g
inkscape:groupmode="layer"
id="g4181"
inkscape:label="StickUpLeft"
style="display:inline"
transform="translate(2203.3186,1962.0394)" />
<g
style="display:inline"
inkscape:label="StickRight"
id="g4161"
inkscape:groupmode="layer"
transform="translate(2203.3186,1962.0394)" />
<g
inkscape:groupmode="layer"
id="g4165"
inkscape:label="StickLeft"
style="display:inline"
transform="translate(2203.3186,1962.0394)" />
<g
inkscape:label="StickUp"
id="g4157"
inkscape:groupmode="layer"
style="display:inline"
transform="translate(2203.3186,1962.0394)">
<rect
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4136"
width="288.94339"
height="288.94339"
x="708.38544"
y="-1390.3773"
ry="0" />
<path
inkscape:transform-center-x="-73.935657"
inkscape:transform-center-y="73.935654"
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 948.22718,-1104.1681 c 7.47613,7.4761 23.9146,3.1588 36.71634,-9.6429 12.80173,-12.8017 17.11898,-29.2402 9.64285,-36.7163 -7.47612,-7.4762 -126.05745,-105.3018 -138.85919,-92.5 -12.80175,12.8017 85.02386,131.383 92.5,138.8592 z"
id="path4175"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssss" />
<rect
ry="0"
y="-1390.3773"
x="1114.0997"
height="288.94339"
width="288.94339"
id="rect4208"
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<circle
r="31.819805"
cy="-1245.9056"
cx="1258.5714"
id="circle4210"
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:10;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:286.5987854px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="486.66803"
y="-1140.8967"
id="text4574"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="486.668"
y="-1140.8967"
id="tspan4578"
style="text-align:end;text-anchor:end">Arm</tspan></text>
<rect
ry="0"
y="-969.96918"
x="708.38544"
height="288.94339"
width="288.94339"
id="rect4615"
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:transform-center-x="73.935653"
inkscape:transform-center-y="73.935654"
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 756.60309,-683.75996 c -7.47613,7.47613 -23.9146,3.15888 -36.71634,-9.64286 -12.80173,-12.80174 -17.11899,-29.2402 -9.64285,-36.71634 7.47612,-7.47614 126.05745,-105.30174 138.85919,-92.5 12.80175,12.80174 -85.02386,131.38307 -92.5,138.8592 z"
id="path4621"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssss" />
<rect
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4637"
width="288.94339"
height="288.94339"
x="1114.0997"
y="-969.96918"
ry="0" />
<circle
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:10;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="circle4639"
cx="1258.5714"
cy="-825.4975"
r="31.819805" />
<text
sodipodi:linespacing="125%"
id="text4657"
y="-720.48853"
x="486.66803"
style="font-style:normal;font-weight:normal;font-size:286.5987854px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="text-align:end;text-anchor:end"
id="tspan4659"
y="-720.48853"
x="486.66803"
sodipodi:role="line">Disarm</tspan></text>
<rect
ry="0"
y="-549.56104"
x="708.38544"
height="288.94339"
width="288.94339"
id="rect4667"
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:transform-center-x="73.935653"
inkscape:transform-center-y="73.935654"
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 756.60309,-263.35179 c -7.47613,7.47613 -23.9146,3.15888 -36.71634,-9.64286 -12.80173,-12.80174 -17.11899,-29.2402 -9.64285,-36.71634 7.47612,-7.47614 126.05745,-105.30174 138.85919,-92.5 12.80175,12.80174 -85.02386,131.38307 -92.5,138.8592 z"
id="path4673"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssss" />
<rect
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4689"
width="288.94339"
height="288.94339"
x="1114.0997"
y="-549.56104"
ry="0" />
<path
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 1090.881,-372.67398 c -10.5728,0 -19.1438,-14.67651 -19.1438,-32.7809 0,-18.10439 8.571,-32.7809 19.1438,-32.7809 10.5729,-1e-5 163.5957,14.6765 163.5957,32.7809 0,18.1044 -153.0228,32.78091 -163.5957,32.7809 z"
id="path4705"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssss"
inkscape:transform-center-x="94.95434"
inkscape:transform-center-y="0.5050695" />
<text
sodipodi:linespacing="125%"
id="text4709"
y="-300.08038"
x="486.66803"
style="font-style:normal;font-weight:normal;font-size:286.5987854px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="text-align:end;text-anchor:end"
id="tspan4711"
y="-300.08038"
x="486.668"
sodipodi:role="line">Profile 1</tspan></text>
<rect
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4719"
width="288.94339"
height="288.94339"
x="708.38544"
y="-129.15286"
ry="0" />
<path
sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
id="path4725"
d="m 756.60309,157.05638 c -7.47613,7.47613 -23.9146,3.15888 -36.71634,-9.64286 -12.80173,-12.80174 -17.11899,-29.2402 -9.64285,-36.71634 7.47612,-7.47614 126.05745,-105.30174 138.85919,-92.5 12.80175,12.80174 -85.02386,131.38307 -92.5,138.8592 z"
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:transform-center-y="73.935654"
inkscape:transform-center-x="73.935653" />
<rect
ry="0"
y="-129.15286"
x="1114.0997"
height="288.94339"
width="288.94339"
id="rect4741"
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 1291.3523,-149.39445 c 0,-10.57285 -14.6765,-19.14384 -32.7809,-19.14384 -18.1043,0 -32.7809,8.57099 -32.7809,19.14384 0,10.57285 14.6765,163.59566 32.7809,163.59566 18.1044,0 32.781,-153.02281 32.7809,-163.59566 z"
id="path4759"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssss" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:286.5987854px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="486.66803"
y="120.3278"
id="text4761"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="486.668"
y="120.3278"
id="tspan4763"
style="text-align:end;text-anchor:end">Profile 2</tspan></text>
<rect
ry="0"
y="291.25531"
x="708.38544"
height="288.94339"
width="288.94339"
id="rect4771"
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:transform-center-x="73.935653"
inkscape:transform-center-y="73.935654"
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 756.60309,577.46454 c -7.47613,7.47613 -23.9146,3.15888 -36.71634,-9.64286 -12.80173,-12.80174 -17.11899,-29.2402 -9.64285,-36.71634 7.47612,-7.47614 126.05745,-105.30174 138.85919,-92.5 12.80175,12.80174 -85.02386,131.38307 -92.5,138.8592 z"
id="path4777"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssss" />
<rect
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4793"
width="288.94339"
height="288.94339"
x="1114.0997"
y="291.25531"
ry="0" />
<path
sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
id="path4807"
d="m 1425.2415,403.08564 c 10.5729,0 19.1439,14.67651 19.1439,32.7809 0,18.10439 -8.571,32.7809 -19.1439,32.7809 -10.5728,10e-6 -163.5957,-14.6765 -163.5957,-32.7809 0,-18.1044 153.0229,-32.78091 163.5957,-32.7809 z"
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<text
sodipodi:linespacing="125%"
id="text4813"
y="540.73602"
x="486.66803"
style="font-style:normal;font-weight:normal;font-size:286.5987854px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="text-align:end;text-anchor:end"
id="tspan4815"
y="540.73602"
x="486.668"
sodipodi:role="line">Profile 3</tspan></text>
<rect
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4823"
width="288.94339"
height="288.94339"
x="708.38544"
y="711.66351"
ry="0" />
<path
sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
id="path4829"
d="m 756.60309,997.87274 c -7.47613,7.47616 -23.9146,3.15886 -36.71634,-9.64286 -12.80173,-12.80174 -17.11899,-29.2402 -9.64285,-36.71634 7.47612,-7.47614 126.05745,-105.30174 138.85919,-92.5 12.80175,12.80174 -85.02386,131.38307 -92.5,138.8592 z"
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:transform-center-y="73.935654"
inkscape:transform-center-x="73.935653" />
<rect
ry="0"
y="711.66351"
x="1114.0997"
height="288.94339"
width="288.94339"
id="rect4845"
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
id="path4849"
d="m 1291.3523,1021.9347 c 0,10.5728 -14.6765,19.1438 -32.7809,19.1438 -18.1043,0 -32.7809,-8.571 -32.7809,-19.1438 0,-10.5729 14.6765,-163.5957 32.7809,-163.5957 18.1044,0 32.781,153.0228 32.7809,163.5957 z"
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:286.5987854px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="486.66803"
y="961.14417"
id="text4865"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="486.66791"
y="961.14417"
id="tspan4867"
style="text-align:end;text-anchor:end">Calibrate Gyro</tspan></text>
<rect
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4875"
width="288.94339"
height="288.94339"
x="708.38544"
y="1132.0717"
ry="0" />
<path
inkscape:transform-center-x="73.935669"
inkscape:transform-center-y="-73.935654"
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 757.10817,1133.9385 c -7.47613,-7.4762 -23.9146,-3.1589 -36.71634,9.6428 -12.80173,12.8018 -17.11899,29.2402 -9.64285,36.7164 7.47612,7.4761 126.05745,105.3017 138.85919,92.5 12.80175,-12.8018 -85.02386,-131.3831 -92.5,-138.8592 z"
id="path4887"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssss" />
<rect
ry="0"
y="1132.0717"
x="1114.0997"
height="288.94339"
width="288.94339"
id="rect4897"
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
id="path4901"
d="m 1291.3523,1442.3429 c 0,10.5728 -14.6765,19.1438 -32.7809,19.1438 -18.1043,0 -32.7809,-8.571 -32.7809,-19.1438 0,-10.5729 14.6765,-163.5957 32.7809,-163.5957 18.1044,0 32.781,153.0228 32.7809,163.5957 z"
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:286.5987854px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="486.66803"
y="1381.5524"
id="text4917"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="486.66803"
y="1381.5524"
id="tspan4919"
style="text-align:end;text-anchor:end">Calibrate Acc</tspan></text>
<rect
ry="0"
y="1552.4799"
x="708.38544"
height="288.94339"
width="288.94339"
id="rect4927"
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:transform-center-x="-73.935665"
inkscape:transform-center-y="-73.935654"
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 948.22718,1554.3467 c 7.47613,-7.4762 23.9146,-3.1589 36.71634,9.6428 12.80173,12.8018 17.11898,29.2402 9.64285,36.7164 -7.47612,7.4761 -126.05745,105.3017 -138.85919,92.5 -12.80175,-12.8018 85.02386,-131.3831 92.5,-138.8592 z"
id="path4937"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssss" />
<rect
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4949"
width="288.94339"
height="288.94339"
x="1114.0997"
y="1552.4799"
ry="0" />
<path
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 1291.3523,1862.7511 c 0,10.5728 -14.6765,19.1438 -32.7809,19.1438 -18.1043,0 -32.7809,-8.571 -32.7809,-19.1438 0,-10.5729 14.6765,-163.5957 32.7809,-163.5957 18.1044,0 32.781,153.0228 32.7809,163.5957 z"
id="path4953"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssss" />
<text
sodipodi:linespacing="125%"
id="text4969"
y="1801.9606"
x="486.66803"
style="font-style:normal;font-weight:normal;font-size:286.5987854px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="text-align:end;text-anchor:end"
id="tspan4971"
y="1801.9606"
x="486.66791"
sodipodi:role="line">Calibrate Compass</tspan></text>
<rect
ry="0"
y="-1390.3773"
x="5835.5283"
height="288.94339"
width="288.94339"
id="rect5607"
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:transform-center-x="73.935653"
inkscape:transform-center-y="73.935654"
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 5883.7461,-1104.1681 c -7.4762,7.4761 -23.9146,3.1588 -36.7164,-9.6429 -12.8017,-12.8017 -17.119,-29.2402 -9.6428,-36.7163 7.4761,-7.4762 126.0574,-105.3018 138.8592,-92.5 12.8017,12.8017 -85.0239,131.383 -92.5,138.8592 z"
id="path5613"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssss" />
<rect
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect5629"
width="288.94339"
height="288.94339"
x="6241.2427"
y="-1390.3773"
ry="0" />
<path
sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
id="path5639"
d="m 6481.0845,-1388.5106 c 7.4761,-7.4762 23.9146,-3.1589 36.7163,9.6428 12.8017,12.8018 17.119,29.2402 9.6428,36.7164 -7.4761,7.4761 -126.0574,105.3017 -138.8591,92.5 -12.8018,-12.8018 85.0238,-131.3831 92.5,-138.8592 z"
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:transform-center-y="-73.935654"
inkscape:transform-center-x="-73.935665" />
<text
sodipodi:linespacing="125%"
id="text5649"
y="-1140.8967"
x="5613.811"
style="font-style:normal;font-weight:normal;font-size:286.5987854px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="text-align:end;text-anchor:end"
id="tspan5651"
y="-1140.8967"
x="5613.811"
sodipodi:role="line">In-flight Calibration Controls</tspan></text>
<rect
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect5659"
width="288.94339"
height="288.94339"
x="5835.5283"
y="-969.96918"
ry="0" />
<path
sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
id="path5677"
d="m 6012.781,-990.21079 c 0,-10.57281 -14.6765,-19.14381 -32.7809,-19.14381 -18.1044,0 -32.7809,8.571 -32.7809,19.14381 0,10.57285 14.6765,163.59566 32.7809,163.59566 18.1044,0 32.7809,-153.02281 32.7809,-163.59566 z"
style="opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
ry="0"
y="-969.96918"
x="6241.2427"
height="288.94339"
width="288.94339"
id="rect5681"
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:transform-center-y="0.5050695"
inkscape:transform-center-x="94.95434"
sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
id="path5697"
d="m 6218.024,-793.08215 c -10.5729,0 -19.1438,-14.67651 -19.1438,-32.7809 0,-18.10439 8.5709,-32.7809 19.1438,-32.7809 10.5728,-10e-6 163.5957,14.6765 163.5957,32.7809 0,18.1044 -153.0229,32.78091 -163.5957,32.7809 z"
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:286.5987854px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="5613.811"
y="-720.48853"
id="text5701"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="5613.811"
y="-720.48853"
id="tspan5703"
style="text-align:end;text-anchor:end">Trim Acc Left</tspan></text>
<rect
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect5711"
width="288.94339"
height="288.94339"
x="5835.5283"
y="-549.56104"
ry="0" />
<path
sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
id="path5729"
d="m 6012.781,-569.80262 c 0,-10.57285 -14.6765,-19.14384 -32.7809,-19.14384 -18.1044,0 -32.7809,8.57099 -32.7809,19.14384 0,10.57285 14.6765,163.59566 32.7809,163.59566 18.1044,0 32.7809,-153.02281 32.7809,-163.59566 z"
style="opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
ry="0"
y="-549.56104"
x="6241.2427"
height="288.94339"
width="288.94339"
id="rect5733"
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 6552.3845,-437.73069 c 10.5728,0 19.1438,14.67651 19.1438,32.7809 0,18.10439 -8.571,32.7809 -19.1438,32.7809 -10.5729,10e-6 -163.5957,-14.6765 -163.5957,-32.7809 0,-18.1044 153.0228,-32.78091 163.5957,-32.7809 z"
id="path5747"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssss" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:286.5987854px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="5613.811"
y="-300.08038"
id="text5753"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="5613.811"
y="-300.08038"
id="tspan5755"
style="text-align:end;text-anchor:end">Trim Acc Right</tspan></text>
<rect
ry="0"
y="-129.15286"
x="5835.5283"
height="288.94339"
width="288.94339"
id="rect5763"
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 6012.781,-149.39445 c 0,-10.57285 -14.6765,-19.14384 -32.7809,-19.14384 -18.1044,0 -32.7809,8.57099 -32.7809,19.14384 0,10.57285 14.6765,163.59566 32.7809,163.59566 18.1044,0 32.7809,-153.02281 32.7809,-163.59566 z"
id="path5781"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssss" />
<rect
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect5785"
width="288.94339"
height="288.94339"
x="6241.2427"
y="-129.15286"
ry="0" />
<path
sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
id="path5803"
d="m 6418.4953,-149.39445 c 0,-10.57285 -14.6765,-19.14384 -32.7809,-19.14384 -18.1044,0 -32.7809,8.57099 -32.7809,19.14384 0,10.57285 14.6765,163.59566 32.7809,163.59566 18.1044,0 32.7809,-153.02281 32.7809,-163.59566 z"
style="opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<text
sodipodi:linespacing="125%"
id="text5805"
y="120.3278"
x="5613.811"
style="font-style:normal;font-weight:normal;font-size:286.5987854px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="text-align:end;text-anchor:end"
id="tspan5807"
y="120.3278"
x="5613.811"
sodipodi:role="line">Trim Acc Forwards</tspan></text>
<rect
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect5815"
width="288.94339"
height="288.94339"
x="5835.5283"
y="291.25531"
ry="0" />
<path
sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
id="path5833"
d="m 6012.781,271.01371 c 0,-10.57285 -14.6765,-19.14384 -32.7809,-19.14384 -18.1044,0 -32.7809,8.57099 -32.7809,19.14384 0,10.57285 14.6765,163.59566 32.7809,163.59566 18.1044,0 32.7809,-153.02281 32.7809,-163.59566 z"
style="opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
ry="0"
y="291.25531"
x="6241.2427"
height="288.94339"
width="288.94339"
id="rect5837"
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
id="path5841"
d="m 6418.4953,601.52646 c 0,10.57285 -14.6765,19.14384 -32.7809,19.14384 -18.1044,0 -32.7809,-8.57099 -32.7809,-19.14384 0,-10.57285 14.6765,-163.59566 32.7809,-163.59566 18.1044,0 32.7809,153.02281 32.7809,163.59566 z"
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:286.5987854px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="5613.811"
y="540.73602"
id="text5857"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="5613.811"
y="540.73602"
id="tspan5859"
style="text-align:end;text-anchor:end">Trim Acc Backwards</tspan></text>
<rect
ry="0"
y="711.66351"
x="5835.5283"
height="288.94339"
width="288.94339"
id="rect5867"
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
id="path5871"
d="m 6012.781,1021.9347 c 0,10.5728 -14.6765,19.1438 -32.7809,19.1438 -18.1044,0 -32.7809,-8.571 -32.7809,-19.1438 0,-10.5729 14.6765,-163.5957 32.7809,-163.5957 18.1044,0 32.7809,153.0228 32.7809,163.5957 z"
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect5889"
width="288.94339"
height="288.94339"
x="6241.2427"
y="711.66351"
ry="0" />
<path
inkscape:transform-center-x="73.935669"
inkscape:transform-center-y="-73.935654"
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 6289.9654,713.53025 c -7.4761,-7.47613 -23.9146,-3.15888 -36.7163,9.64286 -12.8017,12.80174 -17.119,29.2402 -9.6428,36.71634 7.4761,7.47614 126.0574,105.30174 138.8591,92.5 12.8018,-12.80174 -85.0238,-131.38307 -92.5,-138.8592 z"
id="path5901"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssss" />
<text
sodipodi:linespacing="125%"
id="text5909"
y="961.14417"
x="5613.811"
style="font-style:normal;font-weight:normal;font-size:286.5987854px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="text-align:end;text-anchor:end"
id="tspan5911"
y="961.14417"
x="5613.811"
sodipodi:role="line">Disable LCD Page Cycling</tspan></text>
<rect
ry="0"
y="1132.0717"
x="5835.5283"
height="288.94339"
width="288.94339"
id="rect5919"
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
id="path5923"
d="m 6012.781,1442.3429 c 0,10.5728 -14.6765,19.1438 -32.7809,19.1438 -18.1044,0 -32.7809,-8.571 -32.7809,-19.1438 0,-10.5729 14.6765,-163.5957 32.7809,-163.5957 18.1044,0 32.7809,153.0228 32.7809,163.5957 z"
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect5941"
width="288.94339"
height="288.94339"
x="6241.2427"
y="1132.0717"
ry="0" />
<path
sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
id="path5951"
d="m 6481.0845,1133.9385 c 7.4761,-7.4762 23.9146,-3.1589 36.7163,9.6428 12.8017,12.8018 17.119,29.2402 9.6428,36.7164 -7.4761,7.4761 -126.0574,105.3017 -138.8591,92.5 -12.8018,-12.8018 85.0238,-131.3831 92.5,-138.8592 z"
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:transform-center-y="-73.935654"
inkscape:transform-center-x="-73.935665" />
<text
sodipodi:linespacing="125%"
id="text5961"
y="1381.5524"
x="5613.811"
style="font-style:normal;font-weight:normal;font-size:286.5987854px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="text-align:end;text-anchor:end"
id="tspan5963"
y="1381.5524"
x="5613.811"
sodipodi:role="line">Enable LCD Page Cycling</tspan></text>
<rect
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect5971"
width="288.94339"
height="288.94339"
x="5835.5283"
y="1552.4799"
ry="0" />
<path
sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
id="path5977"
d="m 5883.7461,1838.6891 c -7.4762,7.4762 -23.9146,3.1589 -36.7164,-9.6428 -12.8017,-12.8018 -17.119,-29.2402 -9.6428,-36.7164 7.4761,-7.4761 126.0574,-105.3017 138.8592,-92.5 12.8017,12.8018 -85.0239,131.3831 -92.5,138.8592 z"
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:transform-center-y="73.935654"
inkscape:transform-center-x="73.935653" />
<rect
ry="0"
y="1552.4799"
x="6241.2427"
height="288.94339"
width="288.94339"
id="rect5993"
style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#808080;stroke-width:11.05660725;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
id="path6001"
d="m 6481.0845,1838.6891 c 7.4761,7.4762 23.9146,3.1589 36.7163,-9.6428 12.8017,-12.8018 17.119,-29.2402 9.6428,-36.7164 -7.4761,-7.4761 -126.0574,-105.3017 -138.8591,-92.5 -12.8018,12.8018 85.0238,131.3831 92.5,138.8592 z"
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8.07780743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:transform-center-y="73.935654"
inkscape:transform-center-x="-73.935657" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:286.5987854px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="5613.811"
y="1801.9606"
id="text6013"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="5613.811"
y="1801.9606"
id="tspan6015"
style="text-align:end;text-anchor:end">Save Setting</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:352.85842896px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="2179.2813"
y="-1690.4064"
id="text7907"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="2179.2813"
y="-1690.4064"
id="tspan7909"
style="text-align:center;text-anchor:middle">Mode 2 Stick Functions</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -217,26 +217,26 @@ enum EP_BUF_NUM
#define _SetBTABLE(wRegValue)(*BTABLE = (uint16_t)(wRegValue & 0xFFF8))
/* GetCNTR */
#define _GetCNTR() ((uint16_t) *CNTR)
#define _GetCNTR() ((__IO uint16_t) *CNTR)
/* GetISTR */
#define _GetISTR() ((uint16_t) *ISTR)
#define _GetISTR() ((__IO uint16_t) *ISTR)
/* GetFNR */
#define _GetFNR() ((uint16_t) *FNR)
#define _GetFNR() ((__IO uint16_t) *FNR)
/* GetDADDR */
#define _GetDADDR() ((uint16_t) *DADDR)
#define _GetDADDR() ((__IO uint16_t) *DADDR)
/* GetBTABLE */
#define _GetBTABLE() ((uint16_t) *BTABLE)
#define _GetBTABLE() ((__IO uint16_t) *BTABLE)
/* SetENDPOINT */
#define _SetENDPOINT(bEpNum,wRegValue) (*(EP0REG + bEpNum)= \
(uint16_t)wRegValue)
/* GetENDPOINT */
#define _GetENDPOINT(bEpNum) ((uint16_t)(*(EP0REG + bEpNum)))
#define _GetENDPOINT(bEpNum) ((__IO uint16_t)(*(EP0REG + bEpNum)))
/*******************************************************************************
* Macro Name : SetEPType
@ -334,9 +334,9 @@ enum EP_BUF_NUM
* Output : None.
* Return : status .
*******************************************************************************/
#define _GetEPTxStatus(bEpNum) ((uint16_t)_GetENDPOINT(bEpNum) & EPTX_STAT)
#define _GetEPTxStatus(bEpNum) ((__IO uint16_t)_GetENDPOINT(bEpNum) & EPTX_STAT)
#define _GetEPRxStatus(bEpNum) ((uint16_t)_GetENDPOINT(bEpNum) & EPRX_STAT)
#define _GetEPRxStatus(bEpNum) ((__IO uint16_t)_GetENDPOINT(bEpNum) & EPRX_STAT)
/*******************************************************************************
* Macro Name : SetEPTxValid / SetEPRxValid
@ -446,12 +446,12 @@ enum EP_BUF_NUM
* Output : None.
* Return : None.
*******************************************************************************/
#define _GetEPAddress(bEpNum) ((uint8_t)(_GetENDPOINT(bEpNum) & EPADDR_FIELD))
#define _GetEPAddress(bEpNum) ((__IO uint8_t)(_GetENDPOINT(bEpNum) & EPADDR_FIELD))
#define _pEPTxAddr(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8 )*2 + PMAAddr))
#define _pEPTxCount(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8+2)*2 + PMAAddr))
#define _pEPRxAddr(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8+4)*2 + PMAAddr))
#define _pEPRxCount(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8+6)*2 + PMAAddr))
#define _pEPTxAddr(bEpNum) ((__IO uint32_t *)((_GetBTABLE()+bEpNum*8 )*2 + PMAAddr))
#define _pEPTxCount(bEpNum) ((__IO uint32_t *)((_GetBTABLE()+bEpNum*8+2)*2 + PMAAddr))
#define _pEPRxAddr(bEpNum) ((__IO uint32_t *)((_GetBTABLE()+bEpNum*8+4)*2 + PMAAddr))
#define _pEPRxCount(bEpNum) ((__IO uint32_t *)((_GetBTABLE()+bEpNum*8+6)*2 + PMAAddr))
/*******************************************************************************
* Macro Name : SetEPTxAddr / SetEPRxAddr.
@ -471,8 +471,8 @@ enum EP_BUF_NUM
* Output : None.
* Return : address of the buffer.
*******************************************************************************/
#define _GetEPTxAddr(bEpNum) ((uint16_t)*_pEPTxAddr(bEpNum))
#define _GetEPRxAddr(bEpNum) ((uint16_t)*_pEPRxAddr(bEpNum))
#define _GetEPTxAddr(bEpNum) ((__IO uint16_t)*_pEPTxAddr(bEpNum))
#define _GetEPRxAddr(bEpNum) ((__IO uint16_t)*_pEPRxAddr(bEpNum))
/*******************************************************************************
* Macro Name : SetEPCountRxReg.
@ -505,7 +505,7 @@ enum EP_BUF_NUM
#define _SetEPRxDblBuf0Count(bEpNum,wCount) {\
uint32_t *pdwReg = _pEPTxCount(bEpNum); \
__IO uint32_t *pdwReg = _pEPTxCount(bEpNum); \
_SetEPCountRxReg(pdwReg, wCount);\
}
/*******************************************************************************
@ -518,7 +518,7 @@ enum EP_BUF_NUM
*******************************************************************************/
#define _SetEPTxCount(bEpNum,wCount) (*_pEPTxCount(bEpNum) = wCount)
#define _SetEPRxCount(bEpNum,wCount) {\
uint32_t *pdwReg = _pEPRxCount(bEpNum); \
__IO uint32_t *pdwReg = _pEPRxCount(bEpNum); \
_SetEPCountRxReg(pdwReg, wCount);\
}
/*******************************************************************************
@ -528,8 +528,8 @@ enum EP_BUF_NUM
* Output : None.
* Return : Counter value.
*******************************************************************************/
#define _GetEPTxCount(bEpNum)((uint16_t)(*_pEPTxCount(bEpNum)) & 0x3ff)
#define _GetEPRxCount(bEpNum)((uint16_t)(*_pEPRxCount(bEpNum)) & 0x3ff)
#define _GetEPTxCount(bEpNum)((__IO uint16_t)(*_pEPTxCount(bEpNum)) & 0x3ff)
#define _GetEPRxCount(bEpNum)((__IO uint16_t)(*_pEPRxCount(bEpNum)) & 0x3ff)
/*******************************************************************************
* Macro Name : SetEPDblBuf0Addr / SetEPDblBuf1Addr.

View File

@ -81,6 +81,7 @@
#define BLACKBOX_I_INTERVAL 32
#define BLACKBOX_SHUTDOWN_TIMEOUT_MILLIS 200
#define SLOW_FRAME_INTERVAL 4096
#define ARRAY_LENGTH(x) (sizeof((x))/sizeof((x)[0]))
@ -97,35 +98,18 @@
static const char blackboxHeader[] =
"H Product:Blackbox flight data recorder by Nicholas Sherlock\n"
"H Blackbox version:1\n"
"H Data version:2\n"
"H I interval:" STR(BLACKBOX_I_INTERVAL) "\n";
static const char* const blackboxMainHeaderNames[] = {
"I name",
"I signed",
"I predictor",
"I encoding",
"P predictor",
"P encoding"
static const char* const blackboxFieldHeaderNames[] = {
"name",
"signed",
"predictor",
"encoding",
"predictor",
"encoding"
};
#ifdef GPS
static const char* const blackboxGPSGHeaderNames[] = {
"G name",
"G signed",
"G predictor",
"G encoding"
};
static const char* const blackboxGPSHHeaderNames[] = {
"H name",
"H signed",
"H predictor",
"H encoding"
};
#endif
/* All field definition structs should look like this (but with longer arrs): */
typedef struct blackboxFieldDefinition_t {
const char *name;
@ -136,7 +120,30 @@ typedef struct blackboxFieldDefinition_t {
uint8_t arr[1];
} blackboxFieldDefinition_t;
typedef struct blackboxMainFieldDefinition_t {
#define BLACKBOX_DELTA_FIELD_HEADER_COUNT ARRAY_LENGTH(blackboxFieldHeaderNames)
#define BLACKBOX_SIMPLE_FIELD_HEADER_COUNT (BLACKBOX_DELTA_FIELD_HEADER_COUNT - 2)
#define BLACKBOX_CONDITIONAL_FIELD_HEADER_COUNT (BLACKBOX_DELTA_FIELD_HEADER_COUNT - 2)
typedef struct blackboxSimpleFieldDefinition_t {
const char *name;
int8_t fieldNameIndex;
uint8_t isSigned;
uint8_t predict;
uint8_t encode;
} blackboxSimpleFieldDefinition_t;
typedef struct blackboxConditionalFieldDefinition_t {
const char *name;
int8_t fieldNameIndex;
uint8_t isSigned;
uint8_t predict;
uint8_t encode;
uint8_t condition; // Decide whether this field should appear in the log
} blackboxConditionalFieldDefinition_t;
typedef struct blackboxDeltaFieldDefinition_t {
const char *name;
int8_t fieldNameIndex;
@ -146,17 +153,7 @@ typedef struct blackboxMainFieldDefinition_t {
uint8_t Ppredict;
uint8_t Pencode;
uint8_t condition; // Decide whether this field should appear in the log
} blackboxMainFieldDefinition_t;
typedef struct blackboxGPSFieldDefinition_t {
const char *name;
int8_t fieldNameIndex;
uint8_t isSigned;
uint8_t predict;
uint8_t encode;
uint8_t condition; // Decide whether this field should appear in the log
} blackboxGPSFieldDefinition_t;
} blackboxDeltaFieldDefinition_t;
/**
* Description of the blackbox fields we are writing in our main intra (I) and inter (P) frames. This description is
@ -164,7 +161,7 @@ typedef struct blackboxGPSFieldDefinition_t {
* the encoding to happen, we have to encode the flight log ourselves in write{Inter|Intra}frame() in a way that matches
* the encoding we've promised here).
*/
static const blackboxMainFieldDefinition_t blackboxMainFields[] = {
static const blackboxDeltaFieldDefinition_t blackboxMainFields[] = {
/* loopIteration doesn't appear in P frames since it always increments */
{"loopIteration",-1, UNSIGNED, .Ipredict = PREDICT(0), .Iencode = ENCODING(UNSIGNED_VB), .Ppredict = PREDICT(INC), .Pencode = FLIGHT_LOG_FIELD_ENCODING_NULL, CONDITION(ALWAYS)},
/* Time advances pretty steadily so the P-frame prediction is a straight line */
@ -226,7 +223,7 @@ static const blackboxMainFieldDefinition_t blackboxMainFields[] = {
#ifdef GPS
// GPS position/vel frame
static const blackboxGPSFieldDefinition_t blackboxGpsGFields[] = {
static const blackboxConditionalFieldDefinition_t blackboxGpsGFields[] = {
{"time", -1, UNSIGNED, PREDICT(LAST_MAIN_FRAME_TIME), ENCODING(UNSIGNED_VB), CONDITION(NOT_LOGGING_EVERY_FRAME)},
{"GPS_numSat", -1, UNSIGNED, PREDICT(0), ENCODING(UNSIGNED_VB), CONDITION(ALWAYS)},
{"GPS_coord", 0, SIGNED, PREDICT(HOME_COORD), ENCODING(SIGNED_VB), CONDITION(ALWAYS)},
@ -237,28 +234,69 @@ static const blackboxGPSFieldDefinition_t blackboxGpsGFields[] = {
};
// GPS home frame
static const blackboxGPSFieldDefinition_t blackboxGpsHFields[] = {
{"GPS_home", 0, SIGNED, PREDICT(0), ENCODING(SIGNED_VB), CONDITION(ALWAYS)},
{"GPS_home", 1, SIGNED, PREDICT(0), ENCODING(SIGNED_VB), CONDITION(ALWAYS)}
static const blackboxSimpleFieldDefinition_t blackboxGpsHFields[] = {
{"GPS_home", 0, SIGNED, PREDICT(0), ENCODING(SIGNED_VB)},
{"GPS_home", 1, SIGNED, PREDICT(0), ENCODING(SIGNED_VB)}
};
#endif
// Rarely-updated fields
static const blackboxSimpleFieldDefinition_t blackboxSlowFields[] = {
{"flightModeFlags", -1, UNSIGNED, PREDICT(0), ENCODING(UNSIGNED_VB)},
{"stateFlags", -1, UNSIGNED, PREDICT(0), ENCODING(UNSIGNED_VB)},
{"failsafePhase", -1, UNSIGNED, PREDICT(0), ENCODING(UNSIGNED_VB)}
};
typedef enum BlackboxState {
BLACKBOX_STATE_DISABLED = 0,
BLACKBOX_STATE_STOPPED,
BLACKBOX_STATE_SEND_HEADER,
BLACKBOX_STATE_SEND_FIELDINFO,
BLACKBOX_STATE_SEND_GPS_H_HEADERS,
BLACKBOX_STATE_SEND_GPS_G_HEADERS,
BLACKBOX_STATE_SEND_MAIN_FIELD_HEADER,
BLACKBOX_STATE_SEND_GPS_H_HEADER,
BLACKBOX_STATE_SEND_GPS_G_HEADER,
BLACKBOX_STATE_SEND_SLOW_HEADER,
BLACKBOX_STATE_SEND_SYSINFO,
BLACKBOX_STATE_RUNNING,
BLACKBOX_STATE_SHUTTING_DOWN
} BlackboxState;
typedef struct gpsState_t {
typedef struct blackboxMainState_t {
uint32_t time;
int32_t axisPID_P[XYZ_AXIS_COUNT], axisPID_I[XYZ_AXIS_COUNT], axisPID_D[XYZ_AXIS_COUNT];
int16_t rcCommand[4];
int16_t gyroADC[XYZ_AXIS_COUNT];
int16_t accSmooth[XYZ_AXIS_COUNT];
int16_t motor[MAX_SUPPORTED_MOTORS];
int16_t servo[MAX_SUPPORTED_SERVOS];
uint16_t vbatLatest;
uint16_t amperageLatest;
#ifdef BARO
int32_t BaroAlt;
#endif
#ifdef MAG
int16_t magADC[XYZ_AXIS_COUNT];
#endif
#ifdef SONAR
int32_t sonarRaw;
#endif
uint16_t rssi;
} blackboxMainState_t;
typedef struct blackboxGpsState_t {
int32_t GPS_home[2], GPS_coord[2];
uint8_t GPS_numSat;
} gpsState_t;
} blackboxGpsState_t;
// This data is updated really infrequently:
typedef struct blackboxSlowState_t {
uint16_t flightModeFlags;
uint8_t stateFlags;
uint8_t failsafePhase;
} __attribute__((__packed__)) blackboxSlowState_t; // We pack this struct so that padding doesn't interfere with memcmp()
//From mixer.c:
extern uint8_t motorCount;
@ -292,7 +330,8 @@ static uint32_t blackboxConditionCache;
STATIC_ASSERT((sizeof(blackboxConditionCache) * 8) >= FLIGHT_LOG_FIELD_CONDITION_NEVER, too_many_flight_log_conditions);
static uint32_t blackboxIteration;
static uint32_t blackboxPFrameIndex, blackboxIFrameIndex;
static uint16_t blackboxPFrameIndex, blackboxIFrameIndex;
static uint16_t blackboxSlowFrameIterationTimer;
/*
* We store voltages in I-frames relative to this, which was the voltage when the blackbox was activated.
@ -301,13 +340,14 @@ static uint32_t blackboxPFrameIndex, blackboxIFrameIndex;
*/
static uint16_t vbatReference;
static gpsState_t gpsHistory;
static blackboxGpsState_t gpsHistory;
static blackboxSlowState_t slowHistory;
// Keep a history of length 2, plus a buffer for MW to store the new values into
static blackboxValues_t blackboxHistoryRing[3];
static blackboxMainState_t blackboxHistoryRing[3];
// These point into blackboxHistoryRing, use them to know where to store history of a given age (0, 1 or 2 generations old)
static blackboxValues_t* blackboxHistory[3];
static blackboxMainState_t* blackboxHistory[3];
static bool testBlackboxConditionUncached(FlightLogFieldCondition condition)
{
@ -403,9 +443,10 @@ static void blackboxSetState(BlackboxState newState)
xmitState.headerIndex = 0;
xmitState.u.startTime = millis();
break;
case BLACKBOX_STATE_SEND_FIELDINFO:
case BLACKBOX_STATE_SEND_GPS_G_HEADERS:
case BLACKBOX_STATE_SEND_GPS_H_HEADERS:
case BLACKBOX_STATE_SEND_MAIN_FIELD_HEADER:
case BLACKBOX_STATE_SEND_GPS_G_HEADER:
case BLACKBOX_STATE_SEND_GPS_H_HEADER:
case BLACKBOX_STATE_SEND_SLOW_HEADER:
xmitState.headerIndex = 0;
xmitState.u.fieldIndex = -1;
break;
@ -416,6 +457,7 @@ static void blackboxSetState(BlackboxState newState)
blackboxIteration = 0;
blackboxPFrameIndex = 0;
blackboxIFrameIndex = 0;
blackboxSlowFrameIterationTimer = SLOW_FRAME_INTERVAL; //Force a slow frame to be written on the first iteration
break;
case BLACKBOX_STATE_SHUTTING_DOWN:
xmitState.u.startTime = millis();
@ -429,7 +471,7 @@ static void blackboxSetState(BlackboxState newState)
static void writeIntraframe(void)
{
blackboxValues_t *blackboxCurrent = blackboxHistory[0];
blackboxMainState_t *blackboxCurrent = blackboxHistory[0];
int x;
blackboxWrite('I');
@ -531,8 +573,8 @@ static void writeInterframe(void)
int x;
int32_t deltas[8];
blackboxValues_t *blackboxCurrent = blackboxHistory[0];
blackboxValues_t *blackboxLast = blackboxHistory[1];
blackboxMainState_t *blackboxCurrent = blackboxHistory[0];
blackboxMainState_t *blackboxLast = blackboxHistory[1];
blackboxWrite('P');
@ -638,6 +680,60 @@ static void writeInterframe(void)
blackboxHistory[0] = ((blackboxHistory[0] - blackboxHistoryRing + 1) % 3) + blackboxHistoryRing;
}
/* Write the contents of the global "slowHistory" to the log as an "S" frame. Because this data is logged so
* infrequently, delta updates are not reasonable, so we log independent frames. */
static void writeSlowFrame(void)
{
blackboxWrite('S');
blackboxWriteUnsignedVB(slowHistory.flightModeFlags);
blackboxWriteUnsignedVB(slowHistory.stateFlags);
blackboxWriteUnsignedVB(slowHistory.failsafePhase);
blackboxSlowFrameIterationTimer = 0;
}
/**
* Load rarely-changing values from the FC into the given structure
*/
static void loadSlowState(blackboxSlowState_t *slow)
{
slow->flightModeFlags = flightModeFlags;
slow->stateFlags = stateFlags;
slow->failsafePhase = failsafePhase();
}
/**
* If the data in the slow frame has changed, log a slow frame.
*
* If allowPeriodicWrite is true, the frame is also logged if it has been more than SLOW_FRAME_INTERVAL logging iterations
* since the field was last logged.
*/
static void writeSlowFrameIfNeeded(bool allowPeriodicWrite)
{
// Write the slow frame peridocially so it can be recovered if we ever lose sync
bool shouldWrite = allowPeriodicWrite && blackboxSlowFrameIterationTimer >= SLOW_FRAME_INTERVAL;
if (shouldWrite) {
loadSlowState(&slowHistory);
} else {
blackboxSlowState_t newSlowState;
loadSlowState(&newSlowState);
// Only write a slow frame if it was different from the previous state
if (memcmp(&newSlowState, &slowHistory, sizeof(slowHistory)) != 0) {
// Use the new state as our new history
memcpy(&slowHistory, &newSlowState, sizeof(slowHistory));
shouldWrite = true;
}
}
if (shouldWrite) {
writeSlowFrame();
}
}
static int gcd(int num, int denom)
{
if (denom == 0) {
@ -774,9 +870,9 @@ static void writeGPSFrame()
/**
* Fill the current state of the blackbox using values read from the flight controller
*/
static void loadBlackboxState(void)
static void loadMainState(void)
{
blackboxValues_t *blackboxCurrent = blackboxHistory[0];
blackboxMainState_t *blackboxCurrent = blackboxHistory[0];
int i;
blackboxCurrent->time = currentTime;
@ -839,6 +935,9 @@ static void loadBlackboxState(void)
* H Field I name:a,b,c
* H Field I predictor:0,1,2
*
* For all header types, provide a "mainFrameChar" which is the name for the field and will be used to refer to it in the
* header (e.g. P, I etc). For blackboxDeltaField_t fields, also provide deltaFrameChar, otherwise set this to zero.
*
* Provide an array 'conditions' of FlightLogFieldCondition enums if you want these conditions to decide whether a field
* should be included or not. Otherwise provide NULL for this parameter and NULL for secondCondition.
*
@ -849,15 +948,22 @@ static void loadBlackboxState(void)
*
* Returns true if there is still header left to transmit (so call again to continue transmission).
*/
static bool sendFieldDefinition(const char * const *headerNames, unsigned int headerCount, const void *fieldDefinitions,
static bool sendFieldDefinition(char mainFrameChar, char deltaFrameChar, const void *fieldDefinitions,
const void *secondFieldDefinition, int fieldCount, const uint8_t *conditions, const uint8_t *secondCondition)
{
const blackboxFieldDefinition_t *def;
int charsWritten;
unsigned int headerCount;
static bool needComma = false;
size_t definitionStride = (char*) secondFieldDefinition - (char*) fieldDefinitions;
size_t conditionsStride = (char*) secondCondition - (char*) conditions;
if (deltaFrameChar) {
headerCount = BLACKBOX_DELTA_FIELD_HEADER_COUNT;
} else {
headerCount = BLACKBOX_SIMPLE_FIELD_HEADER_COUNT;
}
/*
* We're chunking up the header data so we don't exceed our datarate. So we'll be called multiple times to transmit
* the whole header.
@ -867,10 +973,7 @@ static bool sendFieldDefinition(const char * const *headerNames, unsigned int he
return false; //Someone probably called us again after we had already completed transmission
}
charsWritten = blackboxPrint("H Field ");
charsWritten += blackboxPrint(headerNames[xmitState.headerIndex]);
blackboxWrite(':');
charsWritten++;
charsWritten = blackboxPrintf("H Field %c %s:", xmitState.headerIndex >= BLACKBOX_SIMPLE_FIELD_HEADER_COUNT ? deltaFrameChar : mainFrameChar, blackboxFieldHeaderNames[xmitState.headerIndex]);
xmitState.u.fieldIndex++;
needComma = false;
@ -1051,6 +1154,80 @@ static void blackboxCheckAndLogArmingBeep()
}
}
/*
* Use the user's num/denom settings to decide if the P-frame of the given index should be logged, allowing the user to control
* the portion of logged loop iterations.
*/
static bool blackboxShouldLogPFrame(uint32_t pFrameIndex)
{
/* Adding a magic shift of "masterConfig.blackbox_rate_num - 1" in here creates a better spread of
* recorded / skipped frames when the I frame's position is considered:
*/
return (pFrameIndex + masterConfig.blackbox_rate_num - 1) % masterConfig.blackbox_rate_denom < masterConfig.blackbox_rate_num;
}
// Called once every FC loop in order to log the current state
static void blackboxLogIteration()
{
// Write a keyframe every BLACKBOX_I_INTERVAL frames so we can resynchronise upon missing frames
if (blackboxPFrameIndex == 0) {
/*
* Don't log a slow frame if the slow data didn't change ("I" frames are already large enough without adding
* an additional item to write at the same time)
*/
writeSlowFrameIfNeeded(false);
loadMainState();
writeIntraframe();
} else {
blackboxCheckAndLogArmingBeep();
if (blackboxShouldLogPFrame(blackboxPFrameIndex)) {
/*
* We assume that slow frames are only interesting in that they aid the interpretation of the main data stream.
* So only log slow frames during loop iterations where we log a main frame.
*/
writeSlowFrameIfNeeded(true);
loadMainState();
writeInterframe();
}
#ifdef GPS
if (feature(FEATURE_GPS)) {
/*
* If the GPS home point has been updated, or every 128 intraframes (~10 seconds), write the
* GPS home position.
*
* We write it periodically so that if one Home Frame goes missing, the GPS coordinates can
* still be interpreted correctly.
*/
if (GPS_home[0] != gpsHistory.GPS_home[0] || GPS_home[1] != gpsHistory.GPS_home[1]
|| (blackboxPFrameIndex == BLACKBOX_I_INTERVAL / 2 && blackboxIFrameIndex % 128 == 0)) {
writeGPSHomeFrame();
writeGPSFrame();
} else if (GPS_numSat != gpsHistory.GPS_numSat || GPS_coord[0] != gpsHistory.GPS_coord[0]
|| GPS_coord[1] != gpsHistory.GPS_coord[1]) {
//We could check for velocity changes as well but I doubt it changes independent of position
writeGPSFrame();
}
}
#endif
}
//Flush every iteration so that our runtime variance is minimized
blackboxDeviceFlush();
blackboxSlowFrameIterationTimer++;
blackboxIteration++;
blackboxPFrameIndex++;
if (blackboxPFrameIndex == BLACKBOX_I_INTERVAL) {
blackboxPFrameIndex = 0;
blackboxIFrameIndex++;
}
}
/**
* Call each flight loop iteration to perform blackbox logging.
*/
@ -1072,38 +1249,45 @@ void handleBlackbox(void)
}
if (blackboxHeader[xmitState.headerIndex] == '\0') {
blackboxSetState(BLACKBOX_STATE_SEND_FIELDINFO);
blackboxSetState(BLACKBOX_STATE_SEND_MAIN_FIELD_HEADER);
}
}
break;
case BLACKBOX_STATE_SEND_FIELDINFO:
case BLACKBOX_STATE_SEND_MAIN_FIELD_HEADER:
//On entry of this state, xmitState.headerIndex is 0 and xmitState.u.fieldIndex is -1
if (!sendFieldDefinition(blackboxMainHeaderNames, ARRAY_LENGTH(blackboxMainHeaderNames), blackboxMainFields, blackboxMainFields + 1,
ARRAY_LENGTH(blackboxMainFields), &blackboxMainFields[0].condition, &blackboxMainFields[1].condition)) {
if (!sendFieldDefinition('I', 'P', blackboxMainFields, blackboxMainFields + 1, ARRAY_LENGTH(blackboxMainFields),
&blackboxMainFields[0].condition, &blackboxMainFields[1].condition)) {
#ifdef GPS
if (feature(FEATURE_GPS)) {
blackboxSetState(BLACKBOX_STATE_SEND_GPS_H_HEADERS);
blackboxSetState(BLACKBOX_STATE_SEND_GPS_H_HEADER);
} else
#endif
blackboxSetState(BLACKBOX_STATE_SEND_SYSINFO);
blackboxSetState(BLACKBOX_STATE_SEND_SLOW_HEADER);
}
break;
#ifdef GPS
case BLACKBOX_STATE_SEND_GPS_H_HEADERS:
case BLACKBOX_STATE_SEND_GPS_H_HEADER:
//On entry of this state, xmitState.headerIndex is 0 and xmitState.u.fieldIndex is -1
if (!sendFieldDefinition(blackboxGPSHHeaderNames, ARRAY_LENGTH(blackboxGPSHHeaderNames), blackboxGpsHFields, blackboxGpsHFields + 1,
ARRAY_LENGTH(blackboxGpsHFields), &blackboxGpsHFields[0].condition, &blackboxGpsHFields[1].condition)) {
blackboxSetState(BLACKBOX_STATE_SEND_GPS_G_HEADERS);
if (!sendFieldDefinition('H', 0, blackboxGpsHFields, blackboxGpsHFields + 1, ARRAY_LENGTH(blackboxGpsHFields),
NULL, NULL)) {
blackboxSetState(BLACKBOX_STATE_SEND_GPS_G_HEADER);
}
break;
case BLACKBOX_STATE_SEND_GPS_G_HEADERS:
case BLACKBOX_STATE_SEND_GPS_G_HEADER:
//On entry of this state, xmitState.headerIndex is 0 and xmitState.u.fieldIndex is -1
if (!sendFieldDefinition(blackboxGPSGHeaderNames, ARRAY_LENGTH(blackboxGPSGHeaderNames), blackboxGpsGFields, blackboxGpsGFields + 1,
ARRAY_LENGTH(blackboxGpsGFields), &blackboxGpsGFields[0].condition, &blackboxGpsGFields[1].condition)) {
if (!sendFieldDefinition('G', 0, blackboxGpsGFields, blackboxGpsGFields + 1, ARRAY_LENGTH(blackboxGpsGFields),
&blackboxGpsGFields[0].condition, &blackboxGpsGFields[1].condition)) {
blackboxSetState(BLACKBOX_STATE_SEND_SLOW_HEADER);
}
break;
#endif
case BLACKBOX_STATE_SEND_SLOW_HEADER:
//On entry of this state, xmitState.headerIndex is 0 and xmitState.u.fieldIndex is -1
if (!sendFieldDefinition('S', 0, blackboxSlowFields, blackboxSlowFields + 1, ARRAY_LENGTH(blackboxSlowFields),
NULL, NULL)) {
blackboxSetState(BLACKBOX_STATE_SEND_SYSINFO);
}
break;
#endif
case BLACKBOX_STATE_SEND_SYSINFO:
//On entry of this state, xmitState.headerIndex is 0
@ -1115,51 +1299,7 @@ void handleBlackbox(void)
case BLACKBOX_STATE_RUNNING:
// On entry to this state, blackboxIteration, blackboxPFrameIndex and blackboxIFrameIndex are reset to 0
// Write a keyframe every BLACKBOX_I_INTERVAL frames so we can resynchronise upon missing frames
if (blackboxPFrameIndex == 0) {
// Copy current system values into the blackbox
loadBlackboxState();
writeIntraframe();
} else {
blackboxCheckAndLogArmingBeep();
/* Adding a magic shift of "masterConfig.blackbox_rate_num - 1" in here creates a better spread of
* recorded / skipped frames when the I frame's position is considered:
*/
if ((blackboxPFrameIndex + masterConfig.blackbox_rate_num - 1) % masterConfig.blackbox_rate_denom < masterConfig.blackbox_rate_num) {
loadBlackboxState();
writeInterframe();
}
#ifdef GPS
if (feature(FEATURE_GPS)) {
/*
* If the GPS home point has been updated, or every 128 intraframes (~10 seconds), write the
* GPS home position.
*
* We write it periodically so that if one Home Frame goes missing, the GPS coordinates can
* still be interpreted correctly.
*/
if (GPS_home[0] != gpsHistory.GPS_home[0] || GPS_home[1] != gpsHistory.GPS_home[1]
|| (blackboxPFrameIndex == BLACKBOX_I_INTERVAL / 2 && blackboxIFrameIndex % 128 == 0)) {
writeGPSHomeFrame();
writeGPSFrame();
} else if (GPS_numSat != gpsHistory.GPS_numSat || GPS_coord[0] != gpsHistory.GPS_coord[0]
|| GPS_coord[1] != gpsHistory.GPS_coord[1]) {
//We could check for velocity changes as well but I doubt it changes independent of position
writeGPSFrame();
}
}
#endif
}
blackboxIteration++;
blackboxPFrameIndex++;
if (blackboxPFrameIndex == BLACKBOX_I_INTERVAL) {
blackboxPFrameIndex = 0;
blackboxIFrameIndex++;
}
blackboxLogIteration();
break;
case BLACKBOX_STATE_SHUTTING_DOWN:
//On entry of this state, startTime is set and a flush is performed

View File

@ -17,38 +17,8 @@
#pragma once
#include <stdint.h>
#include "common/axis.h"
#include "flight/mixer.h"
#include "blackbox/blackbox_fielddefs.h"
typedef struct blackboxValues_t {
uint32_t time;
int32_t axisPID_P[XYZ_AXIS_COUNT], axisPID_I[XYZ_AXIS_COUNT], axisPID_D[XYZ_AXIS_COUNT];
int16_t rcCommand[4];
int16_t gyroADC[XYZ_AXIS_COUNT];
int16_t accSmooth[XYZ_AXIS_COUNT];
int16_t motor[MAX_SUPPORTED_MOTORS];
int16_t servo[MAX_SUPPORTED_SERVOS];
uint16_t vbatLatest;
uint16_t amperageLatest;
#ifdef BARO
int32_t BaroAlt;
#endif
#ifdef MAG
int16_t magADC[XYZ_AXIS_COUNT];
#endif
#ifdef SONAR
int32_t sonarRaw;
#endif
uint16_t rssi;
} blackboxValues_t;
void blackboxLogEvent(FlightLogEvent event, flightLogEventData_t *data);
void initBlackbox(void);

View File

@ -17,6 +17,8 @@
#pragma once
#include <stdint.h>
typedef enum FlightLogFieldCondition {
FLIGHT_LOG_FIELD_CONDITION_ALWAYS = 0,
FLIGHT_LOG_FIELD_CONDITION_AT_LEAST_MOTORS_1,

View File

@ -105,6 +105,10 @@ regs Kusti, 23.10.2004
#ifndef __TFP_PRINTF__
#define __TFP_PRINTF__
#include <stdarg.h>
#include "drivers/serial.h"
void init_printf(void *putp, void (*putf) (void *, char));
int tfp_printf(const char *fmt, ...);

View File

@ -171,6 +171,9 @@ static void resetPidProfile(pidProfile_t *pidProfile)
pidProfile->D8[PIDVEL] = 1;
pidProfile->yaw_p_limit = YAW_P_LIMIT_MAX;
pidProfile->dterm_cut_hz = 0;
pidProfile->pterm_cut_hz = 0;
pidProfile->gyro_cut_hz = 0;
pidProfile->P_f[ROLL] = 2.5f; // new PID with preliminary defaults test carefully
pidProfile->I_f[ROLL] = 0.6f;

View File

@ -372,7 +372,9 @@ bool mpu6050GyroDetect(const mpu6050Config_t *configToUse, gyro_t *gyro, uint16_
// 16.4 dps/lsb scalefactor
gyro->scale = 1.0f / 16.4f;
if (lpf >= 188)
if (lpf == 256)
mpuLowPassFilter = INV_FILTER_256HZ_NOLPF2;
else if (lpf >= 188)
mpuLowPassFilter = INV_FILTER_188HZ;
else if (lpf >= 98)
mpuLowPassFilter = INV_FILTER_98HZ;
@ -382,8 +384,10 @@ bool mpu6050GyroDetect(const mpu6050Config_t *configToUse, gyro_t *gyro, uint16_
mpuLowPassFilter = INV_FILTER_20HZ;
else if (lpf >= 10)
mpuLowPassFilter = INV_FILTER_10HZ;
else
else if (lpf > 0)
mpuLowPassFilter = INV_FILTER_5HZ;
else
mpuLowPassFilter = INV_FILTER_256HZ_NOLPF2;
return true;
}

View File

@ -275,33 +275,22 @@ bool mpu6000SpiGyroDetect(gyro_t *gyro, uint16_t lpf)
int16_t data[3];
// default lpf is 42Hz
switch (lpf) {
case 256:
mpuLowPassFilter = BITS_DLPF_CFG_256HZ;
break;
case 188:
mpuLowPassFilter = BITS_DLPF_CFG_188HZ;
break;
case 98:
mpuLowPassFilter = BITS_DLPF_CFG_98HZ;
break;
default:
case 42:
mpuLowPassFilter = BITS_DLPF_CFG_42HZ;
break;
case 20:
mpuLowPassFilter = BITS_DLPF_CFG_20HZ;
break;
case 10:
mpuLowPassFilter = BITS_DLPF_CFG_10HZ;
break;
case 5:
mpuLowPassFilter = BITS_DLPF_CFG_5HZ;
break;
case 0:
mpuLowPassFilter = BITS_DLPF_CFG_2100HZ_NOLPF;
break;
}
if (lpf == 256)
mpuLowPassFilter = BITS_DLPF_CFG_256HZ;
else if (lpf >= 188)
mpuLowPassFilter = BITS_DLPF_CFG_188HZ;
else if (lpf >= 98)
mpuLowPassFilter = BITS_DLPF_CFG_98HZ;
else if (lpf >= 42)
mpuLowPassFilter = BITS_DLPF_CFG_42HZ;
else if (lpf >= 20)
mpuLowPassFilter = BITS_DLPF_CFG_20HZ;
else if (lpf >= 10)
mpuLowPassFilter = BITS_DLPF_CFG_10HZ;
else if (lpf > 0)
mpuLowPassFilter = BITS_DLPF_CFG_5HZ;
else
mpuLowPassFilter = BITS_DLPF_CFG_256HZ;
spiSetDivisor(MPU6000_SPI_INSTANCE, SPI_0_5625MHZ_CLOCK_DIVIDER);

View File

@ -20,10 +20,10 @@
#include <stdint.h>
typedef struct flashGeometry_t {
uint8_t sectors; // Count of the number of erasable blocks on the device
uint16_t sectors; // Count of the number of erasable blocks on the device
uint16_t pagesPerSector;
uint16_t pageSize; // In bytes
const uint16_t pageSize; // In bytes
uint32_t sectorSize; // This is just pagesPerSector * pageSize

View File

@ -42,6 +42,8 @@
#define JEDEC_ID_MICRON_M25P16 0x202015
#define JEDEC_ID_MICRON_N25Q064 0x20BA17
#define JEDEC_ID_WINBOND_W25Q64 0xEF4017
#define JEDEC_ID_MICRON_N25Q128 0x20ba18
#define JEDEC_ID_WINBOND_W25Q128 0xEF4018
#define DISABLE_M25P16 GPIO_SetBits(M25P16_CS_GPIO, M25P16_CS_PIN)
#define ENABLE_M25P16 GPIO_ResetBits(M25P16_CS_GPIO, M25P16_CS_PIN)
@ -53,7 +55,7 @@
#define SECTOR_ERASE_TIMEOUT_MILLIS 5000
#define BULK_ERASE_TIMEOUT_MILLIS 21000
static flashGeometry_t geometry;
static flashGeometry_t geometry = {.pageSize = M25P16_PAGESIZE};
/*
* Whether we've performed an action that could have made the device busy for writes.
@ -148,23 +150,27 @@ static bool m25p16_readIdentification()
// Manufacturer, memory type, and capacity
chipID = (in[1] << 16) | (in[2] << 8) | (in[3]);
// All supported chips use the same pagesize of 256 bytes
switch (chipID) {
case JEDEC_ID_MICRON_M25P16:
geometry.sectors = 32;
geometry.pagesPerSector = 256;
geometry.pageSize = 256;
break;
case JEDEC_ID_MICRON_N25Q064:
case JEDEC_ID_WINBOND_W25Q64:
geometry.sectors = 128;
geometry.pagesPerSector = 256;
geometry.pageSize = 256;
break;
case JEDEC_ID_MICRON_N25Q128:
case JEDEC_ID_WINBOND_W25Q128:
geometry.sectors = 256;
geometry.pagesPerSector = 256;
break;
default:
// Unsupported chip or not an SPI NOR flash
geometry.sectors = 0;
geometry.pagesPerSector = 0;
geometry.pageSize = 0;
geometry.sectorSize = 0;
geometry.totalSize = 0;

View File

@ -20,6 +20,8 @@
#include <stdint.h>
#include "flash.h"
#define M25P16_PAGESIZE 256
bool m25p16_init();
void m25p16_eraseSector(uint32_t address);

27
src/main/flight/filter.c Normal file
View File

@ -0,0 +1,27 @@
/*
* filter.c
*
* Created on: 24 jun. 2015
* Author: borisb
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <math.h>
#include "common/axis.h"
#include "flight/filter.h"
extern uint16_t cycleTime;
// PT1 Low Pass filter
float filterApplyPt1(float input, filterStatePt1_t* state, uint8_t f_cut) {
float dT = (float)cycleTime * 0.000001f;
float RC= 1.0f / ( 2.0f * (float)M_PI * f_cut );
*state = *state + dT / (RC + dT) * (input - *state);
return *state;
}

11
src/main/flight/filter.h Normal file
View File

@ -0,0 +1,11 @@
/*
* filter.h
*
* Created on: 24 jun. 2015
* Author: borisb
*/
typedef float filterStatePt1_t;
float filterApplyPt1(float input, filterStatePt1_t* state, uint8_t f_cut);

View File

@ -42,6 +42,7 @@
#include "flight/imu.h"
#include "flight/navigation.h"
#include "flight/autotune.h"
#include "flight/filter.h"
#include "config/runtime_config.h"
@ -93,6 +94,8 @@ void pidResetErrorGyro(void)
const angle_index_t rcAliasToAngleIndexMap[] = { AI_ROLL, AI_PITCH };
static filterStatePt1_t PTermState[3], DTermState[3];
#ifdef AUTOTUNE
bool shouldAutotune(void)
{
@ -184,6 +187,11 @@ static void pidLuxFloat(pidProfile_t *pidProfile, controlRateConfig_t *controlRa
// -----calculate P component
PTerm = RateError * pidProfile->P_f[axis] * PIDweight[axis] / 100;
// Pterm low pass
if (pidProfile->pterm_cut_hz) {
PTerm = filterApplyPt1(PTerm, &PTermState[axis], pidProfile->pterm_cut_hz);
}
// -----calculate I component. Note that PIDweight is divided by 10, because it is simplified formule from the previous multiply by 10
errorGyroIf[axis] = constrainf(errorGyroIf[axis] + RateError * dT * pidProfile->I_f[axis] * PIDweight[axis] / 10, -250.0f, 250.0f);
@ -202,6 +210,12 @@ static void pidLuxFloat(pidProfile_t *pidProfile, controlRateConfig_t *controlRa
deltaSum = delta1[axis] + delta2[axis] + delta;
delta2[axis] = delta1[axis];
delta1[axis] = delta;
// Dterm low pass
if (pidProfile->dterm_cut_hz) {
deltaSum = filterApplyPt1(deltaSum, &DTermState[axis], pidProfile->dterm_cut_hz);
}
DTerm = constrainf((deltaSum / 3.0f) * pidProfile->D_f[axis] * PIDweight[axis] / 100, -300.0f, 300.0f);
// -----calculate total PID output
@ -282,11 +296,23 @@ static void pidMultiWii(pidProfile_t *pidProfile, controlRateConfig_t *controlRa
}
PTerm -= ((int32_t)gyroADC[axis] / 4) * dynP8[axis] / 10 / 8; // 32 bits is needed for calculation
// Pterm low pass
if (pidProfile->pterm_cut_hz) {
PTerm = filterApplyPt1(PTerm, &PTermState[axis], pidProfile->pterm_cut_hz);
}
delta = (gyroADC[axis] - lastGyro[axis]) / 4;
lastGyro[axis] = gyroADC[axis];
deltaSum = delta1[axis] + delta2[axis] + delta;
delta2[axis] = delta1[axis];
delta1[axis] = delta;
// Dterm low pass
if (pidProfile->dterm_cut_hz) {
deltaSum = filterApplyPt1(deltaSum, &DTermState[axis], pidProfile->dterm_cut_hz);
}
DTerm = (deltaSum * dynD8[axis]) / 32;
axisPID[axis] = PTerm + ITerm - DTerm;
@ -361,12 +387,22 @@ static void pidMultiWii23(pidProfile_t *pidProfile, controlRateConfig_t *control
PTerm -= ((int32_t)(gyroADC[axis] / 4) * dynP8[axis]) >> 6; // 32 bits is needed for calculation
// Pterm low pass
if (pidProfile->pterm_cut_hz) {
PTerm = filterApplyPt1(PTerm, &PTermState[axis], pidProfile->pterm_cut_hz);
}
delta = (gyroADC[axis] - lastGyro[axis]) / 4; // 16 bits is ok here, the dif between 2 consecutive gyro reads is limited to 800
lastGyro[axis] = gyroADC[axis];
DTerm = delta1[axis] + delta2[axis] + delta;
delta2[axis] = delta1[axis];
delta1[axis] = delta;
// Dterm low pass
if (pidProfile->dterm_cut_hz) {
DTerm = filterApplyPt1(DTerm, &DTermState[axis], pidProfile->dterm_cut_hz);
}
DTerm = ((int32_t)DTerm * dynD8[axis]) >> 5; // 32 bits is needed for calculation
axisPID[axis] = PTerm + ITerm - DTerm;
@ -474,11 +510,22 @@ static void pidMultiWiiHybrid(pidProfile_t *pidProfile, controlRateConfig_t *con
}
PTerm -= ((int32_t)gyroADC[axis] / 4) * dynP8[axis] / 10 / 8; // 32 bits is needed for calculation
// Pterm low pass
if (pidProfile->pterm_cut_hz) {
PTerm = filterApplyPt1(PTerm, &PTermState[axis], pidProfile->pterm_cut_hz);
}
delta = (gyroADC[axis] - lastGyro[axis]) / 4;
lastGyro[axis] = gyroADC[axis];
deltaSum = delta1[axis] + delta2[axis] + delta;
delta2[axis] = delta1[axis];
delta1[axis] = delta;
// Dterm low pass
if (pidProfile->dterm_cut_hz) {
deltaSum = filterApplyPt1(deltaSum, &DTermState[axis], pidProfile->dterm_cut_hz);
}
DTerm = (deltaSum * dynD8[axis]) / 32;
axisPID[axis] = PTerm + ITerm - DTerm;
@ -529,8 +576,7 @@ rollAndPitchTrims_t *angleTrim, rxConfig_t *rxConfig)
uint8_t axis;
float ACCDeltaTimeINS, FLOATcycleTime, Mwii3msTimescale;
// MainDptCut = RCconstPI / (float)cfg.maincuthz; // Initialize Cut off frequencies for mainpid D
MainDptCut = RCconstPI / MAIN_CUT_HZ; // maincuthz (default 12Hz, Range 1-50Hz), hardcoded for now
MainDptCut = RCconstPI / constrain(pidProfile->dterm_cut_hz, 1, 50); // maincuthz (default 0 (disabled), Range 1-50Hz)
FLOATcycleTime = (float)constrain(cycleTime, 1, 100000); // 1us - 100ms
ACCDeltaTimeINS = FLOATcycleTime * 0.000001f; // ACCDeltaTimeINS is in seconds now
RCfactor = ACCDeltaTimeINS / (MainDptCut + ACCDeltaTimeINS); // used for pt1 element
@ -585,6 +631,12 @@ rollAndPitchTrims_t *angleTrim, rxConfig_t *rxConfig)
}
PTerm -= gyroADCQuant * dynP8[axis] * 0.003f;
// Pterm low pass
if (pidProfile->pterm_cut_hz) {
PTerm = filterApplyPt1(PTerm, &PTermState[axis], pidProfile->pterm_cut_hz);
}
delta = (gyroADCQuant - lastGyro[axis]) / ACCDeltaTimeINS;
lastGyro[axis] = gyroADCQuant;
@ -631,6 +683,12 @@ rollAndPitchTrims_t *angleTrim, rxConfig_t *rxConfig)
PTerm = constrain(PTerm, -pidProfile->yaw_p_limit, pidProfile->yaw_p_limit);
}
}
// Pterm low pass
if (pidProfile->pterm_cut_hz) {
PTerm = filterApplyPt1(PTerm, &PTermState[axis], pidProfile->pterm_cut_hz);
}
axisPID[FD_YAW] = PTerm + ITerm;
axisPID[FD_YAW] = lrintf(axisPID[FD_YAW]); // Round up result.
@ -720,6 +778,12 @@ static void pidRewrite(pidProfile_t *pidProfile, controlRateConfig_t *controlRat
// -----calculate P component
PTerm = (RateError * pidProfile->P8[axis] * PIDweight[axis] / 100) >> 7;
// Pterm low pass
if (pidProfile->pterm_cut_hz) {
PTerm = filterApplyPt1(PTerm, &PTermState[axis], pidProfile->pterm_cut_hz);
}
// -----calculate I component
// there should be no division before accumulating the error to integrator, because the precision would be reduced.
// Precision is critical, as I prevents from long-time drift. Thus, 32 bits integrator is used.
@ -743,6 +807,12 @@ static void pidRewrite(pidProfile_t *pidProfile, controlRateConfig_t *controlRat
deltaSum = delta1[axis] + delta2[axis] + delta;
delta2[axis] = delta1[axis];
delta1[axis] = delta;
// Dterm delta low pass
if (pidProfile->dterm_cut_hz) {
deltaSum = filterApplyPt1(deltaSum, &DTermState[axis], pidProfile->dterm_cut_hz);
}
DTerm = (deltaSum * pidProfile->D8[axis] * PIDweight[axis] / 100) >> 8;
// -----calculate total PID output

View File

@ -19,7 +19,6 @@
#define GYRO_I_MAX 256 // Gyro I limiter
#define RCconstPI 0.159154943092f // 0.5f / M_PI;
#define MAIN_CUT_HZ 12.0f // (default 12Hz, Range 1-50Hz)
#define OLD_YAW 0 // [0/1] 0 = MultiWii 2.3 yaw, 1 = older yaw.
#define YAW_P_LIMIT_MIN 100 // Maximum value for yaw P limiter
#define YAW_P_LIMIT_MAX 500 // Maximum value for yaw P limiter
@ -63,6 +62,9 @@ typedef struct pidProfile_s {
float H_level;
uint8_t H_sensitivity;
uint16_t yaw_p_limit; // set P term limit (fixed value was 300)
uint8_t dterm_cut_hz; // (default 17Hz, Range 1-50Hz) Used for PT1 element in PID1, PID2 and PID5
uint8_t pterm_cut_hz; // Used for fitlering Pterm noise on noisy frames
uint8_t gyro_cut_hz; // Used for soft gyro filtering
} pidProfile_t;
#define DEGREES_TO_DECIDEGREES(angle) (angle * 10)
@ -75,4 +77,3 @@ void pidSetController(pidControllerType_e type);
void pidResetErrorAngle(void);
void pidResetErrorGyro(void);

View File

@ -49,15 +49,10 @@ static uint8_t bufferHead = 0, bufferTail = 0;
// The position of the buffer's tail in the overall flash address space:
static uint32_t tailAddress = 0;
// The index of the tail within the flash page it is inside
static uint16_t tailIndexInPage = 0;
static bool shouldFlush = false;
static void flashfsClearBuffer()
{
bufferTail = bufferHead = 0;
shouldFlush = false;
}
static bool flashfsBufferIsEmpty()
@ -68,10 +63,6 @@ static bool flashfsBufferIsEmpty()
static void flashfsSetTailAddress(uint32_t address)
{
tailAddress = address;
if (m25p16_getGeometry()->pageSize > 0) {
tailIndexInPage = tailAddress % m25p16_getGeometry()->pageSize;
}
}
void flashfsEraseCompletely()
@ -157,8 +148,6 @@ static uint32_t flashfsTransmitBufferUsed()
*/
static uint32_t flashfsWriteBuffers(uint8_t const **buffers, uint32_t *bufferSizes, int bufferCount, bool sync)
{
const flashGeometry_t *geometry = m25p16_getGeometry();
uint32_t bytesTotal = 0;
int i;
@ -181,8 +170,8 @@ static uint32_t flashfsWriteBuffers(uint8_t const **buffers, uint32_t *bufferSiz
* Each page needs to be saved in a separate program operation, so
* if we would cross a page boundary, only write up to the boundary in this iteration:
*/
if (tailIndexInPage + bytesTotalRemaining > geometry->pageSize) {
bytesTotalThisIteration = geometry->pageSize - tailIndexInPage;
if (tailAddress % M25P16_PAGESIZE + bytesTotalRemaining > M25P16_PAGESIZE) {
bytesTotalThisIteration = M25P16_PAGESIZE - tailAddress % M25P16_PAGESIZE;
} else {
bytesTotalThisIteration = bytesTotalRemaining;
}
@ -293,15 +282,14 @@ static void flashfsAdvanceTailInBuffer(uint32_t delta)
}
/**
* If the flash is ready to accept writes, flush the buffer to it, otherwise schedule
* a flush for later and return immediately.
* If the flash is ready to accept writes, flush the buffer to it.
*
* Returns true if all data in the buffer has been flushed to the device.
* Returns true if all data in the buffer has been flushed to the device, or false if
* there is still data to be written (call flush again later).
*/
bool flashfsFlushAsync()
{
if (flashfsBufferIsEmpty()) {
shouldFlush = false;
return true; // Nothing to flush
}
@ -313,8 +301,6 @@ bool flashfsFlushAsync()
bytesWritten = flashfsWriteBuffers(buffers, bufferSizes, 2, false);
flashfsAdvanceTailInBuffer(bytesWritten);
shouldFlush = !flashfsBufferIsEmpty();
return flashfsBufferIsEmpty();
}
@ -327,7 +313,6 @@ bool flashfsFlushAsync()
void flashfsFlushSync()
{
if (flashfsBufferIsEmpty()) {
shouldFlush = false;
return; // Nothing to flush
}
@ -366,7 +351,7 @@ void flashfsWriteByte(uint8_t byte)
bufferHead = 0;
}
if (shouldFlush || flashfsTransmitBufferUsed() >= FLASHFS_WRITE_BUFFER_AUTO_FLUSH_LEN) {
if (flashfsTransmitBufferUsed() >= FLASHFS_WRITE_BUFFER_AUTO_FLUSH_LEN) {
flashfsFlushAsync();
}
}
@ -393,7 +378,7 @@ void flashfsWrite(const uint8_t *data, unsigned int len, bool sync)
* Would writing this data to our buffer cause our buffer to reach the flush threshold? If so try to write through
* to the flash now
*/
if (shouldFlush || bufferSizes[0] + bufferSizes[1] + bufferSizes[2] >= FLASHFS_WRITE_BUFFER_AUTO_FLUSH_LEN) {
if (bufferSizes[0] + bufferSizes[1] + bufferSizes[2] >= FLASHFS_WRITE_BUFFER_AUTO_FLUSH_LEN) {
uint32_t bytesWritten;
// Attempt to write all three buffers through to the flash asynchronously

View File

@ -486,6 +486,9 @@ const clivalue_t valueTable[] = {
{ "d_vel", VAR_UINT8 | PROFILE_VALUE, &masterConfig.profile[0].pidProfile.D8[PIDVEL], 0, 200 },
{ "yaw_p_limit", VAR_UINT16 | PROFILE_VALUE, &masterConfig.profile[0].pidProfile.yaw_p_limit, YAW_P_LIMIT_MIN, YAW_P_LIMIT_MAX },
{ "dterm_cut_hz", VAR_UINT8 | PROFILE_VALUE, &masterConfig.profile[0].pidProfile.dterm_cut_hz, 0, 200 },
{ "pterm_cut_hz", VAR_UINT8 | PROFILE_VALUE, &masterConfig.profile[0].pidProfile.pterm_cut_hz, 0, 200 },
{ "gyro_cut_hz", VAR_UINT8 | PROFILE_VALUE, &masterConfig.profile[0].pidProfile.gyro_cut_hz, 0, 200 },
#ifdef BLACKBOX
{ "blackbox_rate_num", VAR_UINT8 | MASTER_VALUE, &masterConfig.blackbox_rate_num, 1, 32 },

View File

@ -72,6 +72,7 @@
#include "flight/failsafe.h"
#include "flight/autotune.h"
#include "flight/navigation.h"
#include "flight/filter.h"
#include "config/runtime_config.h"
@ -740,6 +741,16 @@ void loop(void)
cycleTime = (int32_t)(currentTime - previousTime);
previousTime = currentTime;
// Gyro Low Pass
if (currentProfile->pidProfile.gyro_cut_hz) {
int axis;
static filterStatePt1_t gyroADCState[XYZ_AXIS_COUNT];
for (axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
gyroADC[axis] = filterApplyPt1(gyroADC[axis], &gyroADCState[axis], currentProfile->pidProfile.gyro_cut_hz);
}
}
annexCode();
#if defined(BARO) || defined(SONAR)
haveProcessedAnnexCodeOnce = true;

View File

@ -4,7 +4,7 @@
* @author MCD Application Team
* @version V3.5.0
* @date 11-March-2011
* @brief STM32F10x Medium Density Devices vector table for Atollic toolchain.
* @brief STM32F10x High Density Devices vector table for Atollic toolchain.
* This module performs:
* - Set the initial SP
* - Set the initial PC == Reset_Handler,
@ -47,8 +47,9 @@ defined in linker script */
.word _sbss
/* end address for the .bss section. defined in linker script */
.word _ebss
/* stack used for SystemInit_ExtMemCtl; always internal RAM used */
.equ BootRAM, 0xF108F85F
.equ BootRAM, 0xF1E0F85F
/**
* @brief This is the code that gets called when the processor first
* starts execution following a reset event. Only the absolutely
@ -230,16 +231,69 @@ g_pfnVectors:
.word EXTI15_10_IRQHandler
.word RTCAlarm_IRQHandler
.word USBWakeUp_IRQHandler
.word 0
.word TIM8_BRK_IRQHandler
.word TIM8_UP_IRQHandler
.word TIM8_TRG_COM_IRQHandler
.word TIM8_CC_IRQHandler
.word ADC3_IRQHandler
.word FSMC_IRQHandler
.word SDIO_IRQHandler
.word TIM5_IRQHandler
.word SPI3_IRQHandler
.word UART4_IRQHandler
.word UART5_IRQHandler
.word TIM6_IRQHandler
.word TIM7_IRQHandler
.word DMA2_Channel1_IRQHandler
.word DMA2_Channel2_IRQHandler
.word DMA2_Channel3_IRQHandler
.word DMA2_Channel4_5_IRQHandler
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word BootRAM /* @0x108. This is for boot in RAM mode for
STM32F10x Medium Density devices. */
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word BootRAM /* @0x1E0. This is for boot in RAM mode for
STM32F10x High Density devices. */
/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
@ -404,5 +458,56 @@ g_pfnVectors:
.weak USBWakeUp_IRQHandler
.thumb_set USBWakeUp_IRQHandler,Default_Handler
.weak TIM8_BRK_IRQHandler
.thumb_set TIM8_BRK_IRQHandler,Default_Handler
.weak TIM8_UP_IRQHandler
.thumb_set TIM8_UP_IRQHandler,Default_Handler
.weak TIM8_TRG_COM_IRQHandler
.thumb_set TIM8_TRG_COM_IRQHandler,Default_Handler
.weak TIM8_CC_IRQHandler
.thumb_set TIM8_CC_IRQHandler,Default_Handler
.weak ADC3_IRQHandler
.thumb_set ADC3_IRQHandler,Default_Handler
.weak FSMC_IRQHandler
.thumb_set FSMC_IRQHandler,Default_Handler
.weak SDIO_IRQHandler
.thumb_set SDIO_IRQHandler,Default_Handler
.weak TIM5_IRQHandler
.thumb_set TIM5_IRQHandler,Default_Handler
.weak SPI3_IRQHandler
.thumb_set SPI3_IRQHandler,Default_Handler
.weak UART4_IRQHandler
.thumb_set UART4_IRQHandler,Default_Handler
.weak UART5_IRQHandler
.thumb_set UART5_IRQHandler,Default_Handler
.weak TIM6_IRQHandler
.thumb_set TIM6_IRQHandler,Default_Handler
.weak TIM7_IRQHandler
.thumb_set TIM7_IRQHandler,Default_Handler
.weak DMA2_Channel1_IRQHandler
.thumb_set DMA2_Channel1_IRQHandler,Default_Handler
.weak DMA2_Channel2_IRQHandler
.thumb_set DMA2_Channel2_IRQHandler,Default_Handler
.weak DMA2_Channel3_IRQHandler
.thumb_set DMA2_Channel3_IRQHandler,Default_Handler
.weak DMA2_Channel4_5_IRQHandler
.thumb_set DMA2_Channel4_5_IRQHandler,Default_Handler
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/