mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-05-26 03:47:35 +08:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6a1e609e3c | |||
| 32c1364c27 | |||
| 771d2ecf52 | |||
| 9833a2d864 | |||
| d72685120c | |||
| 349bd6175c | |||
| 2dd864a87a | |||
| 613a784ce2 | |||
| 75f3768be6 | |||
| b59e81fbf2 | |||
| e2c40ee4bb | |||
| 17413fb5c0 | |||
| ca3ad3d63d | |||
| 1e12fe13d4 | |||
| 9cfb42ec03 | |||
| 50d3b7e1ff | |||
| 5598581c4e | |||
| ae39d6831f | |||
| ed4d93b9e6 | |||
| ac0b769feb | |||
| fbb5f220bd | |||
| 34a643fcda | |||
| 02eb031ab7 | |||
| 5fb3846b50 | |||
| 878c049215 |
@@ -3,45 +3,92 @@ description: Create a report to help us improve
|
||||
title: "[Bug] "
|
||||
labels: ["bug-report"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**Tips for a great bug report:**
|
||||
- Describe what went wrong and what you expected
|
||||
- Include a flight log link from [logs.px4.io](http://logs.px4.io/) if possible
|
||||
- Mention your PX4 version, flight controller, and vehicle type if relevant
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe the bug
|
||||
description: A clear description of the bug and what you expected to happen.
|
||||
placeholder: |
|
||||
What happened and what did you expect instead?
|
||||
|
||||
Steps to reproduce (if applicable):
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
description: A clear and concise description of the bug.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Flight Log / Additional Information
|
||||
label: To Reproduce
|
||||
description: |
|
||||
**Flight log** (highly recommended for flight-related issues):
|
||||
- Upload to [PX4 Flight Review](http://logs.px4.io/) and paste the link
|
||||
|
||||
**Additional details** (if relevant):
|
||||
- PX4 version (output of `ver all` in MAVLink Shell)
|
||||
- Flight controller model
|
||||
- Vehicle type (multicopter, fixed-wing, VTOL, etc.)
|
||||
- Screenshots or media
|
||||
placeholder: |
|
||||
Flight log link:
|
||||
|
||||
Version:
|
||||
|
||||
Hardware:
|
||||
Steps to reproduce the behavior.
|
||||
1. Drone switched on '...'
|
||||
2. Uploaded mission '....' (attach QGC mission file)
|
||||
3. Took off '....'
|
||||
4. See error
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
description: A clear and concise description of what you expected to happen.
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Screenshot / Media
|
||||
description: Add screenshot / media if you have them
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Flight Log
|
||||
description: |
|
||||
*Always* provide a link to the flight log file:
|
||||
- Download the flight log file from the vehicle ([tutorial](https://docs.px4.io/main/en/getting_started/flight_reporting.html)).
|
||||
- Upload the log to the [PX4 Flight Review](http://logs.px4.io/)
|
||||
- Share the link to the log (Copy and paste the URL of the log)
|
||||
placeholder: |
|
||||
# PASTE HERE THE LINK TO THE LOG
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
## Setup
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Software Version
|
||||
description: |
|
||||
Which version of PX4 are you using?
|
||||
placeholder: |
|
||||
# If you don't know the version, paste the output of `ver all` in the MAVLink Shell of QGC
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: Flight controller
|
||||
description: Specify your flight controller model (what type is it, where was it bought from, ...).
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Vehicle type
|
||||
options:
|
||||
- Multicopter
|
||||
- Helicopter
|
||||
- Fixed Wing
|
||||
- Hybrid VTOL
|
||||
- Airship/Balloon
|
||||
- Rover
|
||||
- Boat
|
||||
- Submarine
|
||||
- Other
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: How are the different components wired up (including port information)
|
||||
description: Details about how all is wired.
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add any other context about the problem here.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
blank_issues_enabled: true
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Support Question
|
||||
url: https://docs.px4.io/main/en/contribute/support.html#forums-and-chat
|
||||
|
||||
@@ -1,9 +1,22 @@
|
||||
<!--
|
||||
|
||||
Thank you for your contribution!
|
||||
|
||||
Get early feedback through
|
||||
- Dronecode Discord: https://discord.gg/dronecode
|
||||
- PX4 Discuss: http://discuss.px4.io/
|
||||
- opening a draft pr and sharing the link
|
||||
|
||||
-->
|
||||
|
||||
### Solved Problem
|
||||
When ... I found that ...
|
||||
|
||||
Fixes #{Github issue ID}
|
||||
|
||||
### Solution
|
||||
- Add ... for ...
|
||||
- Refactor ...
|
||||
|
||||
### Changelog Entry
|
||||
For release notes:
|
||||
@@ -14,10 +27,11 @@ Documentation: Need to clarify page ... / done, read docs.px4.io/...
|
||||
```
|
||||
|
||||
### Alternatives
|
||||
We could also ...
|
||||
|
||||
### Test coverage
|
||||
- Unit/integration test: ...
|
||||
- Simulation/hardware testing logs: https://review.px4.io/
|
||||
|
||||
### Context
|
||||
Related links, screenshot before/after, video
|
||||
|
||||
-->
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
---
|
||||
applyTo: "docs/en/**"
|
||||
---
|
||||
|
||||
# Review Guidelines docs/en Tree
|
||||
|
||||
## File System & Structure
|
||||
|
||||
- **Naming:** Use `lowercase_with_underscores` for all filenames. No spaces.
|
||||
- **Hierarchy:** Markdown files must reside exactly in a first-level category folder.
|
||||
- Valid: `docs/en/category/file.md`
|
||||
- Invalid: `docs/en/category/subcategory/file.md`
|
||||
- **Text Files:** Any `.txt` or `.text` files must start with an underscore (e.g., `_notes.txt`).
|
||||
- **Assets:** All images/non-docs must be in `/docs/assets/`. Deep nesting is permitted here.
|
||||
- **Formats:** Prefer **SVG** for diagrams and **PNG** for screenshots. Flag JPG files.
|
||||
|
||||
## Markdown & Style
|
||||
|
||||
- **Headings:** Use Title Case ("First Letter Capitalisation").
|
||||
- The Page Title must be the only H1 (`#`). All others must be `##` or lower.
|
||||
- Do not apply bold or italic styling inside a heading.
|
||||
- **Formatting:**
|
||||
- **Bold:** Only for UI elements (buttons, menu items).
|
||||
- **Italics (Emphasis):** For tool names (e.g., *QGroundControl*).
|
||||
- **Inline Code:** Use backticks for file paths, parameters, and CLI commands (e.g., `prettier`).
|
||||
- **Structure:** End every line at the end of a sentence (Semantic Line Breaks).
|
||||
|
||||
## Linking & Navigation
|
||||
|
||||
- **Standard Links:** Use standard inline syntax: `[link text](../category/filename.md)`.
|
||||
Note relative link.
|
||||
- **Table Links:** To keep tables readable, use reference-style links.
|
||||
- Definition: `[Link Name]: https://example.com` (placed below the table).
|
||||
- Usage: `[Link Name]` within the table cell.
|
||||
- **Images:** All image links must include a descriptive, accessible alt-text in the brackets: ``.
|
||||
Note that all images should be relative references to images stored in the assets folder, which should be two folders below the any markdown file (as they are stored in a "category" subfolder)
|
||||
|
||||
- **Standard Links:** Use standard inline syntax: `[link text](../category/filename.md)`. Note the use of relative links.
|
||||
- **Table Links:** To keep tables easier to edit, prefer reference-style links.
|
||||
- Definition: `[Link Name]: https://example.com` (placed below the table).
|
||||
- Usage: `[Link Name]` within the table cell.
|
||||
- **Images:** All image links must include a descriptive, accessible alt-text: ``.
|
||||
- **Note:** All images must be relative references to the `/docs/assets/` folder. Since documents are nested in a category folder, this is usually two levels up (`../../assets/`).
|
||||
|
||||
## Quality Control
|
||||
|
||||
- **Prettier Check:** Ensure Prettier rules have been applied. If there is evidence of inconsistent indentation or spacing, request the author run `npx prettier --write .` before merging.
|
||||
- **Language:** Enforce **UK English** spelling and grammar.
|
||||
@@ -1,212 +0,0 @@
|
||||
---
|
||||
applyTo: "src/drivers/**"
|
||||
---
|
||||
|
||||
# PX4 Driver Review Instructions
|
||||
|
||||
This file provides guidelines for reviewing driver files in the `src/drivers/` directory.
|
||||
|
||||
## Copyright Statements
|
||||
|
||||
### Required Files
|
||||
|
||||
All source files (`.cpp`, `.c`, `.hpp`, `.h`, `CMakeLists.txt`) MUST include a copyright statement at the top.
|
||||
|
||||
**Exceptions:**
|
||||
- `Kconfig` files
|
||||
- `module.yaml` files
|
||||
|
||||
### Copyright Format
|
||||
|
||||
**For new files (created in 2026):**
|
||||
```cpp
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2026 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name PX4 nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
```
|
||||
|
||||
**For updated files (originally created in 2015, updated in 2026):**
|
||||
```cpp
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2015-2026 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* [... rest of copyright text ...]
|
||||
*
|
||||
****************************************************************************/
|
||||
```
|
||||
|
||||
### Key Points
|
||||
- First year should be the original creation year
|
||||
- When updating an existing file, update the year range: `YYYY-2026`
|
||||
- Use the current year (2026 in this case) for new files
|
||||
- Maintain consistent formatting with other PX4 driver files
|
||||
|
||||
---
|
||||
|
||||
## Driver Self-Documentation
|
||||
|
||||
All drivers MUST be self-documenting through the `print_usage()` method.
|
||||
|
||||
### Required Implementation
|
||||
|
||||
Every driver `.cpp` file must implement a `print_usage()` method that includes:
|
||||
|
||||
1. **PRINT_MODULE_DESCRIPTION macro** - Contains markdown documentation
|
||||
2. **Module identification** - Using PRINT_MODULE_USAGE_NAME and optionally PRINT_MODULE_USAGE_SUBCATEGORY
|
||||
3. **Parameter documentation** - Relevant parameters, especially enablement parameters
|
||||
|
||||
### PRINT_MODULE_DESCRIPTION Structure
|
||||
|
||||
The description should follow this markdown format:
|
||||
|
||||
```cpp
|
||||
PRINT_MODULE_DESCRIPTION(
|
||||
R"DESCR_STR(
|
||||
### Description
|
||||
[Clear description of what the driver does and its primary functionality]
|
||||
|
||||
### Implementation
|
||||
[Optional: High-level overview of how the driver works]
|
||||
|
||||
### Examples
|
||||
[Optional: CLI usage examples if non-trivial]
|
||||
$ module_name start -d /dev/ttyS1
|
||||
$ module_name stop
|
||||
|
||||
)DESCR_STR");
|
||||
```
|
||||
|
||||
### Required Sections
|
||||
|
||||
#### 1. Description Section
|
||||
- Brief explanation of the driver's purpose
|
||||
- Key features/capabilities
|
||||
- Important parameters (especially enable parameters like `SENS_XX_CFG`)
|
||||
|
||||
#### 2. Documentation Links
|
||||
When applicable, include links to user documentation:
|
||||
```cpp
|
||||
Setup/usage information: https://docs.px4.io/main/en/sensor/[sensor-name].html
|
||||
```
|
||||
|
||||
#### 3. Examples Section (when relevant)
|
||||
Provide CLI usage examples for non-trivial commands:
|
||||
```cpp
|
||||
### Examples
|
||||
Attempt to start driver on a specified serial device.
|
||||
$ vectornav start -d /dev/ttyS1
|
||||
Stop driver
|
||||
$ vectornav stop
|
||||
```
|
||||
|
||||
### Complete Example
|
||||
|
||||
```cpp
|
||||
int MyDriver::print_usage(const char *reason)
|
||||
{
|
||||
if (reason) {
|
||||
PX4_WARN("%s\n", reason);
|
||||
}
|
||||
|
||||
PRINT_MODULE_DESCRIPTION(
|
||||
R"DESCR_STR(
|
||||
### Description
|
||||
This driver interfaces with the XYZ sensor via I2C/SPI. It provides
|
||||
distance measurements and is automatically started when SENS_XYZ_CFG
|
||||
is set to the appropriate value.
|
||||
|
||||
Key features:
|
||||
- Distance range: 0.2m to 50m
|
||||
- Update rate: up to 100Hz
|
||||
- I2C and SPI support
|
||||
|
||||
Setup/usage information: https://docs.px4.io/main/en/sensor/xyz_sensor.html
|
||||
|
||||
### Examples
|
||||
Start driver on I2C bus 1 with address 0x29:
|
||||
$ xyz_sensor start -X -b 1 -a 0x29
|
||||
)DESCR_STR");
|
||||
|
||||
PRINT_MODULE_USAGE_NAME("xyz_sensor", "driver");
|
||||
PRINT_MODULE_USAGE_SUBCATEGORY("distance_sensor");
|
||||
PRINT_MODULE_USAGE_COMMAND("start");
|
||||
PRINT_MODULE_USAGE_PARAMS_I2C_SPI_DRIVER(true, true);
|
||||
PRINT_MODULE_USAGE_PARAMS_I2C_ADDRESS(0x29);
|
||||
PRINT_MODULE_USAGE_DEFAULT_COMMANDS();
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Common Patterns by Driver Type
|
||||
|
||||
**For UART/Serial Drivers:**
|
||||
```cpp
|
||||
PRINT_MODULE_USAGE_PARAM_STRING('d', "/dev/ttyS3", "<file:dev>", "Serial device", true);
|
||||
```
|
||||
|
||||
**For I2C/SPI Drivers:**
|
||||
```cpp
|
||||
PRINT_MODULE_USAGE_PARAMS_I2C_SPI_DRIVER(true, true);
|
||||
PRINT_MODULE_USAGE_PARAMS_I2C_ADDRESS(0x76);
|
||||
```
|
||||
|
||||
**For Sensor Drivers:**
|
||||
```cpp
|
||||
PRINT_MODULE_USAGE_SUBCATEGORY("distance_sensor"); // or imu, magnetometer, etc.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Review Checklist
|
||||
|
||||
When reviewing driver files, verify:
|
||||
|
||||
- [ ] Copyright header is present (except Kconfig and module.yaml)
|
||||
- [ ] Copyright year is correct (current year for new files, year range for updates)
|
||||
- [ ] `print_usage()` method exists
|
||||
- [ ] `PRINT_MODULE_DESCRIPTION` macro is present with markdown content
|
||||
- [ ] Description section explains driver purpose clearly
|
||||
- [ ] Relevant parameters are documented (especially enable parameters)
|
||||
- [ ] Documentation links are included when available
|
||||
- [ ] Examples are provided for complex CLI usage
|
||||
- [ ] Module name and category are correctly specified
|
||||
- [ ] Standard commands (start, stop, status) are documented
|
||||
|
||||
---
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- Driver template examples: `src/drivers/*/` (various sensor types)
|
||||
- Module macros: `platforms/common/include/px4_platform_common/module.h`
|
||||
- Similar drivers for reference patterns (DShot, VectorNav, CrsfRc, etc.)
|
||||
@@ -1,24 +0,0 @@
|
||||
runners:
|
||||
x86-small-runner:
|
||||
cpu: [1, 2]
|
||||
ram: [1, 4]
|
||||
disk: default
|
||||
spot: price-capacity-optimized
|
||||
image: ubuntu24-full-x64
|
||||
extras: s3-cache
|
||||
x86-firmware-builder:
|
||||
cpu: [4, 8]
|
||||
ram: [8, 16]
|
||||
disk: default
|
||||
family: ["c7i", "m7i", "r7i"]
|
||||
spot: price-capacity-optimized
|
||||
image: ubuntu24-full-x64
|
||||
extras: s3-cache
|
||||
arm64-firmware-builder:
|
||||
cpu: [4, 8]
|
||||
ram: [8, 16]
|
||||
disk: default
|
||||
family: ["c7g", "m7g", "r7g"]
|
||||
spot: price-capacity-optimized
|
||||
image: ubuntu24-full-arm64
|
||||
extras: s3-cache
|
||||
@@ -26,15 +26,11 @@ concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
actions: read
|
||||
|
||||
jobs:
|
||||
group_targets:
|
||||
name: Scan for Board Targets
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: [runs-on,runner=1cpu-linux-x64,image=ubuntu24-full-x64,"run-id=${{ github.run_id }}",spot=false]
|
||||
runs-on: [runs-on,runner=1cpu-linux-x64,image=ubuntu22-full-x64,"run-id=${{ github.run_id }}",spot=false]
|
||||
outputs:
|
||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||
timestamp: ${{ steps.set-timestamp.outputs.timestamp }}
|
||||
@@ -42,14 +38,6 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Cache Python pip
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**./Tools/setup/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
|
||||
- name: Update python packaging to avoid canonicalize_version() error
|
||||
run: |
|
||||
pip3 install -U packaging
|
||||
@@ -60,15 +48,12 @@ jobs:
|
||||
path: "./Tools/setup/requirements.txt"
|
||||
|
||||
- id: set-matrix
|
||||
name: Generate Build Matrix
|
||||
run: echo "matrix=$(./Tools/ci/generate_board_targets_json.py --group)" >> $GITHUB_OUTPUT
|
||||
run: echo "::set-output name=matrix::$(./Tools/ci/generate_board_targets_json.py --group)"
|
||||
|
||||
- id: set-timestamp
|
||||
name: Save Current Timestamp
|
||||
run: echo "timestamp=$(date +"%Y%m%d%H%M%S")" >> $GITHUB_OUTPUT
|
||||
run: echo "::set-output name=timestamp::$(date +"%Y%m%d%H%M%S")"
|
||||
|
||||
- id: set-branch
|
||||
name: Save Current Branch Name
|
||||
run: |
|
||||
echo "branchname=${{
|
||||
github.event_name == 'pull_request' &&
|
||||
@@ -85,7 +70,7 @@ jobs:
|
||||
echo "$(./Tools/ci/generate_board_targets_json.py --group --verbose)"
|
||||
|
||||
setup:
|
||||
name: Build [${{ matrix.runner }}][${{ matrix.group }}]
|
||||
name: Build Group [${{ matrix.group }}][${{ matrix.arch == 'nuttx' && 'x86' || 'arm64' }}]
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: [runs-on,"runner=8cpu-linux-${{ matrix.runner }}","image=ubuntu24-full-${{ matrix.runner }}","run-id=${{ github.run_id }}",spot=false]
|
||||
needs: group_targets
|
||||
@@ -95,7 +80,6 @@ jobs:
|
||||
container:
|
||||
image: ${{ matrix.container }}
|
||||
steps:
|
||||
- uses: runs-on/action@v2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
@@ -103,24 +87,14 @@ jobs:
|
||||
- name: Git ownership workaround
|
||||
run: git config --system --add safe.directory '*'
|
||||
|
||||
# ccache key breakdown:
|
||||
# ccache-<system os>-<system arch>-<builder group>-
|
||||
# ccache-<linux>-<arm64>-<aarch64-0>-
|
||||
# ccache-<linux>-<x64>-<nuttx-0>-
|
||||
- name: Cache Restore from Key
|
||||
id: cc_restore
|
||||
uses: actions/cache/restore@v4
|
||||
- name: Setup ccache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.ccache
|
||||
key: ${{ format('ccache-{0}-{1}-{2}', runner.os, matrix.runner, matrix.group) }}
|
||||
restore-keys: |
|
||||
ccache-${{ runner.os }}-${{ matrix.runner }}-${{ matrix.group }}-
|
||||
ccache-${{ runner.os }}-${{ matrix.runner }}-
|
||||
ccache-${{ runner.os }}-${{ matrix.runner }}-
|
||||
ccache-${{ runner.os }}-
|
||||
ccache-
|
||||
key: ${{ matrix.group }}-ccache-${{ needs.group_targets.outputs.timestamp }}
|
||||
restore-keys: ${{ matrix.group }}-ccache-${{ needs.group_targets.outputs.timestamp }}
|
||||
|
||||
- name: Cache Config and Stats
|
||||
- name: Configure ccache
|
||||
run: |
|
||||
mkdir -p ~/.ccache
|
||||
echo "base_dir = ${GITHUB_WORKSPACE}" > ~/.ccache/ccache.conf
|
||||
@@ -128,11 +102,10 @@ jobs:
|
||||
echo "compression_level = 6" >> ~/.ccache/ccache.conf
|
||||
echo "max_size = 120M" >> ~/.ccache/ccache.conf
|
||||
echo "hash_dir = false" >> ~/.ccache/ccache.conf
|
||||
echo "compiler_check = content" >> ~/.ccache/ccache.conf
|
||||
ccache -s
|
||||
ccache -z
|
||||
|
||||
- name: Building Artifacts for [${{ matrix.targets }}]
|
||||
- name: Building [${{ matrix.group }}]
|
||||
run: |
|
||||
./Tools/ci/build_all_runner.sh ${{matrix.targets}} ${{matrix.arch}}
|
||||
|
||||
@@ -146,27 +119,15 @@ jobs:
|
||||
name: px4_${{matrix.group}}_build_artifacts
|
||||
path: artifacts/
|
||||
|
||||
- name: Cache Post Build Stats
|
||||
if: always()
|
||||
run: |
|
||||
ccache -s
|
||||
ccache -z
|
||||
|
||||
- name: Cache Save
|
||||
if: always()
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
path: ~/.ccache
|
||||
key: ${{ steps.cc_restore.outputs.cache-primary-key }}
|
||||
run: ccache -s
|
||||
|
||||
artifacts:
|
||||
name: Upload Artifacts
|
||||
name: Upload Artifacts to S3
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: [runs-on,runner=1cpu-linux-x64,image=ubuntu24-full-x64,"run-id=${{ github.run_id }}",spot=false]
|
||||
needs: [setup, group_targets]
|
||||
if: startsWith(github.ref, 'refs/tags/v') || contains(fromJSON('["main","stable","beta"]'), needs.group_targets.outputs.branchname)
|
||||
outputs:
|
||||
uploadlocation: ${{ steps.upload-location.outputs.uploadlocation }}
|
||||
if: contains(fromJSON('["main", "stable", "beta"]'), needs.group_targets.outputs.branchname)
|
||||
steps:
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -174,36 +135,11 @@ jobs:
|
||||
path: artifacts/
|
||||
merge-multiple: true
|
||||
|
||||
- name: Choose Upload Location
|
||||
id: upload-location
|
||||
- name: Branch Name
|
||||
run: |
|
||||
# Determine upload location based on branch or tag with the following considerations:
|
||||
# Destination: AWS S3 bucket px4-travis in folder Firmware/
|
||||
# - If branch is main -> upload to master/
|
||||
# - Older versions of QGC are hardocded to look for master/
|
||||
# - If branch is stable or beta -> upload to stable/ or beta/
|
||||
# - If a tag vX.Y.Z -> upload to vX.Y.Z/
|
||||
# - Also update stable/ to point to the same version
|
||||
#. - Older versions of QGC are hardocded to look for stable/
|
||||
# - If a pull request -> do not upload
|
||||
set -euo pipefail
|
||||
echo "${{ needs.group_targets.outputs.branchname }}"
|
||||
|
||||
ref="${GITHUB_REF}"
|
||||
branch=${{ needs.group_targets.outputs.branchname }}
|
||||
location="$branch"
|
||||
|
||||
if [[ "$branch" == "main" ]]; then
|
||||
location="master"
|
||||
fi
|
||||
|
||||
if [[ "$ref" == refs/tags/v[0-9]* ]]; then
|
||||
tag="${ref#refs/tags/}"
|
||||
location="$tag"
|
||||
fi
|
||||
|
||||
echo "uploadlocation=$location" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Uploading Artifacts to S3 [${{ steps.upload-location.outputs.uploadlocation }}]
|
||||
- name: Uploading Artifacts to S3 [${{ needs.group_targets.outputs.branchname == 'main' && 'master' || needs.group_targets.outputs.branchname }}]
|
||||
uses: jakejarvis/s3-sync-action@master
|
||||
with:
|
||||
args: --acl public-read
|
||||
@@ -213,30 +149,25 @@ jobs:
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
AWS_REGION: 'us-west-1'
|
||||
SOURCE_DIR: artifacts/
|
||||
DEST_DIR: Firmware/${{ steps.upload-location.outputs.uploadlocation }}/
|
||||
DEST_DIR: Firmware/${{ needs.group_targets.outputs.branchname == 'main' && 'master' || needs.group_targets.outputs.branchname }}/
|
||||
|
||||
# if we are uploading artifacts to a versioned folder
|
||||
# we should also update the stable folder in the s3 bucket
|
||||
- name: Uploading Artifacts to S3 [stable]
|
||||
uses: jakejarvis/s3-sync-action@master
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
release:
|
||||
name: Create Release and Upload Artifacts
|
||||
permissions:
|
||||
contents: write
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: [runs-on,runner=1cpu-linux-x64,image=ubuntu24-full-x64,"run-id=${{ github.run_id }}",spot=false]
|
||||
needs: [setup, group_targets]
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
steps:
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
args: --acl public-read
|
||||
env:
|
||||
AWS_S3_BUCKET: 'px4-travis'
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
AWS_REGION: 'us-west-1'
|
||||
SOURCE_DIR: artifacts/
|
||||
DEST_DIR: Firmware/stable/
|
||||
path: artifacts/
|
||||
merge-multiple: true
|
||||
|
||||
# if build is a release triggered by a versioned tag then create a github release
|
||||
# and upload the build artifacts. A draft release is created so that the release
|
||||
# can be reviewed before publishing
|
||||
- name: Upload Artifacts to GitHub Release
|
||||
- name: Upload Binaries to Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
with:
|
||||
draft: true
|
||||
files: artifacts/*.px4
|
||||
name: ${{ steps.upload-location.outputs.uploadlocation }}
|
||||
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
version: ['ubuntu:22.04', 'ubuntu:24.04']
|
||||
runs-on: [runs-on,runner=4cpu-linux-x64,"image=ubuntu24-full-x64","run-id=${{ github.run_id }}",spot=false]
|
||||
runs-on: [runs-on,runner=8cpu-linux-x64,"image=ubuntu24-full-x64","run-id=${{ github.run_id }}",spot=false]
|
||||
container:
|
||||
image: ${{ matrix.version }}
|
||||
volumes:
|
||||
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
name: Set Tags and Variables
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: [runs-on,"runner=1cpu-linux-x64","image=ubuntu24-full-x64","run-id=${{ github.run_id }}",extras=s3-cache,spot=false]
|
||||
runs-on: [runs-on,"runner=1cpu-linux-x64","image=ubuntu24-full-x64","run-id=${{ github.run_id }}",spot=false,extras=s3-cache]
|
||||
outputs:
|
||||
px4_version: ${{ steps.px4_version.outputs.px4_version }}
|
||||
meta_tags: ${{ steps.meta.outputs.tags }}
|
||||
@@ -87,7 +87,7 @@ jobs:
|
||||
- platform: linux/amd64
|
||||
arch: amd64
|
||||
runner: x64
|
||||
runs-on: [runs-on,"runner=4cpu-linux-${{ matrix.runner }}","image=ubuntu24-full-${{ matrix.runner }}","run-id=${{ github.run_id }}",extras=s3-cache,spot=false]
|
||||
runs-on: [runs-on,"runner=8cpu-linux-${{ matrix.runner }}","image=ubuntu24-full-${{ matrix.runner }}","run-id=${{ github.run_id }}",spot=false,extras=s3-cache]
|
||||
steps:
|
||||
- uses: runs-on/action@v1
|
||||
- uses: actions/checkout@v4
|
||||
@@ -130,15 +130,15 @@ jobs:
|
||||
load: false
|
||||
push: ${{ startsWith(github.ref, 'refs/tags/') || (github.event_name == 'workflow_dispatch' && github.event.inputs.deploy_to_registry) }}
|
||||
provenance: false
|
||||
cache-from: type=gha,version=1,scope=${{ matrix.arch }}
|
||||
cache-to: type=gha,version=1,mode=max,scope=${{ matrix.arch }}
|
||||
cache-from: type=gha,version=1
|
||||
cache-to: type=gha,version=1,mode=max
|
||||
|
||||
deploy:
|
||||
name: Deploy To Registry
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
runs-on: [runs-on,"runner=4cpu-linux-x64","image=ubuntu24-full-x64","run-id=${{ github.run_id }}",extras=s3-cache,spot=false]
|
||||
runs-on: [runs-on,"runner=8cpu-linux-x64","image=ubuntu24-full-x64","run-id=${{ github.run_id }}",spot=false,extras=s3-cache]
|
||||
needs: [build, setup]
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') || (github.event_name == 'workflow_dispatch' && github.event.inputs.deploy_to_registry) }}
|
||||
steps:
|
||||
|
||||
@@ -1,6 +1,19 @@
|
||||
name: Docs - Deploy PX4 User Guide to Github pages (Manual)
|
||||
name: Docs - Deploy PX4 User Guide
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
- 'release/**'
|
||||
paths:
|
||||
- 'docs/en/**'
|
||||
pull_request:
|
||||
branches:
|
||||
- '**'
|
||||
paths:
|
||||
- 'docs/en/**'
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||
@@ -20,7 +33,7 @@ env:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: [runs-on,runner=4cpu-linux-x64,image=ubuntu24-full-x64,"run-id=${{ github.run_id }}",extras=s3-cache,spot=false]
|
||||
runs-on: [runs-on,runner=8cpu-linux-x64,image=ubuntu24-full-x64,"run-id=${{ github.run_id }}",spot=false,extras=s3-cache]
|
||||
steps:
|
||||
- uses: runs-on/action@v1
|
||||
- name: Checkout
|
||||
@@ -55,7 +68,7 @@ jobs:
|
||||
deploy:
|
||||
if: ${{ github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.merged) || github.event_name == 'workflow_dispatch' }}
|
||||
needs: build
|
||||
runs-on: [runs-on,runner=4cpu-linux-x64,image=ubuntu24-full-x64,"run-id=${{ github.run_id }}",spot=false]
|
||||
runs-on: [runs-on,runner=8cpu-linux-x64,image=ubuntu24-full-x64,"run-id=${{ github.run_id }}",spot=false]
|
||||
|
||||
steps:
|
||||
- name: Download Artifact
|
||||
|
||||
@@ -7,52 +7,42 @@ on:
|
||||
- "release/**"
|
||||
paths:
|
||||
- "docs/en/**"
|
||||
- "docs/zh/**"
|
||||
- "docs/uk/**"
|
||||
- "docs/ko/**"
|
||||
pull_request:
|
||||
branches:
|
||||
- "**"
|
||||
paths:
|
||||
- "docs/en/**"
|
||||
- "docs/zh/**"
|
||||
- "docs/uk/**"
|
||||
- "docs/ko/**"
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
actions: read
|
||||
id-token: write # for AWS OIDC
|
||||
|
||||
concurrency:
|
||||
group: docs-deploy
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: [runs-on,runner=4cpu-linux-x64,image=ubuntu24-full-x64,"run-id=${{ github.run_id }}",spot=false,extras=s3-cache]
|
||||
outputs:
|
||||
branchname: ${{ steps.set-branch.outputs.branchname }}
|
||||
releaseversion: ${{ steps.set-version.outputs.releaseversion }}
|
||||
runs-on:
|
||||
[
|
||||
runs-on,
|
||||
runner=8cpu-linux-x64,
|
||||
image=ubuntu24-full-x64,
|
||||
"run-id=${{ github.run_id }}",
|
||||
spot=false,
|
||||
extras=s3-cache,
|
||||
]
|
||||
steps:
|
||||
- uses: runs-on/action@v1
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- id: set-branch
|
||||
run: echo "branchname=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT
|
||||
|
||||
- id: set-version
|
||||
run: |
|
||||
branch="${{ steps.set-branch.outputs.branchname }}"
|
||||
if [[ "$branch" == "main" ]]; then
|
||||
version="main"
|
||||
else
|
||||
version="v${branch#release/}"
|
||||
fi
|
||||
echo "releaseversion=$version" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
@@ -65,8 +55,6 @@ jobs:
|
||||
|
||||
- name: Build with VitePress
|
||||
working-directory: ./docs
|
||||
env:
|
||||
BRANCH_NAME: ${{ steps.set-version.outputs.releaseversion }}
|
||||
run: |
|
||||
npm run docs:build_ubuntu
|
||||
touch .vitepress/dist/.nojekyll
|
||||
@@ -103,14 +91,14 @@ jobs:
|
||||
|
||||
- name: Upload HTML with short cache
|
||||
run: |
|
||||
aws s3 sync ~/_book/ s3://px4-docs/${{ needs.build.outputs.releaseversion }}/ \
|
||||
aws s3 sync ~/_book/ s3://px4-docs/${{ env.BRANCH_NAME }}/ \
|
||||
--delete \
|
||||
--exclude "*" --include "*.html" \
|
||||
--cache-control "public, max-age=60"
|
||||
|
||||
- name: Upload assets with long cache
|
||||
run: |
|
||||
aws s3 sync ~/_book/ s3://px4-docs/${{ needs.build.outputs.releaseversion }}/ \
|
||||
aws s3 sync ~/_book/ s3://px4-docs/${{ env.BRANCH_NAME }}/ \
|
||||
--delete \
|
||||
--exclude "*.html" \
|
||||
--cache-control "public, max-age=86400, immutable"
|
||||
@@ -48,7 +48,6 @@ jobs:
|
||||
run: |
|
||||
git clone https://github.com/emscripten-core/emsdk.git _emscripten_sdk
|
||||
cd _emscripten_sdk
|
||||
git checkout 4.0.15
|
||||
./emsdk install latest
|
||||
./emsdk activate latest
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ env:
|
||||
jobs:
|
||||
analyze_flash:
|
||||
name: Analyzing ${{ matrix.target }}
|
||||
runs-on: [runs-on,runner=4cpu-linux-x64,image=ubuntu24-full-x64,"run-id=${{ github.run_id }}",spot=false]
|
||||
runs-on: [runs-on,runner=8cpu-linux-x64,image=ubuntu24-full-x64,"run-id=${{ github.run_id }}",spot=false]
|
||||
container:
|
||||
image: px4io/px4-dev:v1.16.0-rc1-258-g0369abd556
|
||||
strategy:
|
||||
@@ -54,7 +54,6 @@ jobs:
|
||||
run: |
|
||||
make clean
|
||||
make distclean
|
||||
make submodulesclean
|
||||
|
||||
- name: If it's a PR checkout the base branch
|
||||
if: ${{ github.event.pull_request }}
|
||||
@@ -98,7 +97,7 @@ jobs:
|
||||
# Track this issue https://github.com/PX4/PX4-Autopilot/issues/24408
|
||||
post_pr_comment:
|
||||
name: Publish Results
|
||||
runs-on: [runs-on,runner=1cpu-linux-x64,image=ubuntu24-full-x64,"run-id=${{ github.run_id }}"]
|
||||
runs-on: [runs-on,runner=1cpu-linux-x64,image=ubuntu24-full-x64,"run-id=${{ github.run_id }}",spot=false]
|
||||
needs: [analyze_flash]
|
||||
env:
|
||||
V5X-SUMMARY-MAP-ABS: ${{ fromJSON(fromJSON(needs.analyze_flash.outputs.px4_fmu-v5x-bloaty-summary-map).vm-absolute) }}
|
||||
|
||||
@@ -22,7 +22,7 @@ concurrency:
|
||||
jobs:
|
||||
check_itcm:
|
||||
name: Checking ${{ matrix.target }}
|
||||
runs-on: [runs-on,runner=4cpu-linux-x64,image=ubuntu24-full-x64,"run-id=${{ github.run_id }}",spot=false]
|
||||
runs-on: [runs-on,runner=8cpu-linux-x64,image=ubuntu24-full-x64,"run-id=${{ github.run_id }}",spot=false]
|
||||
container:
|
||||
image: px4io/px4-dev:v1.16.0-rc1-258-g0369abd556
|
||||
strategy:
|
||||
@@ -41,10 +41,6 @@ jobs:
|
||||
scripts: >
|
||||
boards/nxp/tropic-community/nuttx-config/scripts/itcm_functions_includes.ld
|
||||
boards/nxp/tropic-community/nuttx-config/scripts/itcm_static_functions.ld
|
||||
- target: nxp_mr-tropic
|
||||
scripts: >
|
||||
boards/nxp/mr-tropic/nuttx-config/scripts/itcm_functions_includes.ld
|
||||
boards/nxp/mr-tropic/nuttx-config/scripts/itcm_static_functions.ld
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
|
||||
@@ -23,7 +23,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: [runs-on,runner=4cpu-linux-x64,image=ubuntu22-full-x64,"run-id=${{ github.run_id }}",spot=false]
|
||||
runs-on: [runs-on,runner=16cpu-linux-x64,image=ubuntu22-full-x64,"run-id=${{ github.run_id }}",spot=false]
|
||||
container:
|
||||
image: px4io/px4-dev-ros2-galactic:2021-09-08
|
||||
options: --privileged --ulimit core=-1 --security-opt seccomp=unconfined
|
||||
@@ -90,9 +90,6 @@ jobs:
|
||||
mkdir -p /opt/px4_ws/src
|
||||
cd /opt/px4_ws/src
|
||||
git clone --recursive https://github.com/Auterion/px4-ros2-interface-lib.git
|
||||
# Ignore python packages due to compilation issue (can be enabled when updating ROS)
|
||||
touch px4-ros2-interface-lib/px4_ros2_py/COLCON_IGNORE || true
|
||||
touch px4-ros2-interface-lib/examples/python/COLCON_IGNORE || true
|
||||
cd ..
|
||||
# Copy messages to ROS workspace
|
||||
"${PX4_DIR}/Tools/copy_to_ros_ws.sh" "$(pwd)"
|
||||
|
||||
@@ -21,7 +21,7 @@ concurrency:
|
||||
jobs:
|
||||
build_and_test:
|
||||
name: Build and test
|
||||
runs-on: [runs-on,runner=4cpu-linux-x64,image=ubuntu24-full-x64,"run-id=${{ github.run_id }}",spot=false]
|
||||
runs-on: [runs-on,runner=8cpu-linux-x64,image=ubuntu24-full-x64,"run-id=${{ github.run_id }}",spot=false]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
@@ -24,7 +24,7 @@ concurrency:
|
||||
jobs:
|
||||
build:
|
||||
name: Testing PX4 ${{ matrix.config.model }}
|
||||
runs-on: [runs-on,runner=4cpu-linux-x64,image=ubuntu22-full-x64,"run-id=${{ github.run_id }}",spot=false]
|
||||
runs-on: [runs-on,runner=16cpu-linux-x64,image=ubuntu22-full-x64,"run-id=${{ github.run_id }}",spot=false]
|
||||
container:
|
||||
image: px4io/px4-dev-simulation-focal:2021-09-08
|
||||
options: --privileged --ulimit core=-1 --security-opt seccomp=unconfined
|
||||
@@ -118,7 +118,7 @@ jobs:
|
||||
PX4_HOME_LON: ${{matrix.config.longitude}}
|
||||
PX4_HOME_ALT: ${{matrix.config.altitude}}
|
||||
PX4_CMAKE_BUILD_TYPE: ${{matrix.config.build_type}}
|
||||
run: test/mavsdk_tests/mavsdk_test_runner.py --speed-factor 10 --abort-early --model ${{matrix.config.model}} test/mavsdk_tests/configs/sitl.json --verbose --force-color
|
||||
run: test/mavsdk_tests/mavsdk_test_runner.py --speed-factor 10 --abort-early --model ${{matrix.config.model}} --upload test/mavsdk_tests/configs/sitl.json --verbose --force-color
|
||||
timeout-minutes: 45
|
||||
|
||||
- name: Upload failed logs
|
||||
|
||||
@@ -7,15 +7,10 @@ jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v10
|
||||
- uses: actions/stale@v8
|
||||
with:
|
||||
operations-per-run: 250
|
||||
days-before-stale: 90
|
||||
days-before-close: 30
|
||||
days-before-stale: 30
|
||||
days-before-close: -1
|
||||
stale-issue-label: 'stale'
|
||||
stale-pr-label: 'stale'
|
||||
remove-stale-when-updated: true
|
||||
stale-issue-message: ''
|
||||
close-issue-message: 'This issue has been automatically closed due to 120 days of inactivity. If you believe this is still relevant, please feel free to reopen it or create a new issue.'
|
||||
stale-pr-message: ''
|
||||
close-pr-message: 'This pull request has been automatically closed due to 120 days of inactivity. If you would like to continue, please feel free to reopen it or submit a new PR.'
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
name: Sync ROS 2 messages to px4_msgs
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
- 'stable'
|
||||
- 'beta'
|
||||
- 'release/**'
|
||||
paths:
|
||||
- 'msg/**'
|
||||
- 'srv/**'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
sync_to_px4_msgs:
|
||||
if: github.repository == 'PX4/PX4-Autopilot'
|
||||
runs-on: [runs-on,runner=4cpu-linux-x64,image=ubuntu22-full-x64,"run-id=${{ github.run_id }}",spot=false]
|
||||
steps:
|
||||
- name: Checkout PX4 repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup git credentials
|
||||
run: |
|
||||
git config --global user.name "${{ secrets.PX4BUILDBOT_USER }}"
|
||||
git config --global user.email "${{ secrets.PX4BUILDBOT_EMAIL }}"
|
||||
|
||||
- name: Clone PX4_msgs repo
|
||||
run: |
|
||||
git clone https://${{ secrets.PX4BUILTBOT_PERSONAL_ACCESS_TOKEN }}@github.com/PX4/px4_msgs.git
|
||||
|
||||
- name: Check out the same branch as the PX4 repo
|
||||
run: |
|
||||
cd px4_msgs
|
||||
if git checkout ${{ github.ref_name }}; then
|
||||
echo "Checked out existing branch"
|
||||
else
|
||||
git checkout -b ${{ github.ref_name }}
|
||||
fi
|
||||
|
||||
- name: Copy ROS 2 messages
|
||||
run: |
|
||||
rm -f px4_msgs/msg/*.msg
|
||||
rm -f px4_msgs/msg/versioned/*.msg
|
||||
rm -f px4_msgs/srv/*.srv
|
||||
rm -f px4_msgs/srv/versioned/*.srv
|
||||
cp msg/*.msg px4_msgs/msg/
|
||||
cp msg/versioned/*.msg px4_msgs/msg/ || true
|
||||
cp srv/*.srv px4_msgs/srv/
|
||||
cp srv/versioned/*.srv px4_msgs/srv/ || true
|
||||
|
||||
- name: Commit and push changes
|
||||
run: |
|
||||
cd px4_msgs
|
||||
git status
|
||||
git add .
|
||||
git commit -a -m "Update to PX4 ${{ github.sha }}" || true
|
||||
git push origin ${{ github.ref_name }} || true
|
||||
cd ..
|
||||
rm -rf px4_msgs
|
||||
@@ -103,9 +103,3 @@
|
||||
[submodule "src/drivers/ins/sbgecom/sbgECom"]
|
||||
path = src/drivers/ins/sbgecom/sbgECom
|
||||
url = https://github.com/PX4/sbgECom.git
|
||||
[submodule "src/modules/mc_raptor/blob"]
|
||||
path = src/modules/mc_raptor/blob
|
||||
url = https://github.com/rl-tools/px4-blob
|
||||
[submodule "src/lib/rl_tools/rl_tools"]
|
||||
path = src/lib/rl_tools/rl_tools
|
||||
url = https://github.com/rl-tools/rl-tools.git
|
||||
|
||||
Vendored
-65
@@ -6,16 +6,6 @@ CONFIG:
|
||||
buildType: RelWithDebInfo
|
||||
settings:
|
||||
CONFIG: px4_sitl_default
|
||||
px4_sitl_raptor:
|
||||
short: px4_sitl_raptor
|
||||
buildType: RelWithDebInfo
|
||||
settings:
|
||||
CONFIG: px4_sitl_raptor
|
||||
px4_sitl_raptor_debug:
|
||||
short: px4_sitl_raptor_debug
|
||||
buildType: Debug
|
||||
settings:
|
||||
CONFIG: px4_sitl_raptor
|
||||
px4_sitl_spacecraft:
|
||||
short: px4_sitl_spacecraft
|
||||
buildType: RelWithDebInfo
|
||||
@@ -151,11 +141,6 @@ CONFIG:
|
||||
buildType: MinSizeRel
|
||||
settings:
|
||||
CONFIG: ark_can-flow_canbootloader
|
||||
ark_can-flow-mr_default:
|
||||
short: ark_can-flow-mr_default
|
||||
buildType: MinSizeRel
|
||||
settings:
|
||||
CONFIG: ark_can-flow-mr_default
|
||||
ark_can-flow-mr_canbootloader:
|
||||
short: ark_can-flow-mr_canbootloader
|
||||
buildType: MinSizeRel
|
||||
@@ -251,16 +236,6 @@ CONFIG:
|
||||
buildType: MinSizeRel
|
||||
settings:
|
||||
CONFIG: ark_fpv_default
|
||||
ark_mag_canbootloader:
|
||||
short: ark_mag_canbootloader
|
||||
buildType: MiniSizeRel
|
||||
settings:
|
||||
CONFIG: ark_mag_canbootloader
|
||||
ark_mag_default:
|
||||
short: ark_mag_default
|
||||
buildType: MiniSizeRel
|
||||
settings:
|
||||
CONFIG: ark_mag_default
|
||||
ark_pi6x_bootloader:
|
||||
short: ark_pi6x_bootloader
|
||||
buildType: MinSizeRel
|
||||
@@ -431,16 +406,6 @@ CONFIG:
|
||||
buildType: MinSizeRel
|
||||
settings:
|
||||
CONFIG: micoair_h743-v2_default
|
||||
micoair_h743-lite_bootloader:
|
||||
short: micoair_h743-lite_bootloader
|
||||
buildType: MinSizeRel
|
||||
settings:
|
||||
CONFIG: micoair_h743-lite_bootloader
|
||||
micoair_h743-lite_default:
|
||||
short: micoair_h743-lite
|
||||
buildType: MinSizeRel
|
||||
settings:
|
||||
CONFIG: micoair_h743-lite_default
|
||||
modalai_fc-v1_default:
|
||||
short: modalai_fc-v1
|
||||
buildType: MinSizeRel
|
||||
@@ -491,16 +456,6 @@ CONFIG:
|
||||
buildType: MinSizeRel
|
||||
settings:
|
||||
CONFIG: nxp_mr-canhubk3_fmu
|
||||
nxp_mr-tropic_default:
|
||||
short: nxp_mr-tropic_default
|
||||
buildType: MinSizeRel
|
||||
settings:
|
||||
CONFIG: nxp_mr-tropic_default
|
||||
nxp_mr-tropic_bootloader:
|
||||
short: nxp_mr-tropic_bootloader
|
||||
buildType: MinSizeRel
|
||||
settings:
|
||||
CONFIG: nxp_mr-tropic_bootloader
|
||||
nxp_tropic-community_default:
|
||||
short: nxp_tropic-community_default
|
||||
buildType: MinSizeRel
|
||||
@@ -531,23 +486,3 @@ CONFIG:
|
||||
buildType: MinSizeRel
|
||||
settings:
|
||||
CONFIG: x-mav_ap-h743v2_default
|
||||
svehicle_e2_bootloader:
|
||||
short: svehicle_e2_bootloader
|
||||
buildType: MinSizeRel
|
||||
settings:
|
||||
CONFIG: svehicle_e2_bootloader
|
||||
svehicle_e2_default:
|
||||
short: svehicle_e2
|
||||
buildType: MinSizeRel
|
||||
settings:
|
||||
CONFIG: svehicle_e2_default
|
||||
x-mav_ap-h743r1_bootloader:
|
||||
short: x-mav_ap-h743r1-boot
|
||||
buildType: MinSizeRel
|
||||
settings:
|
||||
CONFIG: x-mav_ap-h743r1_bootloader
|
||||
x-mav_ap-h743r1_default:
|
||||
short: x-mav_ap-h743r1
|
||||
buildType: MinSizeRel
|
||||
settings:
|
||||
CONFIG: x-mav_ap-h743r1_default
|
||||
|
||||
+1
-1
@@ -267,7 +267,7 @@ endif()
|
||||
|
||||
set(package-contact "px4users@googlegroups.com")
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
## This file should be placed in the root directory of your project.
|
||||
## Then modify the CMakeLists.txt file in the root directory of your
|
||||
## project to incorporate the testing dashboard.
|
||||
##
|
||||
## # The following are required to submit to the CDash dashboard:
|
||||
## ENABLE_TESTING()
|
||||
## INCLUDE(CTest)
|
||||
|
||||
set(CTEST_PROJECT_NAME "PX4 Firmware")
|
||||
set(CTEST_NIGHTLY_START_TIME "00:00:00 EST")
|
||||
|
||||
set(CTEST_DROP_METHOD "http")
|
||||
set(CTEST_DROP_SITE "my.cdash.org")
|
||||
set(CTEST_DROP_LOCATION "/submit.php?project=PX4+Firmware")
|
||||
set(CTEST_DROP_SITE_CDASH TRUE)
|
||||
Vendored
+30
-1
@@ -101,7 +101,6 @@ pipeline {
|
||||
echo $0;
|
||||
git clone https://github.com/emscripten-core/emsdk.git _emscripten_sdk;
|
||||
cd _emscripten_sdk;
|
||||
git checkout 4.0.15;
|
||||
./emsdk install latest;
|
||||
./emsdk activate latest;
|
||||
cd ..;
|
||||
@@ -221,6 +220,36 @@ pipeline {
|
||||
}
|
||||
}
|
||||
|
||||
stage('PX4 ROS msgs') {
|
||||
agent {
|
||||
docker { image 'px4io/px4-dev-base-focal:2021-08-18' }
|
||||
}
|
||||
steps {
|
||||
sh('export')
|
||||
sh('make distclean; git clean -ff -x -d .')
|
||||
withCredentials([usernamePassword(credentialsId: 'px4buildbot_github_personal_token', passwordVariable: 'GIT_PASS', usernameVariable: 'GIT_USER')]) {
|
||||
sh("git clone https://${GIT_USER}:${GIT_PASS}@github.com/PX4/px4_msgs.git")
|
||||
// 'main' branch
|
||||
sh('rm -f px4_msgs/msg/*.msg')
|
||||
sh('rm -f px4_msgs/msg/versioned/*.msg')
|
||||
sh('rm -f px4_msgs/srv/*.srv')
|
||||
sh('rm -f px4_msgs/srv/versioned/*.srv')
|
||||
sh('cp msg/*.msg px4_msgs/msg/')
|
||||
sh('cp msg/versioned/*.msg px4_msgs/msg/ || true')
|
||||
sh('cp srv/*.srv px4_msgs/srv/')
|
||||
sh('cp srv/versioned/*.srv px4_msgs/srv/ || true')
|
||||
sh('cd px4_msgs; git status; git add .; git commit -a -m "Update message definitions `date`" || true')
|
||||
sh('cd px4_msgs; git push origin main || true')
|
||||
sh('rm -rf px4_msgs')
|
||||
}
|
||||
}
|
||||
when {
|
||||
anyOf {
|
||||
branch 'main'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('S3') {
|
||||
agent {
|
||||
docker { image 'px4io/px4-dev-base-focal:2021-08-18' }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2012 - 2025, PX4 Development Team
|
||||
Copyright (c) 2012 - 2023, PX4 Development Team
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -325,8 +325,6 @@ bootloaders_update: \
|
||||
ark_fmu-v6x_bootloader \
|
||||
ark_fpv_bootloader \
|
||||
ark_pi6x_bootloader \
|
||||
auterion_fmu-v6s_bootloader \
|
||||
auterion_fmu-v6x_bootloader \
|
||||
cuav_nora_bootloader \
|
||||
cuav_x7pro_bootloader \
|
||||
cuav_7-nano_bootloader \
|
||||
@@ -346,7 +344,6 @@ bootloaders_update: \
|
||||
micoair_h743_bootloader \
|
||||
micoair_h743-aio_bootloader \
|
||||
micoair_h743-v2_bootloader \
|
||||
micoair_h743-lite_bootloader \
|
||||
modalai_fc-v2_bootloader \
|
||||
mro_ctrl-zero-classic_bootloader \
|
||||
mro_ctrl-zero-h7_bootloader \
|
||||
|
||||
@@ -85,32 +85,10 @@ endif()
|
||||
if(PX4_ETHERNET)
|
||||
set(added_arguments ${added_arguments} --ethernet)
|
||||
endif()
|
||||
# Check if board has an rc.board_airframes file to filter airframes
|
||||
set(board_airframes_file "${PX4_BOARD_DIR}/init/rc.board_airframes")
|
||||
set(airframes_whitelist "")
|
||||
if(EXISTS "${board_airframes_file}")
|
||||
message(STATUS "ROMFS: Using board-specific airframes list: ${board_airframes_file}")
|
||||
file(STRINGS "${board_airframes_file}" airframes_whitelist)
|
||||
# Remove comments and empty lines
|
||||
list(FILTER airframes_whitelist EXCLUDE REGEX "^[ \t]*#")
|
||||
list(FILTER airframes_whitelist EXCLUDE REGEX "^[ \t]*$")
|
||||
endif()
|
||||
|
||||
# create list of relative romfs file names
|
||||
set(romfs_copy_files_relative)
|
||||
foreach(romfs_file IN LISTS romfs_copy_files)
|
||||
string(REPLACE "${romfs_src_dir}/" "" romfs_file_rel ${romfs_file})
|
||||
|
||||
# If we have an airframes whitelist, filter airframe files
|
||||
if(airframes_whitelist AND romfs_file_rel MATCHES "^init.d/airframes/")
|
||||
# Extract just the filename
|
||||
get_filename_component(airframe_name "${romfs_file_rel}" NAME)
|
||||
# Check if it's in the whitelist
|
||||
if(NOT "${airframe_name}" IN_LIST airframes_whitelist)
|
||||
continue()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(APPEND romfs_copy_files_relative ${romfs_file_rel})
|
||||
endforeach()
|
||||
# copy the ROMFS files by creating a tar and extracting it to the build
|
||||
|
||||
@@ -27,6 +27,7 @@ param set-default SIH_KDV 0.2
|
||||
param set-default SIH_VEHICLE_TYPE 1 # sih as fixed wing
|
||||
param set-default RWTO_TKOFF 1 # enable takeoff from runway (as opposed to launched)
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
param set-default CA_ROTOR0_PX 0.3
|
||||
|
||||
|
||||
@@ -44,6 +44,8 @@ param set-default NAV_DLL_ACT 2
|
||||
|
||||
param set-default RWTO_TKOFF 1
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
param set-default CA_ROTOR0_PX 0.3
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@ param set-default NAV_DLL_ACT 2
|
||||
|
||||
param set-default RWTO_TKOFF 1
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
param set-default CA_ROTOR0_PX 0.3
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@ param set-default MIS_TAKEOFF_ALT 30
|
||||
param set-default NAV_ACC_RAD 15
|
||||
param set-default NAV_DLL_ACT 2
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
param set-default CA_ROTOR0_PX 0.3
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ param set-default NAV_DLL_ACT 2
|
||||
param set-default RWTO_TKOFF 1
|
||||
param set-default RWTO_PSP 8
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
param set-default CA_ROTOR0_PX 0.3
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ param set-default NAV_DLL_ACT 2
|
||||
param set-default RWTO_TKOFF 1
|
||||
param set-default RWTO_PSP 8
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
param set-default CA_ROTOR0_PX 0.3
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@ param set-default NAV_DLL_ACT 2
|
||||
|
||||
param set-default RWTO_TKOFF 1
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
param set-default CA_ROTOR0_PX 0.3
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ param set-default NAV_DLL_ACT 2
|
||||
param set-default RWTO_TKOFF 1
|
||||
param set-default RWTO_PSP 8
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
param set-default CA_ROTOR0_PX 0.3
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ param set-default NAV_DLL_ACT 2
|
||||
|
||||
param set-default RWTO_TKOFF 1
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
param set-default CA_ROTOR0_PX 0.3
|
||||
|
||||
|
||||
@@ -44,6 +44,8 @@ param set-default MIS_TAKEOFF_ALT 30
|
||||
param set-default NAV_ACC_RAD 15
|
||||
param set-default NAV_DLL_ACT 2
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
param set-default CA_ROTOR0_PX 0.3
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ param set-default RWTO_MAX_PITCH 20
|
||||
param set-default RWTO_PSP 8
|
||||
param set-default RWTO_AIRSPD_SCL 1.8
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
param set-default CA_ROTOR0_PX 0.3
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ param set-default NAV_DLL_ACT 2
|
||||
|
||||
param set-default RWTO_TKOFF 1
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
param set-default CA_ROTOR0_PX 0.3
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@ param set-default NAV_DLL_ACT 2
|
||||
|
||||
param set-default RWTO_TKOFF 1
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
param set-default CA_ROTOR0_PX 0.3
|
||||
|
||||
|
||||
@@ -43,6 +43,8 @@ param set-default FW_THR_TRIM 0.8
|
||||
param set-default FW_THR_IDLE 0
|
||||
param set-default COM_DISARM_PRFLT 0
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
param set-default CA_ROTOR0_PX 0.3
|
||||
|
||||
|
||||
@@ -48,6 +48,8 @@ param set-default FW_THR_TRIM 0.8
|
||||
param set-default FW_THR_IDLE 0
|
||||
param set-default COM_DISARM_PRFLT 0
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
param set-default CA_ROTOR0_PX 0.3
|
||||
|
||||
|
||||
@@ -49,3 +49,9 @@ param set-default SIM_GZ_EC_MAX4 1000
|
||||
|
||||
param set-default MPC_THR_HOVER 0.60
|
||||
param set-default NAV_DLL_ACT 2
|
||||
|
||||
# DEBUGGING: ekf range fusion
|
||||
# default, ekf replay, cv+avoid, high rate sensors
|
||||
param set-default SDLOG_PROFILE 2179
|
||||
# sim distance on ground
|
||||
param set-default EKF2_MIN_RNG 0.177
|
||||
|
||||
@@ -53,6 +53,8 @@ param set-default NAV_DLL_ACT 2
|
||||
|
||||
param set-default RWTO_TKOFF 1
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
|
||||
param set-default COM_PREARM_MODE 2
|
||||
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
|
||||
@@ -101,6 +101,6 @@ param set-default NAV_ACC_RAD 5
|
||||
param set-default NAV_DLL_ACT 2
|
||||
|
||||
param set-default VT_FWD_THRUST_EN 4
|
||||
param set-default VT_F_TRANS_THR 1
|
||||
param set-default VT_F_TRANS_THR 0.3
|
||||
param set-default VT_TYPE 2
|
||||
param set-default FD_ESCS_EN 0
|
||||
|
||||
@@ -11,6 +11,8 @@ PX4_SIM_MODEL=${PX4_SIM_MODEL:=advanced_plane}
|
||||
|
||||
param set-default SIM_GZ_EN 1
|
||||
|
||||
param set-default SENS_EN_ARSPDSIM 1
|
||||
|
||||
param set-default FW_LND_ANG 8
|
||||
|
||||
param set-default FW_PR_FF 0.08
|
||||
@@ -46,6 +48,8 @@ param set-default NAV_DLL_ACT 2
|
||||
|
||||
param set-default RWTO_TKOFF 1
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
|
||||
param set-default CA_SV_CS_COUNT 6
|
||||
|
||||
+20
-22
@@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
# @name Generic Ackermann Rover
|
||||
# @name Rover Ackermann
|
||||
# @type Rover
|
||||
# @class Rover
|
||||
|
||||
@@ -14,32 +14,30 @@ param set-default SIM_GZ_EN 1 # Gazebo bridge
|
||||
param set-default NAV_ACC_RAD 0.5
|
||||
|
||||
# Ackermann Parameters
|
||||
param set-default RA_WHEEL_BASE 0.5
|
||||
param set-default RA_WHEEL_BASE 0.321
|
||||
param set-default RA_ACC_RAD_GAIN 2
|
||||
param set-default RA_ACC_RAD_MAX 1.5
|
||||
param set-default RA_ACC_RAD_MAX 3
|
||||
param set-default RA_MAX_STR_ANG 0.5236
|
||||
param set-default RA_STR_RATE_LIM 360
|
||||
|
||||
# Rate Control Parameters
|
||||
param set-default RO_YAW_RATE_I 0.01
|
||||
param set-default RO_YAW_RATE_P 0.25
|
||||
param set-default RO_YAW_RATE_LIM 130
|
||||
param set-default RO_YAW_ACCEL_LIM 800
|
||||
param set-default RO_YAW_DECEL_LIM 800
|
||||
param set-default RO_YAW_RATE_CORR 1
|
||||
param set-default RO_YAW_EXPO 0.85
|
||||
param set-default RO_YAW_SUPEXPO 0.3
|
||||
# Rover Control Parameters
|
||||
param set-default RO_ACCEL_LIM 3
|
||||
param set-default RO_DECEL_LIM 6
|
||||
param set-default RO_JERK_LIM 15
|
||||
param set-default RO_MAX_THR_SPEED 3.1
|
||||
|
||||
# Attitude Control Parameters
|
||||
# Rover Rate Control Parameters
|
||||
param set-default RO_YAW_RATE_I 0.1
|
||||
param set-default RO_YAW_RATE_P 1
|
||||
param set-default RO_YAW_RATE_LIM 180
|
||||
param set-default RO_YAW_RATE_CORR 1
|
||||
|
||||
# Rover Attitude Control Parameters
|
||||
param set-default RO_YAW_P 3
|
||||
|
||||
# Velocity Control Parameters
|
||||
param set-default RO_ACCEL_LIM 4
|
||||
param set-default RO_DECEL_LIM 6
|
||||
param set-default RO_JERK_LIM 10
|
||||
param set-default RO_MAX_THR_SPEED 3.1
|
||||
param set-default RO_SPEED_LIM 2.5
|
||||
param set-default RO_SPEED_I 0.01
|
||||
# Rover Velocity Control Parameters
|
||||
param set-default RO_SPEED_LIM 3
|
||||
param set-default RO_SPEED_I 0.1
|
||||
param set-default RO_SPEED_P 1
|
||||
param set-default RO_SPEED_RED 1
|
||||
|
||||
@@ -50,8 +48,8 @@ param set-default PP_LOOKAHD_MIN 1
|
||||
|
||||
# Wheels
|
||||
param set-default SIM_GZ_WH_FUNC1 101
|
||||
param set-default SIM_GZ_WH_MIN1 70
|
||||
param set-default SIM_GZ_WH_MAX1 130
|
||||
param set-default SIM_GZ_WH_MIN1 0
|
||||
param set-default SIM_GZ_WH_MAX1 200
|
||||
param set-default SIM_GZ_WH_DIS1 100
|
||||
|
||||
# Steering
|
||||
+13
-20
@@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
# @name Generic Mecanum Rover
|
||||
# @name Aion Robotics R1 Rover
|
||||
# @type Rover
|
||||
# @class Rover
|
||||
|
||||
@@ -7,15 +7,14 @@
|
||||
|
||||
PX4_SIMULATOR=${PX4_SIMULATOR:=gz}
|
||||
PX4_GZ_WORLD=${PX4_GZ_WORLD:=rover}
|
||||
PX4_SIM_MODEL=${PX4_SIM_MODEL:=rover_mecanum}
|
||||
PX4_SIM_MODEL=${PX4_SIM_MODEL:=r1_rover_mecanum}
|
||||
|
||||
param set-default SIM_GZ_EN 1 # Gazebo bridge
|
||||
|
||||
param set-default NAV_ACC_RAD 0.5
|
||||
|
||||
# Mecanum Parameters
|
||||
param set-default RM_WHEEL_TRACK 0.6
|
||||
param set-default RM_YAW_STK_GAIN 0.6
|
||||
param set-default RM_WHEEL_TRACK 0.3
|
||||
|
||||
# Rover Control Parameters
|
||||
param set-default RO_ACCEL_LIM 3
|
||||
@@ -30,21 +29,15 @@ param set-default RO_YAW_RATE_LIM 120
|
||||
param set-default RO_YAW_ACCEL_LIM 240
|
||||
param set-default RO_YAW_DECEL_LIM 1000
|
||||
param set-default RO_YAW_RATE_CORR 1.75
|
||||
param set-default RO_YAW_EXPO 0.85
|
||||
param set-default RO_YAW_SUPEXPO 0.3
|
||||
|
||||
# Rover Attitude Control Parameters
|
||||
param set-default RO_YAW_P 5
|
||||
|
||||
# Velocity Control Parameters
|
||||
param set-default RO_ACCEL_LIM 4
|
||||
param set-default RO_DECEL_LIM 6
|
||||
param set-default RO_JERK_LIM 10
|
||||
param set-default RO_MAX_THR_SPEED 3.1
|
||||
param set-default RO_SPEED_LIM 2.5
|
||||
param set-default RO_SPEED_I 0.01
|
||||
param set-default RO_SPEED_P 0.1
|
||||
param set-default RO_SPEED_RED 0.5
|
||||
# Rover Velocity Control Parameters
|
||||
param set-default RO_SPEED_LIM 2
|
||||
param set-default RO_SPEED_I 0.5
|
||||
param set-default RO_SPEED_P 1
|
||||
param set-default RO_SPEED_RED 1
|
||||
|
||||
# Pure Pursuit parameters
|
||||
param set-default PP_LOOKAHD_GAIN 0.5
|
||||
@@ -55,24 +48,24 @@ param set-default PP_LOOKAHD_MIN 1
|
||||
param set-default SENS_EN_MAGSIM 1
|
||||
|
||||
# Actuator mapping
|
||||
param set-default SIM_GZ_WH_FUNC1 104 # left wheel back
|
||||
param set-default SIM_GZ_WH_FUNC1 102 # right wheel front
|
||||
param set-default SIM_GZ_WH_MIN1 70
|
||||
param set-default SIM_GZ_WH_MAX1 130
|
||||
param set-default SIM_GZ_WH_DIS1 100
|
||||
|
||||
param set-default SIM_GZ_WH_FUNC2 103 # right wheel back
|
||||
param set-default SIM_GZ_WH_FUNC2 101 # left wheel front
|
||||
param set-default SIM_GZ_WH_MIN2 70
|
||||
param set-default SIM_GZ_WH_MAX2 130
|
||||
param set-default SIM_GZ_WH_DIS2 100
|
||||
|
||||
param set-default SIM_GZ_WH_FUNC3 102 # left wheel front
|
||||
param set-default SIM_GZ_WH_FUNC3 104 # right wheel back
|
||||
param set-default SIM_GZ_WH_MIN3 70
|
||||
param set-default SIM_GZ_WH_MAX3 130
|
||||
param set-default SIM_GZ_WH_DIS3 100
|
||||
|
||||
param set-default SIM_GZ_WH_FUNC4 101 # right wheel front
|
||||
param set-default SIM_GZ_WH_FUNC4 103 # left wheel back
|
||||
param set-default SIM_GZ_WH_MIN4 70
|
||||
param set-default SIM_GZ_WH_MAX4 130
|
||||
param set-default SIM_GZ_WH_DIS4 100
|
||||
|
||||
param set-default SIM_GZ_WH_REV 0
|
||||
param set-default SIM_GZ_WH_REV 10
|
||||
@@ -19,6 +19,5 @@ param set-default MNT_MAN_PITCH 2
|
||||
param set-default MNT_MAN_YAW 3
|
||||
|
||||
param set-default MNT_RANGE_ROLL 180
|
||||
param set-default MNT_MAX_PITCH 45
|
||||
param set-default MNT_MIN_PITCH -135
|
||||
param set-default MNT_RANGE_PITCH 180
|
||||
param set-default MNT_RANGE_YAW 720
|
||||
|
||||
@@ -17,7 +17,6 @@ param set-default NAV_ACC_RAD 0.5
|
||||
param set-default RD_WHEEL_TRACK 0.6
|
||||
param set-default RD_TRANS_DRV_TRN 0.785398
|
||||
param set-default RD_TRANS_TRN_DRV 0.174533
|
||||
param set-default RD_YAW_STK_GAIN 0.6
|
||||
|
||||
# Rate Control Parameters
|
||||
param set-default RO_YAW_RATE_I 0.01
|
||||
@@ -26,8 +25,6 @@ param set-default RO_YAW_RATE_LIM 250
|
||||
param set-default RO_YAW_ACCEL_LIM 400
|
||||
param set-default RO_YAW_DECEL_LIM 800
|
||||
param set-default RO_YAW_RATE_CORR 1
|
||||
param set-default RO_YAW_EXPO 0.85
|
||||
param set-default RO_YAW_SUPEXPO 0.3
|
||||
|
||||
# Attitude Control Parameters
|
||||
param set-default RO_YAW_P 5
|
||||
|
||||
@@ -26,6 +26,7 @@ param set-default TRIG_INTERFACE 3
|
||||
param set-default TRIG_MODE 4
|
||||
param set-default MNT_MODE_IN 4
|
||||
param set-default MNT_MODE_OUT 2
|
||||
param set-default MAV_PROTO_VER 2
|
||||
|
||||
param set-default CA_AIRFRAME 0
|
||||
param set-default CA_ROTOR_COUNT 6
|
||||
|
||||
@@ -1,167 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# @name KTH-ATMOS
|
||||
#
|
||||
# @type Free-Flyer
|
||||
# @class Spacecraft
|
||||
#
|
||||
# @output Motor1 back left thruster, +x thrust
|
||||
# @output Motor2 front left thruster, -x thrust
|
||||
# @output Motor3 back right thruster, +x thrust
|
||||
# @output Motor4 front right thruster, -x thrust
|
||||
# @output Motor5 front left thruster, +y thrust
|
||||
# @output Motor6 front right thruster, -y thrust
|
||||
# @output Motor7 back left thruster, +y thrust
|
||||
# @output Motor8 back right thruster, -y thrust
|
||||
#
|
||||
# @maintainer discower-io
|
||||
# @url https://atmos.discower.io
|
||||
#
|
||||
|
||||
. ${R}etc/init.d/rc.sc_defaults
|
||||
|
||||
PX4_SIMULATOR=${PX4_SIMULATOR:=gz}
|
||||
PX4_GZ_WORLD=${PX4_GZ_WORLD:=default}
|
||||
PX4_SIM_MODEL=${PX4_SIM_MODEL:=atmos_dual}
|
||||
|
||||
param set-default SIM_GZ_EN 1
|
||||
|
||||
param set-default SENS_EN_MAGSIM 1
|
||||
param set-default COM_ARM_CHK_ESCS 0 # We don't have ESCs
|
||||
param set-default FD_ESCS_EN 0
|
||||
|
||||
param set-default CA_AIRFRAME 14
|
||||
param set-default MAV_TYPE 45
|
||||
|
||||
param set-default CA_ROTOR_COUNT 8
|
||||
param set-default CA_R_REV 0
|
||||
|
||||
# Auto to be provided by Custom Airframe
|
||||
param set-default CA_METHOD 0
|
||||
|
||||
# Set proper failsafes
|
||||
param set-default COM_ACT_FAIL_ACT 0
|
||||
param set-default COM_LOW_BAT_ACT 0
|
||||
param set-default NAV_DLL_ACT 0
|
||||
param set-default GF_ACTION 1
|
||||
param set-default NAV_RCL_ACT 1
|
||||
|
||||
# disable attitude failure detection
|
||||
param set-default FD_FAIL_P 0
|
||||
param set-default FD_FAIL_R 0
|
||||
|
||||
param set-default CA_ROTOR0_PX -0.12
|
||||
param set-default CA_ROTOR0_PY -0.12
|
||||
param set-default CA_ROTOR0_PZ 0.0
|
||||
param set-default CA_ROTOR0_CT 1.4
|
||||
param set-default CA_ROTOR0_AX 1.0
|
||||
param set-default CA_ROTOR0_AY 0.0
|
||||
param set-default CA_ROTOR0_AZ 0.0
|
||||
|
||||
param set-default CA_ROTOR1_PX 0.12
|
||||
param set-default CA_ROTOR1_PY -0.12
|
||||
param set-default CA_ROTOR1_PZ 0.0
|
||||
param set-default CA_ROTOR1_CT 1.4
|
||||
param set-default CA_ROTOR1_AX -1.0
|
||||
param set-default CA_ROTOR1_AY 0.0
|
||||
param set-default CA_ROTOR1_AZ 0.0
|
||||
|
||||
param set-default CA_ROTOR2_PX -0.12
|
||||
param set-default CA_ROTOR2_PY 0.12
|
||||
param set-default CA_ROTOR2_PZ 0.0
|
||||
param set-default CA_ROTOR2_CT 1.4
|
||||
param set-default CA_ROTOR2_AX 1.0
|
||||
param set-default CA_ROTOR2_AY 0.0
|
||||
param set-default CA_ROTOR2_AZ 0.0
|
||||
|
||||
param set-default CA_ROTOR3_PX 0.12
|
||||
param set-default CA_ROTOR3_PY 0.12
|
||||
param set-default CA_ROTOR3_PZ 0.0
|
||||
param set-default CA_ROTOR3_CT 1.4
|
||||
param set-default CA_ROTOR3_AX -1.0
|
||||
param set-default CA_ROTOR3_AY 0.0
|
||||
param set-default CA_ROTOR3_AZ 0.0
|
||||
|
||||
param set-default CA_ROTOR4_PX 0.12
|
||||
param set-default CA_ROTOR4_PY -0.12
|
||||
param set-default CA_ROTOR4_PZ 0.0
|
||||
param set-default CA_ROTOR4_CT 1.4
|
||||
param set-default CA_ROTOR4_AX 0.0
|
||||
param set-default CA_ROTOR4_AY 1.0
|
||||
param set-default CA_ROTOR4_AZ 0.0
|
||||
|
||||
param set-default CA_ROTOR5_PX 0.12
|
||||
param set-default CA_ROTOR5_PY 0.12
|
||||
param set-default CA_ROTOR5_PZ 0.0
|
||||
param set-default CA_ROTOR5_CT 1.4
|
||||
param set-default CA_ROTOR5_AX 0.0
|
||||
param set-default CA_ROTOR5_AY -1.0
|
||||
param set-default CA_ROTOR5_AZ 0.0
|
||||
|
||||
param set-default CA_ROTOR6_PX -0.12
|
||||
param set-default CA_ROTOR6_PY -0.12
|
||||
param set-default CA_ROTOR6_PZ 0.0
|
||||
param set-default CA_ROTOR6_CT 1.4
|
||||
param set-default CA_ROTOR6_AX 0.0
|
||||
param set-default CA_ROTOR6_AY 1.0
|
||||
param set-default CA_ROTOR6_AZ 0.0
|
||||
|
||||
param set-default CA_ROTOR7_PX -0.12
|
||||
param set-default CA_ROTOR7_PY 0.12
|
||||
param set-default CA_ROTOR7_PZ 0.0
|
||||
param set-default CA_ROTOR7_CT 1.4
|
||||
param set-default CA_ROTOR7_AX 0.0
|
||||
param set-default CA_ROTOR7_AY -1.0
|
||||
param set-default CA_ROTOR7_AZ 0.0
|
||||
|
||||
param set-default SIM_GZ_EC_FUNC1 101
|
||||
param set-default SIM_GZ_EC_FUNC2 102
|
||||
param set-default SIM_GZ_EC_FUNC3 103
|
||||
param set-default SIM_GZ_EC_FUNC4 104
|
||||
param set-default SIM_GZ_EC_FUNC5 105
|
||||
param set-default SIM_GZ_EC_FUNC6 106
|
||||
param set-default SIM_GZ_EC_FUNC7 107
|
||||
param set-default SIM_GZ_EC_FUNC8 108
|
||||
param set-default SIM_GZ_EC_FUNC9 301
|
||||
param set-default SIM_GZ_EC_FUNC10 302
|
||||
param set-default SIM_GZ_EC_FUNC11 303
|
||||
param set-default SIM_GZ_EC_FUNC12 304
|
||||
|
||||
param set-default SIM_GZ_EC_MIN1 0
|
||||
param set-default SIM_GZ_EC_MIN2 0
|
||||
param set-default SIM_GZ_EC_MIN3 0
|
||||
param set-default SIM_GZ_EC_MIN4 0
|
||||
param set-default SIM_GZ_EC_MIN5 0
|
||||
param set-default SIM_GZ_EC_MIN6 0
|
||||
param set-default SIM_GZ_EC_MIN7 0
|
||||
param set-default SIM_GZ_EC_MIN8 0
|
||||
param set-default SIM_GZ_EC_MIN9 1100
|
||||
param set-default SIM_GZ_EC_MIN10 1100
|
||||
param set-default SIM_GZ_EC_MIN11 1100
|
||||
param set-default SIM_GZ_EC_MIN12 1100
|
||||
|
||||
param set-default SIM_GZ_EC_MAX1 10000
|
||||
param set-default SIM_GZ_EC_MAX2 10000
|
||||
param set-default SIM_GZ_EC_MAX3 10000
|
||||
param set-default SIM_GZ_EC_MAX4 10000
|
||||
param set-default SIM_GZ_EC_MAX5 10000
|
||||
param set-default SIM_GZ_EC_MAX6 10000
|
||||
param set-default SIM_GZ_EC_MAX7 10000
|
||||
param set-default SIM_GZ_EC_MAX8 10000
|
||||
param set-default SIM_GZ_EC_MAX9 1900
|
||||
param set-default SIM_GZ_EC_MAX10 1900
|
||||
param set-default SIM_GZ_EC_MAX11 1900
|
||||
param set-default SIM_GZ_EC_MAX12 1900
|
||||
|
||||
# Controller Tunings
|
||||
param set SC_YAWRATE_P 3.335
|
||||
param set SC_YAWRATE_I 0.87
|
||||
param set SC_YAWRATE_D 0.15
|
||||
param set SC_YR_INT_LIM 0.2
|
||||
param set SC_YAW_P 3.0
|
||||
|
||||
param set SPC_POS_P 0.20
|
||||
param set SPC_VEL_P 6.55
|
||||
param set SPC_VEL_I 0.0
|
||||
param set SPC_VEL_D 0.0
|
||||
param set SPC_VEL_MAX 12.0
|
||||
@@ -80,8 +80,10 @@ px4_add_romfs_files(
|
||||
4009_gz_r1_rover
|
||||
4010_gz_x500_mono_cam
|
||||
4011_gz_lawnmower
|
||||
4012_gz_rover_ackermann
|
||||
4013_gz_x500_lidar_2d
|
||||
4014_gz_x500_mono_cam_down
|
||||
4015_gz_r1_rover_mecanum
|
||||
4016_gz_x500_lidar_down
|
||||
4017_gz_x500_lidar_front
|
||||
4018_gz_quadtailsitter
|
||||
@@ -112,13 +114,10 @@ px4_add_romfs_files(
|
||||
17002_flightgear_tf-g2
|
||||
|
||||
50000_gz_rover_differential
|
||||
51000_gz_rover_ackermann
|
||||
52000_gz_rover_mecanum
|
||||
|
||||
60002_gz_uuv_bluerov2_heavy
|
||||
|
||||
70000_gz_atmos
|
||||
70001_gz_atmos_dual
|
||||
|
||||
# [22000, 22999] Reserve for custom models
|
||||
)
|
||||
|
||||
@@ -159,19 +159,24 @@ if [ -n "${PX4_SIM_MODEL#*gz_}" ] && [ -z "${PX4_GZ_MODEL_NAME}" ]; then
|
||||
fi
|
||||
|
||||
# Set up camera to follow the model if requested
|
||||
if [ -z "${PX4_GZ_NO_FOLLOW}" ]; then
|
||||
if [ -n "${PX4_GZ_FOLLOW}" ]; then
|
||||
|
||||
echo "INFO [init] Setting camera to follow ${MODEL_NAME_INSTANCE}"
|
||||
|
||||
# Set camera to follow the model
|
||||
${gz_command} service -s "/gui/follow" --reqtype gz.msgs.StringMsg \
|
||||
--reptype gz.msgs.Boolean --timeout 5000 \
|
||||
--req "data: \"${MODEL_NAME_INSTANCE}\"" > /dev/null 2>&1
|
||||
|
||||
# Set default camera offset if not specified
|
||||
follow_x=${PX4_GZ_FOLLOW_OFFSET_X:--2.0}
|
||||
follow_y=${PX4_GZ_FOLLOW_OFFSET_Y:--2.0}
|
||||
follow_z=${PX4_GZ_FOLLOW_OFFSET_Z:-2.0}
|
||||
|
||||
# Set camera offset
|
||||
${gz_command} topic -t /gui/track -m gz.msgs.CameraTrack \
|
||||
-p "track_mode: FOLLOW, follow_target: {name: '${MODEL_NAME_INSTANCE}'},\
|
||||
follow_offset: {x: ${follow_x}, y: ${follow_y}, z: ${follow_z}}, follow_pgain: 1.0, track_pgain: 1.0"
|
||||
${gz_command} service -s "/gui/follow/offset" --reqtype gz.msgs.Vector3d \
|
||||
--reptype gz.msgs.Boolean --timeout 5000 \
|
||||
--req "x: ${follow_x}, y: ${follow_y}, z: ${follow_z}" > /dev/null 2>&1
|
||||
|
||||
echo "INFO [init] Camera follow offset set to ${follow_x}, ${follow_y}, ${follow_z}"
|
||||
fi
|
||||
|
||||
@@ -126,6 +126,15 @@ then
|
||||
set AUTOCNF yes
|
||||
fi
|
||||
|
||||
# Allow overriding parameters via env variables: export PX4_PARAM_{name}={value}
|
||||
env | while IFS='=' read -r line; do
|
||||
value=${line#*=}
|
||||
name=${line%%=*}
|
||||
case $name in
|
||||
"PX4_PARAM_"*) param set "${name#PX4_PARAM_}" "$value" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# multi-instance setup
|
||||
# shellcheck disable=SC2154
|
||||
param set MAV_SYS_ID $((px4_instance+1))
|
||||
@@ -164,6 +173,7 @@ param set-default COM_RC_IN_MODE 1
|
||||
param set-default EKF2_REQ_GPS_H 0.5
|
||||
|
||||
param set-default IMU_GYRO_FFT_EN 1
|
||||
param set-default MAV_PROTO_VER 2 # Ensures QGC does not drop the first few packets after a SITL restart due to MAVLINK 1 packets
|
||||
|
||||
param set-default -s MC_AT_EN 1
|
||||
|
||||
@@ -229,15 +239,6 @@ then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Allow overriding parameters via env variables: export PX4_PARAM_{name}={value}
|
||||
env | while IFS='=' read -r line; do
|
||||
value=${line#*=}
|
||||
name=${line%%=*}
|
||||
case $name in
|
||||
"PX4_PARAM_"*) param set "${name#PX4_PARAM_}" "$value" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
dataman start
|
||||
|
||||
# only start the simulator if not in replay mode, as both control the lockstep time
|
||||
|
||||
@@ -123,9 +123,3 @@ if(CONFIG_MODULES_TEMPERATURE_COMPENSATION)
|
||||
rc.thermal_cal
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CONFIG_DRIVERS_VTXTABLE)
|
||||
px4_add_romfs_files(
|
||||
rc.vtxtable
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
param set UAVCAN_ENABLE 0
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
param set-default CA_ROTOR0_PX 0.3
|
||||
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
#
|
||||
# @board px4_fmu-v2 exclude
|
||||
# @board bitcraze_crazyflie exclude
|
||||
# @board px4_fmu-v6x exclude
|
||||
# @board ark_fmu-v6x exclude
|
||||
#
|
||||
|
||||
. ${R}etc/init.d/rc.fw_defaults
|
||||
@@ -42,6 +40,8 @@ param set-default FW_P_LIM_MAX 25
|
||||
param set-default FW_P_LIM_MIN -5
|
||||
param set-default FW_P_RMAX_NEG 20
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
param set-default CA_ROTOR0_PX 0.3
|
||||
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
#
|
||||
# @board px4_fmu-v2 exclude
|
||||
# @board bitcraze_crazyflie exclude
|
||||
# @board px4_fmu-v6x exclude
|
||||
# @board ark_fmu-v6x exclude
|
||||
#
|
||||
|
||||
. ${R}etc/init.d/rc.fw_defaults
|
||||
@@ -39,6 +37,8 @@ param set-default FW_P_LIM_MAX 25
|
||||
param set-default FW_P_LIM_MIN -5
|
||||
param set-default FW_P_RMAX_NEG 20
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
param set-default CA_ROTOR0_PX 0.3
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
. ${R}etc/init.d/rc.fw_defaults
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
param set-default CA_ROTOR0_PX 0.3
|
||||
param set-default CA_SV_CS_COUNT 4
|
||||
|
||||
@@ -32,6 +32,7 @@ param set-default FW_WR_IMAX 0.8
|
||||
param set-default FW_WR_P 1
|
||||
param set-default FW_W_RMAX 0
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
param set-default CA_SV_CS_COUNT 7
|
||||
param set-default CA_SV_CS0_TRQ_R -0.5
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
. ${R}etc/init.d/rc.fw_defaults
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
|
||||
param set-default CA_ROTOR_COUNT 1
|
||||
param set-default CA_ROTOR0_PX 0.15
|
||||
param set-default CA_SV_CS_COUNT 2
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
#
|
||||
# @board px4_fmu-v2 exclude
|
||||
# @board bitcraze_crazyflie exclude
|
||||
# @board px4_fmu-v6x exclude
|
||||
# @board ark_fmu-v6x exclude
|
||||
#
|
||||
|
||||
. ${R}etc/init.d/rc.mc_defaults
|
||||
@@ -77,6 +75,9 @@ param set-default NAV_ACC_RAD 2
|
||||
param set-default RTL_DESCEND_ALT 5
|
||||
param set-default RTL_RETURN_ALT 5
|
||||
|
||||
# Logging Parameters
|
||||
param set-default SDLOG_PROFILE 131
|
||||
|
||||
# Sensors Parameters
|
||||
param set-default SENS_CM8JL65_CFG 104
|
||||
param set-default SENS_FLOW_MAXHGT 25
|
||||
|
||||
@@ -7,10 +7,6 @@
|
||||
#
|
||||
# @board px4_fmu-v2 exclude
|
||||
# @board px4_fmu-v5x exclude
|
||||
# @board auterion_fmu-v6s exclude
|
||||
# @board ark_fmu-v6x exclude
|
||||
# @board auterion_fmu-v6x exclude
|
||||
# @board px4_fmu-v6x exclude
|
||||
# @board bitcraze_crazyflie exclude
|
||||
#
|
||||
# @maintainer Iain Galloway <iain.galloway@nxp.com>
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#
|
||||
# @board px4_fmu-v2 exclude
|
||||
# @board bitcraze_crazyflie exclude
|
||||
# @board auterion_fmu-v6x exclude
|
||||
# @board px4_fmu-v6x exclude
|
||||
#
|
||||
|
||||
@@ -78,6 +77,9 @@ param set-default NAV_ACC_RAD 2
|
||||
param set-default RTL_DESCEND_ALT 5
|
||||
param set-default RTL_RETURN_ALT 5
|
||||
|
||||
# Logging Parameters
|
||||
param set-default SDLOG_PROFILE 131
|
||||
|
||||
# Sensors Parameters
|
||||
param set-default SENS_CM8JL65_CFG 202
|
||||
param set-default SENS_FLOW_MAXHGT 25
|
||||
|
||||
@@ -13,11 +13,6 @@
|
||||
# @board px4_fmu-v4pro exclude
|
||||
# @board px4_fmu-v5 exclude
|
||||
# @board px4_fmu-v5x exclude
|
||||
# @board auterion_fmu-v6s exclude
|
||||
# @board ark_fmu-v6x exclude
|
||||
# @board auterion_fmu-v6x exclude
|
||||
# @board px4_fmu-v6x exclude
|
||||
# @board px4_fmu-v6xrt exclude
|
||||
# @board bitcraze_crazyflie exclude
|
||||
#
|
||||
|
||||
|
||||
@@ -29,6 +29,9 @@ param set-default MPC_MAN_TILT_MAX 60
|
||||
|
||||
param set-default THR_MDL_FAC 0.3
|
||||
|
||||
# enable high-rate logging profile (helps with tuning)
|
||||
param set-default SDLOG_PROFILE 19
|
||||
|
||||
param set-default IMU_DGYRO_CUTOFF 50
|
||||
param set-default IMU_GYRO_CUTOFF 90
|
||||
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
#
|
||||
# @board px4_fmu-v2 exclude
|
||||
# @board bitcraze_crazyflie exclude
|
||||
# @board px4_fmu-v6x exclude
|
||||
# @board ark_fmu-v6x exclude
|
||||
#
|
||||
|
||||
. ${R}etc/init.d/rc.mc_defaults
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
#
|
||||
# @board px4_fmu-v2 exclude
|
||||
# @board bitcraze_crazyflie exclude
|
||||
# @board px4_fmu-v6x exclude
|
||||
# @board ark_fmu-v6x exclude
|
||||
#
|
||||
|
||||
. ${R}etc/init.d/rc.mc_defaults
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
# @board cuav_x7pro exclude
|
||||
# @board px4_fmu-v4pro exclude
|
||||
# @board px4_fmu-v5x exclude
|
||||
# @board auterion_fmu-v6x exclude
|
||||
# @board px4_fmu-v6x exclude
|
||||
#
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
# @board px4_fmu-v4pro exclude
|
||||
# @board px4_fmu-v5 exclude
|
||||
# @board px4_fmu-v5x exclude
|
||||
# @board auterion_fmu-v6x exclude
|
||||
# @board px4_fmu-v6x exclude
|
||||
# @board bitcraze_crazyflie exclude
|
||||
# @board cuav_x7pro exclude
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
# @board px4_fmu-v4pro exclude
|
||||
# @board px4_fmu-v5 exclude
|
||||
# @board px4_fmu-v5x exclude
|
||||
# @board auterion_fmu-v6x exclude
|
||||
# @board px4_fmu-v6x exclude
|
||||
# @board bitcraze_crazyflie exclude
|
||||
# @board cuav_x7pro exclude
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
# @board px4_fmu-v4pro exclude
|
||||
# @board px4_fmu-v5 exclude
|
||||
# @board px4_fmu-v5x exclude
|
||||
# @board auterion_fmu-v6x exclude
|
||||
# @board px4_fmu-v6x exclude
|
||||
# @board bitcraze_crazyflie exclude
|
||||
# @board diatone_mamba-f405-mk2 exclude
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
# @board px4_fmu-v4pro exclude
|
||||
# @board px4_fmu-v5 exclude
|
||||
# @board px4_fmu-v5x exclude
|
||||
# @board auterion_fmu-v6x exclude
|
||||
# @board px4_fmu-v6x exclude
|
||||
# @board diatone_mamba-f405-mk2 exclude
|
||||
#
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# @name NXP B3RB Rover Ackermann
|
||||
#
|
||||
# @type Rover
|
||||
# @class Rover
|
||||
#
|
||||
# @board px4_fmu-v2 exclude
|
||||
# @board bitcraze_crazyflie exclude
|
||||
#
|
||||
|
||||
. ${R}etc/init.d/rc.rover_ackermann_defaults
|
||||
|
||||
param set-default BAT1_N_CELLS 3
|
||||
|
||||
# Set geometry & output configration
|
||||
param set-default PWM_MAIN_FUNC1 201
|
||||
param set-default PWM_MAIN_FUNC2 101
|
||||
param set-default PWM_MAIN_FUNC3 101
|
||||
param set-default PWM_MAIN_DIS1 1500
|
||||
param set-default PWM_MAIN_DIS2 0
|
||||
param set-default PWM_MAIN_DIS3 1500
|
||||
param set-default PWM_MAIN_MIN1 1000
|
||||
param set-default PWM_MAIN_MIN2 2500
|
||||
param set-default PWM_MAIN_MIN3 0
|
||||
param set-default PWM_MAIN_MAX1 2000
|
||||
param set-default PWM_MAIN_MAX2 2500
|
||||
param set-default PWM_MAIN_MAX3 50
|
||||
param set-default PWM_MAIN_TIM0 400
|
||||
param set-default PWM_MAIN_TIM1 400
|
||||
param set-default PWM_MAIN_TIM2 20000
|
||||
@@ -12,9 +12,7 @@
|
||||
# @board px4_fmu-v4pro exclude
|
||||
# @board px4_fmu-v5 exclude
|
||||
# @board px4_fmu-v5x exclude
|
||||
# @board px4_fmu-v6x exclude
|
||||
# @board bitcraze_crazyflie exclude
|
||||
# @board ark_fmu-v6x exclude
|
||||
#
|
||||
|
||||
. ${R}etc/init.d/rc.mc_defaults
|
||||
|
||||
@@ -20,9 +20,6 @@
|
||||
|
||||
. ${R}etc/init.d/rc.sc_defaults
|
||||
|
||||
# Overwrite DDS AG IP to `192.168.0.1`
|
||||
param set-default UXRCE_DDS_AG_IP -1062731775
|
||||
|
||||
param set-default CA_AIRFRAME 14
|
||||
param set-default MAV_TYPE 45
|
||||
|
||||
|
||||
@@ -153,7 +153,6 @@ if(CONFIG_MODULES_ROVER_ACKERMANN)
|
||||
# [51000, 51999] Ackermann rovers
|
||||
51000_generic_rover_ackermann
|
||||
51001_axial_scx10_2_trail_honcho
|
||||
51002_nxp_b3rb
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -10,8 +10,6 @@ set VEHICLE_TYPE fw
|
||||
# MAV_TYPE_FIXED_WING 1
|
||||
param set-default MAV_TYPE 1
|
||||
|
||||
param set-default CA_AIRFRAME 1
|
||||
|
||||
#
|
||||
# Default parameters for fixed wing UAVs.
|
||||
#
|
||||
@@ -28,7 +26,6 @@ param set-default EKF2_MAG_ACCLIM 0
|
||||
param set-default EKF2_REQ_EPH 10
|
||||
param set-default EKF2_REQ_EPV 10
|
||||
param set-default EKF2_REQ_HDRIFT 0.5
|
||||
param set-default EKF2_REQ_PDOP 4
|
||||
param set-default EKF2_REQ_SACC 1
|
||||
param set-default EKF2_REQ_VDRIFT 1
|
||||
param set-default EKF2_RNG_QLTY_T 3
|
||||
|
||||
@@ -41,9 +41,3 @@ if param compare -s MC_NN_EN 1
|
||||
then
|
||||
mc_nn_control start
|
||||
fi
|
||||
|
||||
|
||||
if param compare -s MC_RAPTOR_ENABLE 1
|
||||
then
|
||||
mc_raptor start
|
||||
fi
|
||||
|
||||
@@ -8,6 +8,9 @@ set VEHICLE_TYPE spacecraft
|
||||
# MAV_TYPE_SPACECRAFT_ORBITTER
|
||||
param set-default MAV_TYPE 45
|
||||
|
||||
# Set micro-dds-client to use ethernet and IP-address 192.168.0.1
|
||||
param set-default UXRCE_DDS_AG_IP -1062731775
|
||||
|
||||
# Disable preflight disarm to not interfere with external launching
|
||||
param set-default COM_DISARM_PRFLT -1
|
||||
param set-default CBRK_SUPPLY_CHK 894281
|
||||
|
||||
@@ -154,12 +154,6 @@ then
|
||||
fi
|
||||
fi
|
||||
|
||||
# Microchip MCP9808 temperature sensor external I2C
|
||||
if param compare -s SENS_EN_MCP9808 1
|
||||
then
|
||||
mcp9808 start -X
|
||||
fi
|
||||
|
||||
# TE MS4515 differential pressure sensor external I2C
|
||||
if param compare -s SENS_EN_MS4515 1
|
||||
then
|
||||
@@ -225,24 +219,6 @@ then
|
||||
pcf8583 start -X -a 0x51
|
||||
fi
|
||||
|
||||
# ADC sensor ADS7953 external SPI
|
||||
if param compare -s ADC_ADS7953_EN 1
|
||||
then
|
||||
ads7953 start -S
|
||||
fi
|
||||
|
||||
# ADC sensor tla2528 external I2C
|
||||
if param compare -s ADC_TLA2528_EN 1
|
||||
then
|
||||
tla2528 start -X
|
||||
fi
|
||||
|
||||
# Start TMP102 temperature sensor
|
||||
if param compare SENS_EN_TMP102 1
|
||||
then
|
||||
tmp102 start -X
|
||||
fi
|
||||
|
||||
# probe for optional external I2C devices
|
||||
if param compare SENS_EXT_I2C_PRB 1
|
||||
then
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# VTX table loading script.
|
||||
#
|
||||
# NOTE: Script variables are declared/initialized/unset in the rcS script.
|
||||
#
|
||||
|
||||
vtxtable load
|
||||
@@ -228,26 +228,30 @@ else
|
||||
fi
|
||||
unset BOARD_RC_ADDITIONAL_INIT
|
||||
|
||||
# Load airframe configuration based on SYS_AUTOSTART parameter if successful VEHICLE_TYPE gets set
|
||||
# Run autogenerated ROMFS airframe script
|
||||
. ${R}etc/init.d/rc.autostart
|
||||
|
||||
if [ ${VEHICLE_TYPE} = none ]
|
||||
# Load airframe configuration based on SYS_AUTOSTART parameter
|
||||
if ! param compare SYS_AUTOSTART 0
|
||||
then
|
||||
# Run external airframe script on SD card
|
||||
if [ $STORAGE_AVAILABLE = yes ]
|
||||
# rc.autostart directly run the right airframe script which sets the VEHICLE_TYPE
|
||||
# Look for airframe in ROMFS
|
||||
. ${R}etc/init.d/rc.autostart
|
||||
|
||||
if [ ${VEHICLE_TYPE} = none ]
|
||||
then
|
||||
. ${R}etc/init.d/rc.autostart_ext
|
||||
else
|
||||
echo "ERROR [init] SD not mounted, skipping external airframe"
|
||||
# Use external startup file
|
||||
if [ $STORAGE_AVAILABLE = yes ]
|
||||
then
|
||||
. ${R}etc/init.d/rc.autostart_ext
|
||||
else
|
||||
echo "ERROR [init] SD card not mounted - can't load external airframe"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ${VEHICLE_TYPE} = none ]
|
||||
then
|
||||
echo "ERROR [init] No airframe file found for SYS_AUTOSTART value"
|
||||
param set SYS_AUTOSTART 0
|
||||
tune_control play error
|
||||
if [ ${VEHICLE_TYPE} = none ]
|
||||
then
|
||||
echo "ERROR [init] No airframe file found for SYS_AUTOSTART value"
|
||||
param set SYS_AUTOSTART 0
|
||||
tune_control play error
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check parameter version and reset upon airframe configuration version mismatch.
|
||||
@@ -479,19 +483,6 @@ else
|
||||
pwm_out start
|
||||
fi
|
||||
|
||||
#
|
||||
# Optional UAVCAN/DroneCAN or Cyphal
|
||||
#
|
||||
if param greater -s UAVCAN_ENABLE 0
|
||||
then
|
||||
uavcan start
|
||||
else
|
||||
if param greater -s CYPHAL_ENABLE 0
|
||||
then
|
||||
cyphal start
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# Configure vehicle type specific parameters.
|
||||
# Note: rc.vehicle_setup is the entry point for all vehicle type specific setup.
|
||||
@@ -520,11 +511,6 @@ else
|
||||
#
|
||||
. ${R}etc/init.d/rc.serial
|
||||
|
||||
if param greater -s ZENOH_ENABLE 0
|
||||
then
|
||||
zenoh start
|
||||
fi
|
||||
|
||||
# Must be started after the serial config is read
|
||||
rc_input start $RC_INPUT_ARGS
|
||||
|
||||
@@ -630,16 +616,6 @@ else
|
||||
fi
|
||||
unset RC_LOGGING
|
||||
|
||||
#
|
||||
# Start the VTX services.
|
||||
#
|
||||
set RC_VTXTABLE ${R}etc/init.d/rc.vtxtable
|
||||
if [ -f ${RC_VTXTABLE} ]
|
||||
then
|
||||
. ${RC_VTXTABLE}
|
||||
fi
|
||||
unset RC_VTXTABLE
|
||||
|
||||
#
|
||||
# Set additional parameters and env variables for selected AUTOSTART.
|
||||
#
|
||||
@@ -656,6 +632,27 @@ else
|
||||
fi
|
||||
unset BOARD_BOOTLOADER_UPGRADE
|
||||
|
||||
#
|
||||
# Check if UAVCAN is enabled, default to it for ESCs.
|
||||
#
|
||||
if param greater -s UAVCAN_ENABLE 0
|
||||
then
|
||||
# Start core UAVCAN module.
|
||||
if ! uavcan start
|
||||
then
|
||||
tune_control play error
|
||||
fi
|
||||
else
|
||||
if param greater -s CYPHAL_ENABLE 0
|
||||
then
|
||||
cyphal start
|
||||
fi
|
||||
fi
|
||||
if param greater -s ZENOH_ENABLE 0
|
||||
then
|
||||
zenoh start
|
||||
fi
|
||||
|
||||
#
|
||||
# End of autostart.
|
||||
#
|
||||
|
||||
@@ -15,4 +15,4 @@ ignore-exclude-errors-x
|
||||
lineend=linux
|
||||
exclude=EASTL
|
||||
add-brackets
|
||||
max-code-length=140
|
||||
max-code-length=120
|
||||
|
||||
@@ -21,13 +21,11 @@ exec find boards msg src platforms test \
|
||||
-path src/lib/crypto/monocypher -prune -o \
|
||||
-path src/lib/events/libevents -prune -o \
|
||||
-path src/lib/parameters/uthash -prune -o \
|
||||
-path src/lib/rl_tools/rl_tools -prune -o \
|
||||
-path src/lib/wind_estimator/python/generated -prune -o \
|
||||
-path src/modules/ekf2/EKF/python/ekf_derivation/generated -prune -o \
|
||||
-path src/modules/ekf2/EKF/yaw_estimator/derivation/generated -prune -o \
|
||||
-path src/modules/gyro_fft/CMSIS_5 -prune -o \
|
||||
-path src/modules/mavlink/mavlink -prune -o \
|
||||
-path src/modules/mc_raptor/blob -prune -o \
|
||||
-path test/fuzztest -prune -o \
|
||||
-path test/mavsdk_tests/catch2 -prune -o \
|
||||
-path src/lib/crypto/monocypher -prune -o \
|
||||
|
||||
@@ -7,7 +7,6 @@ fi
|
||||
|
||||
ssh_port=22
|
||||
ssh_user=root
|
||||
ssh_opts="-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
||||
|
||||
while getopts ":f:c:d:p:u:r" opt; do
|
||||
case ${opt} in
|
||||
@@ -68,7 +67,7 @@ target_file_name="update-dev.tar"
|
||||
if [ "$revert" == true ]; then
|
||||
# revert to the release version which was originally deployed
|
||||
cmd="cp $target_dir/update.tar $target_dir/$target_file_name"
|
||||
ssh $ssh_opts -t -p $ssh_port $ssh_user@$device "$cmd"
|
||||
ssh -t -p $ssh_port $ssh_user@$device "$cmd"
|
||||
else
|
||||
# create custom update-dev.tar
|
||||
tmp_dir="$(mktemp -d)"
|
||||
@@ -106,11 +105,11 @@ else
|
||||
$tar_name -C "$tmp_dir" --sort=name --owner=root:0 --group=root:0 --mtime='2019-01-01 00:00:00' -cvf $target_file_name $firmware_path $config_path
|
||||
|
||||
# send it to the target to start flashing
|
||||
scp $ssh_opts -P $ssh_port "$target_file_name" $ssh_user@"$device":$target_dir
|
||||
scp -P $ssh_port "$target_file_name" $ssh_user@"$device":$target_dir
|
||||
popd &>/dev/null
|
||||
rm -rf "$tmp_dir"
|
||||
fi
|
||||
|
||||
# grab status output for flashing progress
|
||||
cmd="tail --follow=name $target_dir/update_status 2>/dev/null || true"
|
||||
ssh $ssh_opts -t -p $ssh_port $ssh_user@$device "$cmd"
|
||||
ssh -t -p $ssh_port $ssh_user@$device "$cmd"
|
||||
|
||||
@@ -17,12 +17,37 @@ if [[ -f $1"/.git" || -d $1"/.git" ]]; then
|
||||
SUBMODULE_STATUS=$(git submodule summary "$1")
|
||||
STATUSRETVAL=$(echo $SUBMODULE_STATUS | grep -A20 -i "$1")
|
||||
if ! [[ -z "$STATUSRETVAL" ]]; then
|
||||
echo -e "\033[33mWarning: $1 submodule has uncommitted changes:\033[0m"
|
||||
echo -e "\033[31mChecked $1 submodule, ACTION REQUIRED:\033[0m"
|
||||
echo ""
|
||||
echo -e "Different commits:"
|
||||
echo -e "$SUBMODULE_STATUS"
|
||||
echo ""
|
||||
echo -e "To update submodules to the expected version, run:"
|
||||
echo -e " \033[94mgit submodule sync --recursive && git submodule update --init --recursive\033[0m"
|
||||
echo ""
|
||||
echo -e " *******************************************************************************"
|
||||
echo -e " * \033[31mIF YOU DID NOT CHANGE THIS FILE (OR YOU DON'T KNOW WHAT A SUBMODULE IS):\033[0m *"
|
||||
echo -e " * \033[31mHit 'u' and <ENTER> to update ALL submodules and resolve this.\033[0m *"
|
||||
echo -e " * (performs \033[94mgit submodule sync --recursive\033[0m *"
|
||||
echo -e " * and \033[94mgit submodule update --init --recursive\033[0m ) *"
|
||||
echo -e " *******************************************************************************"
|
||||
echo ""
|
||||
echo ""
|
||||
echo -e " Only for EXPERTS:"
|
||||
echo -e " $1 submodule is not in the recommended version."
|
||||
echo -e " Hit 'y' and <ENTER> to continue the build with this version. Hit <ENTER> to resolve manually."
|
||||
echo -e " Use \033[94mgit add $1 && git commit -m 'Updated $1'\033[0m to choose this version (careful!)"
|
||||
echo ""
|
||||
read user_cmd
|
||||
if [ "$user_cmd" == "y" ]; then
|
||||
echo "Continuing build with manually overridden submodule.."
|
||||
elif [ "$user_cmd" == "u" ]; then
|
||||
git submodule sync --recursive -- $1
|
||||
git submodule update --init --recursive -- $1 || true
|
||||
git submodule update --init --recursive --force -- $1
|
||||
echo "Submodule fixed, continuing build.."
|
||||
else
|
||||
echo "Build aborted."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
git submodule --quiet sync --recursive --quiet -- $1
|
||||
|
||||
@@ -25,15 +25,15 @@ parser.add_argument('-p', '--pretty', dest='pretty', action='store_true',
|
||||
help='Pretty output instead of a single line')
|
||||
parser.add_argument('-g', '--groups', dest='group', action='store_true',
|
||||
help='Groups targets')
|
||||
parser.add_argument('-f', '--filter', dest='filter', help='comma separated list of build target name prefixes to include instead of all e.g. "px4_fmu-v5_"')
|
||||
parser.add_argument('-f', '--filter', dest='filter', help='comma separated list of board names to use instead of all')
|
||||
|
||||
args = parser.parse_args()
|
||||
verbose = args.verbose
|
||||
|
||||
target_filter = []
|
||||
board_filter = []
|
||||
if args.filter:
|
||||
for target in args.filter.split(','):
|
||||
target_filter.append(target)
|
||||
for board in args.filter.split(','):
|
||||
board_filter.append(board)
|
||||
|
||||
default_container = 'ghcr.io/px4/px4-dev:v1.16.0-rc1-258-g0369abd556'
|
||||
build_configs = []
|
||||
@@ -144,7 +144,7 @@ for manufacturer in os.scandir(os.path.join(source_dir, '../boards')):
|
||||
label = files.name[:-9]
|
||||
target_name = manufacturer.name + '_' + board.name + '_' + label
|
||||
|
||||
if target_filter and not any(target_name.startswith(f) for f in target_filter):
|
||||
if board_filter and not board_name in board_filter:
|
||||
if verbose: print(f'excluding board {board_name} ({target_name})')
|
||||
continue
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ def main():
|
||||
cur_history_index = len(command_history)
|
||||
mav_serialport.write(cur_line+'\n')
|
||||
cur_line = ''
|
||||
elif ord(ch) == 8: # backspace
|
||||
elif ord(ch) == 127: # backslash
|
||||
if len(cur_line) > 0:
|
||||
erase_last_n_chars(1)
|
||||
cur_line = cur_line[:-1]
|
||||
|
||||
@@ -238,7 +238,6 @@ def get_actuator_output(yaml_config, output_functions, timer_config_file, verbos
|
||||
( 'disarmed', 'Disarmed', 'DIS', False ),
|
||||
( 'min', 'Minimum', 'MIN', False ),
|
||||
( 'max', 'Maximum', 'MAX', False ),
|
||||
( 'center', 'Center\n(for Servos)', 'CENT', False ),
|
||||
( 'failsafe', 'Failsafe', 'FAIL', True ),
|
||||
]
|
||||
for key, label, param_suffix, advanced in standard_params_array:
|
||||
|
||||
@@ -284,9 +284,6 @@ Note that non-motor outputs might already be active in prearm state if COM_PREAR
|
||||
'''
|
||||
minimum_description = \
|
||||
'''Minimum output value (when not disarmed).
|
||||
'''
|
||||
center_description = \
|
||||
'''Servo Center output value (when not disarmed).
|
||||
'''
|
||||
maximum_description = \
|
||||
'''Maxmimum output value (when not disarmed).
|
||||
@@ -299,7 +296,6 @@ When set to -1 (default), the value depends on the function (see {:}).
|
||||
standard_params_array = [
|
||||
( 'disarmed', 'Disarmed', 'DIS', disarmed_description ),
|
||||
( 'min', 'Minimum', 'MIN', minimum_description ),
|
||||
( 'center', 'Center', 'CENT', center_description ),
|
||||
( 'max', 'Maximum', 'MAX', maximum_description ),
|
||||
( 'failsafe', 'Failsafe', 'FAIL', failsafe_description ),
|
||||
]
|
||||
@@ -316,10 +312,6 @@ When set to -1 (default), the value depends on the function (see {:}).
|
||||
standard_params[key]['default'] = -1
|
||||
standard_params[key]['min'] = -1
|
||||
|
||||
if key == 'center':
|
||||
standard_params[key]['default'] = -1
|
||||
standard_params[key]['min'] = -1
|
||||
|
||||
param = {
|
||||
'description': {
|
||||
'short': channel_label+' ${i} '+label+' Value',
|
||||
|
||||
+58
-822
@@ -8,803 +8,6 @@ Also generates docs/en/middleware/dds_topics.md from dds_topics.yaml
|
||||
import os
|
||||
import argparse
|
||||
import sys
|
||||
import re
|
||||
|
||||
VALID_FIELDS = { #Note, also have to add the message types as those can be fields
|
||||
'uint64',
|
||||
'uint16',
|
||||
'uint8',
|
||||
'uint32'
|
||||
}
|
||||
|
||||
ALLOWED_UNITS = set(["m", "m/s", "m/s^2", "(m/s)^2", "deg", "deg/s", "rad", "rad/s", "rad^2", "rpm" ,"V", "A", "mA", "mAh", "W", "dBm", "h", "s", "ms", "us", "Ohm", "MB", "Kb/s", "degC","Pa","%","-"])
|
||||
invalid_units = set()
|
||||
ALLOWED_FRAMES = set(["NED","Body"])
|
||||
ALLOWED_INVALID_VALUES = set(["NaN", "0"])
|
||||
ALLOWED_CONSTANTS_NOT_IN_ENUM = set(["ORB_QUEUE_LENGTH","MESSAGE_VERSION"])
|
||||
|
||||
class Error:
|
||||
def __init__(self, type, message, linenumber=None, issueString = None, field = None):
|
||||
self.type = type
|
||||
self.message = message
|
||||
self.linenumber = linenumber
|
||||
self.issueString = issueString
|
||||
self.field = field
|
||||
|
||||
def display_error(self):
|
||||
#print(f"Debug: Error: display_error")
|
||||
|
||||
|
||||
if 'trailing_whitespace' == self.type:
|
||||
if self.issueString.strip():
|
||||
print(f"NOTE: Line has trailing whitespace ({self.message}: {self.linenumber}): {self.issueString}")
|
||||
else:
|
||||
print(f"NOTE: Line has trailing whitespace ({self.message}: {self.linenumber})")
|
||||
elif 'leading_whitespace_field_or_constant' == self.type:
|
||||
print(f"NOTE: Whitespace before field or constant ({self.message}: {self.linenumber}): {self.issueString}")
|
||||
elif 'field_or_constant_has_multiple_whitepsace' == self.type:
|
||||
print(f"NOTE: Field/constant has more than one sequential whitespace character ({self.message}: {self.linenumber}): {self.issueString}")
|
||||
elif 'empty_start_line' == self.type:
|
||||
print(f"NOTE: Empty line at start of file ({self.message}: {self.linenumber})")
|
||||
elif 'internal_comment' == self.type:
|
||||
print(f"NOTE: Internal Comment ({self.message}: {self.linenumber})\n {self.issueString}")
|
||||
elif 'internal_comment_empty' == self.type:
|
||||
print(f"NOTE: Empty Internal Comment ({self.message}: {self.linenumber})")
|
||||
elif 'summary_missing' == self.type:
|
||||
print(f"WARNING: No message description ({self.message})")
|
||||
elif 'topic_error' == self.type:
|
||||
print(f"NOTE: TOPIC ISSUE: {self.issueString}")
|
||||
elif 'unknown_unit' == self.type:
|
||||
print(f"WARNING: Unknown Unit: [{self.issueString}] on `{self.field}` ({self.message}: {self.linenumber})")
|
||||
elif 'constant_not_in_assigned_enum' == self.type:
|
||||
print(f"WARNING: `{self.issueString}` constant: Prefix not in `@enum` field metadata ({self.message}: {self.linenumber})")
|
||||
elif 'unknown_invalid_value' == self.type:
|
||||
print(f"WARNING: Unknown @invalid value: [{self.issueString}] on `{self.field}` ({self.message}: {self.linenumber})")
|
||||
elif 'unknown_frame' == self.type:
|
||||
print(f"WARNING: Unknown @frame: [{self.issueString}] on `{self.field}` ({self.message}: {self.linenumber})")
|
||||
elif 'command_no_params_pipes' == self.type:
|
||||
print(f"WARNING: `{self.field}` command has no parameters (pipes): [{self.issueString}] ({self.message}: {self.linenumber})")
|
||||
elif 'command_missing_params' == self.type:
|
||||
print(f"WARNING: `{self.field}` command missing params - should be 7 params surrounded by 8 pipes: [{self.issueString}] ({self.message}: {self.linenumber})")
|
||||
elif 'command_too_many_params' == self.type:
|
||||
print(f"WARNING: `{self.field}` command too many params (should be 7). Extras: [{self.issueString}] ({self.message}: {self.linenumber})")
|
||||
|
||||
|
||||
else:
|
||||
self.display_info()
|
||||
|
||||
def display_info(self):
|
||||
"""
|
||||
Display info about an error.
|
||||
Used as a fallback if error does not have specific printout in display_error()
|
||||
"""
|
||||
#print(f"Debug: Error: display_info")
|
||||
print(f" type: {self.type}, message: {self.message}, linenumber: {self.linenumber}, issueString: {self.issueString}, field: {self.field}")
|
||||
|
||||
class Enum:
|
||||
def __init__(self, name, parentMessage):
|
||||
self.name = name
|
||||
self.parent = parentMessage
|
||||
self.enumValues = dict()
|
||||
|
||||
def display_info(self):
|
||||
"""
|
||||
Display info about an enum
|
||||
"""
|
||||
print(f"Debug: Enum: display_info")
|
||||
print(f" name: {self.name}")
|
||||
for key, value in self.enumValues.items():
|
||||
value.display_info()
|
||||
|
||||
class ConstantValue:
|
||||
def __init__(self, name, type, value, comment, line_number):
|
||||
self.name = name.strip()
|
||||
self.type = type.strip()
|
||||
self.value = value.strip()
|
||||
self.comment = comment
|
||||
self.line_number = line_number
|
||||
|
||||
if not self.value:
|
||||
print(f"Debug WARNING: NO VALUE in ConstantValue: {self.name}") ## TODO make into ERROR
|
||||
exit()
|
||||
|
||||
# TODO if value or name are empty, error
|
||||
|
||||
def display_info(self):
|
||||
print(f"Debug: ConstantValue: display_info")
|
||||
print(f" name: {self.name}, type: {self.type}, value: {self.value}, comment: {self.comment}, line: {self.line_number}")
|
||||
|
||||
|
||||
class CommandParam:
|
||||
"""
|
||||
Represents an individual param in a command constant
|
||||
Encapsulates parsing of the param to extract units etc.
|
||||
"""
|
||||
|
||||
def __init__(self, num, paramText, line_number, parentCommand):
|
||||
self.paramNum = num
|
||||
self.paramText = paramText.strip()
|
||||
self.enum = None
|
||||
self.range = None
|
||||
#self.type = type
|
||||
self.units = []
|
||||
self.enums = []
|
||||
self.minValue = None
|
||||
self.maxValue = None
|
||||
self.invalidValue = None
|
||||
self.frameValue = None
|
||||
self.lineNumber = line_number
|
||||
self.parent = parentCommand
|
||||
self.parentMessage = self.parent.parent
|
||||
|
||||
match = None
|
||||
if self.paramText:
|
||||
match = re.match(r'^((?:\[[^\]]*\]\s*)+)(.*)$', paramText)
|
||||
self.description = paramText
|
||||
bracketed_part = None
|
||||
if match:
|
||||
bracketed_part = match.group(1).strip() # .strip() removes trailing whitespace from the bracketed part
|
||||
self.description = match.group(2).strip()
|
||||
if bracketed_part:
|
||||
# get units
|
||||
bracket_content_matches = re.findall(r'\[(.*?)\]', bracketed_part)
|
||||
#print(f"DEBUG: bracket_content_matches: {bracket_content_matches}")
|
||||
for item in bracket_content_matches:
|
||||
item = item.strip()
|
||||
if item.startswith('@'): # Not a unit:
|
||||
if item.startswith('@enum'):
|
||||
item = item.split(" ")
|
||||
enum = item[1].strip()
|
||||
if enum and enum not in self.enums:
|
||||
self.enums.append(enum)
|
||||
|
||||
# Create parent enum objects for any enums created in this step
|
||||
for enumName in self.enums:
|
||||
if not enumName in self.parentMessage.enums:
|
||||
self.parentMessage.enums[enumName]=Enum(enumName,self.parentMessage)
|
||||
|
||||
elif item.startswith('@range'):
|
||||
item = item[6:].strip().split(",")
|
||||
self.range = item
|
||||
self.minValue = item[0].strip()
|
||||
self.maxValue = item[1].strip()
|
||||
elif item.startswith('@invalid'):
|
||||
self.invalidValue = item[8:].strip()
|
||||
#TODO: Do we require a description? (not currently)
|
||||
if self.invalidValue.split(" ")[0] not in ALLOWED_INVALID_VALUES:
|
||||
print(f"TODO: Command param do not support @invalid: {self.invalidValue}")
|
||||
"""
|
||||
error = Error("unknown_invalid_value", self.parent.filename, self.lineNumber, self.invalidValue, self.name)
|
||||
#error.display_error()
|
||||
if not "unknown_invalid_value" in self.parent.errors:
|
||||
self.parent.errors["unknown_invalid_value"] = []
|
||||
self.parent.errors["unknown_invalid_value"].append(error)
|
||||
"""
|
||||
|
||||
elif item.startswith('@frame'):
|
||||
self.frameValue = item[6:].strip()
|
||||
print(f"TODO: Command param do not support @frame: {self.frameValue}")
|
||||
"""
|
||||
if self.frameValue not in ALLOWED_FRAMES:
|
||||
error = Error("unknown_frame", self.parent.filename, self.lineNumber, self.frameValue, self.name)
|
||||
#error.display_error()
|
||||
if not "unknown_frame" in self.parent.errors:
|
||||
self.parent.errors["unknown_frame"] = []
|
||||
self.parent.errors["unknown_frame"].append(error)
|
||||
"""
|
||||
else:
|
||||
print(f"WARNING: Unhandled metadata in message comment: {item}")
|
||||
# TODO - report errors for different kinds of metadata
|
||||
exit()
|
||||
|
||||
else: # bracket is a unit
|
||||
unit = item.strip()
|
||||
|
||||
if item == "-":
|
||||
unit = ""
|
||||
|
||||
if unit and unit not in self.units:
|
||||
self.units.append(unit)
|
||||
|
||||
if unit not in ALLOWED_UNITS:
|
||||
invalid_units.add(unit)
|
||||
error = Error("unknown_unit", self.parentMessage.filename, self.lineNumber, unit, self.parent.name)
|
||||
#error.display_error()
|
||||
if not "unknown_unit" in self.parentMessage.errors:
|
||||
self.parentMessage.errors["unknown_unit"] = []
|
||||
self.parentMessage.errors["unknown_unit"].append(error)
|
||||
|
||||
|
||||
def display_info(self):
|
||||
print(f"Debug: CommandParam: display_info")
|
||||
print(f" id: {self.paramNum}")
|
||||
print(f" paramText: {self.paramText}\n unit: {self.units}\n enums: {self.enums}\n lineNumber: {self.lineNumber}\n range: {self.range}\n minValue: {self.minValue}\n maxValue: {self.maxValue}\n invalidValue: {self.invalidValue}\n frameValue: {self.frameValue}\n parent: {self.parent}\n ")
|
||||
|
||||
|
||||
|
||||
class CommandConstant:
|
||||
"""
|
||||
Represents a constant that is a command definition.
|
||||
Encapsulates parsing of the command format.
|
||||
The individual params are further parsed in CommandParam
|
||||
"""
|
||||
def __init__(self, name, type, value, comment, line_number, parentMessage):
|
||||
self.name = name.strip()
|
||||
self.type = type.strip()
|
||||
self.value = value.strip()
|
||||
self.comment = comment
|
||||
self.line_number = line_number
|
||||
self.parent = parentMessage
|
||||
|
||||
self.description = self.comment
|
||||
self.param1 = None
|
||||
self.param2 = None
|
||||
self.param3 = None
|
||||
self.param4 = None
|
||||
self.param5 = None
|
||||
self.param6 = None
|
||||
self.param7 = None
|
||||
|
||||
if not self.value:
|
||||
print(f"Debug WARNING: NO VALUE in CommandConstant: {self.name}") ## TODO make into ERROR
|
||||
exit()
|
||||
|
||||
if not self.comment: # This is an bug for a command
|
||||
#print(f"Debug WARNING: NO COMMENT in CommandConstant: {self.name}") ## TODO make into ERROR
|
||||
return
|
||||
|
||||
# Parse command comment to get the description and parameters.
|
||||
# print(f"Debug CommandConstant: {self.comment}")
|
||||
if not "|" in self.comment:
|
||||
# This is an error for a command constant
|
||||
error = Error("command_no_params_pipes", self.parent.filename, self.line_number, self.comment, self.name)
|
||||
#error.display_error()
|
||||
if not "command_no_params_pipes" in self.parent.errors:
|
||||
self.parent.errors["command_no_params_pipes"] = []
|
||||
self.parent.errors["command_no_params_pipes"].append(error)
|
||||
return
|
||||
|
||||
# Split on pipes
|
||||
commandSplit = self.comment.split("|")
|
||||
if len(commandSplit) < 9:
|
||||
# Should 7 pipes, so each command is fully surrounded
|
||||
error = Error("command_missing_params", self.parent.filename, self.line_number, self.comment, self.name)
|
||||
#error.display_error()
|
||||
if not "command_missing_params" in self.parent.errors:
|
||||
self.parent.errors["command_missing_params"] = []
|
||||
self.parent.errors["command_missing_params"].append(error)
|
||||
|
||||
self.description = commandSplit[0].strip()
|
||||
self.description = self.description if self.description else None
|
||||
|
||||
params_to_update = commandSplit[1:8]
|
||||
|
||||
for i, value in enumerate(params_to_update, start=1):
|
||||
if value.strip():
|
||||
# parse the param
|
||||
param = CommandParam(i, value, self.line_number, self)
|
||||
#param.display_info() # DEBUG CODE XXX
|
||||
setattr(self, f"param{i}", param)
|
||||
# parse the param
|
||||
|
||||
if len(commandSplit) > 8:
|
||||
extras = commandSplit[8:]
|
||||
error = Error("command_too_many_params", self.parent.filename, self.line_number, extras, self.name)
|
||||
if not "command_too_many_params" in self.parent.errors:
|
||||
self.parent.errors["command_too_many_params"] = []
|
||||
self.parent.errors["command_too_many_params"].append(error)
|
||||
|
||||
|
||||
# TODO if value or name are empty, error
|
||||
|
||||
def markdown_out(self):
|
||||
#print("DEBUG: CommandConstant.markdown_out")
|
||||
output = f"""### {self.name} ({self.value})
|
||||
|
||||
{self.description}
|
||||
|
||||
Param | Units | Range/Enum | Description
|
||||
--- | --- | --- | ---
|
||||
"""
|
||||
for i in range(1, 8):
|
||||
attr_name = f"param{i}"
|
||||
# getattr returns None if the attribute doesn't exist
|
||||
val = getattr(self, attr_name, None)
|
||||
|
||||
if val is not None:
|
||||
rangeVal = ""
|
||||
if val.minValue or val.maxValue:
|
||||
rangeVal = f"[{val.minValue if val.minValue else '-'} : {val.maxValue if val.maxValue else '-' }]"
|
||||
|
||||
output+=f"{i} | {", ".join(val.units)}|{', '.join(f"[{e}](#{e})" for e in val.enums)}{rangeVal} | {val.description}\n"
|
||||
else:
|
||||
output+=f"{i} | | | ?\n"
|
||||
|
||||
output+=f"\n"
|
||||
return output
|
||||
|
||||
|
||||
def display_info(self):
|
||||
print(f"Debug: CommandConstant: display_info")
|
||||
print(f" name: {self.name}, type: {self.type}, value: {self.value}, comment: {self.comment}, line: {self.line_number}")
|
||||
print(f" description: {self.description}\n param1: {self.param1}\n param2: {self.param2}\n param3: {self.param3}\n param4: {self.param4}\n param5: {self.param5}\n param6: {self.param6}\n param7: {self.param7}")
|
||||
|
||||
class MessageField:
|
||||
"""
|
||||
Represents a field.
|
||||
Encapsulates parsing of the field information.
|
||||
"""
|
||||
def __init__(self, name, type, comment, line_number, parentMessage):
|
||||
self.name = name
|
||||
self.type = type
|
||||
self.comment = comment
|
||||
self.unit = None
|
||||
self.enums = None
|
||||
self.minValue = None
|
||||
self.maxValue = None
|
||||
self.invalidValue = None
|
||||
self.frameValue = None
|
||||
self.lineNumber = line_number
|
||||
self.parent = parentMessage
|
||||
|
||||
#print(f"MessageComment: {comment}")
|
||||
match = None
|
||||
if self.comment:
|
||||
match = re.match(r'^((?:\[[^\]]*\]\s*)+)(.*)$', comment)
|
||||
self.description = comment
|
||||
bracketed_part = None
|
||||
if match:
|
||||
bracketed_part = match.group(1).strip() # .strip() removes trailing whitespace from the bracketed part
|
||||
self.description = match.group(2).strip()
|
||||
if bracketed_part:
|
||||
# get units
|
||||
bracket_content_matches = re.findall(r'\[(.*?)\]', bracketed_part)
|
||||
#print(f"bracket_content_matches: {bracket_content_matches}")
|
||||
for item in bracket_content_matches:
|
||||
item = item.strip()
|
||||
if item.startswith('@'): # Not a unit:
|
||||
if item.startswith('@enum'):
|
||||
item = item.split(" ")
|
||||
self.enums = item[1:]
|
||||
# Create parent enum objects
|
||||
for enumName in self.enums:
|
||||
if not enumName in parentMessage.enums:
|
||||
parentMessage.enums[enumName]=Enum(enumName,parentMessage)
|
||||
elif item.startswith('@range'):
|
||||
item = item[6:].strip().split(",")
|
||||
self.minValue = item[0].strip()
|
||||
self.maxValue = item[1].strip()
|
||||
elif item.startswith('@invalid'):
|
||||
self.invalidValue = item[8:].strip()
|
||||
#TODO: Do we require a description? (not currently)
|
||||
if self.invalidValue.split(" ")[0] not in ALLOWED_INVALID_VALUES:
|
||||
error = Error("unknown_invalid_value", self.parent.filename, self.lineNumber, self.invalidValue, self.name)
|
||||
#error.display_error()
|
||||
if not "unknown_invalid_value" in self.parent.errors:
|
||||
self.parent.errors["unknown_invalid_value"] = []
|
||||
self.parent.errors["unknown_invalid_value"].append(error)
|
||||
elif item.startswith('@frame'):
|
||||
self.frameValue = item[6:].strip()
|
||||
if self.frameValue not in ALLOWED_FRAMES:
|
||||
error = Error("unknown_frame", self.parent.filename, self.lineNumber, self.frameValue, self.name)
|
||||
#error.display_error()
|
||||
if not "unknown_frame" in self.parent.errors:
|
||||
self.parent.errors["unknown_frame"] = []
|
||||
self.parent.errors["unknown_frame"].append(error)
|
||||
else:
|
||||
print(f"WARNING: Unhandled metadata in message comment: {item}")
|
||||
# TODO - report errors for different kinds of metadata
|
||||
exit()
|
||||
|
||||
else: # bracket is a unit
|
||||
self.unit = item
|
||||
|
||||
if self.unit not in ALLOWED_UNITS:
|
||||
invalid_units.add(self.unit)
|
||||
error = Error("unknown_unit", self.parent.filename, self.lineNumber, self.unit, self.name)
|
||||
#error.display_error()
|
||||
if not "unknown_unit" in self.parent.errors:
|
||||
self.parent.errors["unknown_unit"] = []
|
||||
self.parent.errors["unknown_unit"].append(error)
|
||||
|
||||
if item == "-":
|
||||
self.unit = ""
|
||||
|
||||
|
||||
def display_info(self):
|
||||
print(f"Debug: MessageField: display_info")
|
||||
print(f" name: {self.name}, type: {self.type}, description: {self.description}, enums: {self.enums}, minValue: {self.minValue}, maxValue: {self.maxValue}, invalidValue: {self.invalidValue}, frameValue: {self.frameValue}")
|
||||
|
||||
|
||||
class UORBMessage:
|
||||
"""
|
||||
Represents a whole message, including fields, enums, commands, constants.
|
||||
The parser function delegates the parsing of each part of the message to
|
||||
more appropriate classes, once the specific type of line has been identified.
|
||||
"""
|
||||
|
||||
def __init__(self, filename):
|
||||
|
||||
self.filename = filename
|
||||
msg_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"../../msg")
|
||||
self.msg_filename = os.path.join(msg_path, self.filename)
|
||||
self.name = os.path.splitext(os.path.basename(msg_file))[0]
|
||||
self.shortDescription = ""
|
||||
self.longDescription = ""
|
||||
self.fields = []
|
||||
self.constantFields = dict()
|
||||
self.commandConstants = dict()
|
||||
self.enums = dict()
|
||||
self.output_file = os.path.join(output_dir, f"{self.name}.md")
|
||||
self.topics = []
|
||||
self.errors = dict()
|
||||
|
||||
self.parseFile()
|
||||
|
||||
if args.errors:
|
||||
#print(f"DEBUG: args.errors: {args.errors}")
|
||||
if args.error_messages:
|
||||
messages = args.error_messages.split(" ")
|
||||
#print(f"DEBUG: args.errors: {messages},self.name: {self.name}")
|
||||
if self.name in messages:
|
||||
self.reportErrors()
|
||||
#print(f"Debug: {self.name} in {messages}")
|
||||
else:
|
||||
self.reportErrors()
|
||||
|
||||
def reportErrors(self):
|
||||
#print(f"Debug: UORBMessage: reportErrors()")
|
||||
for errorType, errors in self.errors.items():
|
||||
for error in errors:
|
||||
error.display_error()
|
||||
|
||||
def markdown_out(self):
|
||||
#print(f"Debug: UORBMessage: markdown_out()")
|
||||
|
||||
# Add page header (forces wide pages)
|
||||
markdown = f"""---
|
||||
pageClass: is-wide-page
|
||||
---
|
||||
|
||||
# {self.name} (UORB message)
|
||||
|
||||
"""
|
||||
## Append description info if present
|
||||
markdown += f"{self.shortDescription}\n\n" if self.shortDescription else ""
|
||||
markdown += f"{self.longDescription}\n\n" if self.longDescription else ""
|
||||
|
||||
topicList = " ".join(self.topics)
|
||||
markdown += f"**TOPICS:** {topicList}\n\n"
|
||||
|
||||
# Generate field docs
|
||||
markdown += f"## Fields\n\n"
|
||||
markdown += "Name | Type | Unit [Frame] | Range/Enum | Description\n"
|
||||
markdown += "--- | --- | --- | --- | ---\n"
|
||||
for field in self.fields:
|
||||
unit = f"{field.unit}" if field.unit else ""
|
||||
frame = f"[{field.frameValue}]" if field.frameValue else ""
|
||||
unit = f"{unit} {frame}"
|
||||
unit.strip()
|
||||
unit = f" {unit}"
|
||||
|
||||
value = " "
|
||||
if field.enums:
|
||||
value = ""
|
||||
for enum in field.enums:
|
||||
value += f"[{enum}](#{enum})"
|
||||
value = value.strip()
|
||||
value = f"{value}"
|
||||
elif field.minValue or field.maxValue:
|
||||
value = f"[{field.minValue if field.minValue else '-'} : {field.maxValue if field.maxValue else '-' }]"
|
||||
|
||||
description = f" {field.description}" if field.description else ""
|
||||
invalid = f" (Invalid: {field.invalidValue}) " if field.invalidValue else ""
|
||||
markdown += f"{field.name} | `{field.type}` |{unit}|{value}|{description}{invalid}\n"
|
||||
|
||||
# Generate table for command docs
|
||||
if len(self.commandConstants) > 0:
|
||||
#print("DEBUGCOMMAND")
|
||||
markdown += f"\n## Commands\n\n"
|
||||
|
||||
"""
|
||||
markdown += "Name | Type | Value | Description\n"
|
||||
markdown += "--- | --- | --- |---\n"
|
||||
for name, command in self.commandConstants.items():
|
||||
description = f" {command.comment} " if enum.comment else " "
|
||||
markdown += f'<a href="#{name}"></a> {name} | `{command.type}` | {command.value} |{description}\n'
|
||||
"""
|
||||
for commandConstant in self.commandConstants.values():
|
||||
#print(commandConstant)
|
||||
markdown += commandConstant.markdown_out()
|
||||
|
||||
# Generate enum docs
|
||||
if len(self.enums) > 0:
|
||||
markdown += f"\n## Enums\n"
|
||||
|
||||
for name, enum in self.enums.items():
|
||||
markdown += f"\n### {name} {{#{name}}}\n\n"
|
||||
|
||||
markdown += "Name | Type | Value | Description\n"
|
||||
markdown += "--- | --- | --- | ---\n"
|
||||
|
||||
for enumValueName, enumValue in enum.enumValues.items():
|
||||
description = f" {enumValue.comment} " if enumValue.comment else " "
|
||||
markdown += f'<a href="#{enumValueName}"></a> {enumValueName} | `{enumValue.type}` | {enumValue.value} |{description}\n'
|
||||
|
||||
# Generate table for constants docs
|
||||
if len(self.constantFields) > 0:
|
||||
markdown += f"\n## Constants\n\n"
|
||||
markdown += "Name | Type | Value | Description\n"
|
||||
markdown += "--- | --- | --- |---\n"
|
||||
for name, enum in self.constantFields.items():
|
||||
description = f" {enum.comment} " if enum.comment else " "
|
||||
markdown += f'<a href="#{name}"></a> {name} | `{enum.type}` | {enum.value} |{description}\n'
|
||||
|
||||
|
||||
|
||||
# Append msg contents to the end
|
||||
with open(self.msg_filename, 'r') as source_file:
|
||||
msg_contents = source_file.read()
|
||||
msg_contents = msg_contents.strip()
|
||||
|
||||
#Format markdown using msg name, comment, url, contents.
|
||||
markdown += f"""
|
||||
|
||||
## Source Message
|
||||
|
||||
[Source file (GitHub)](https://github.com/PX4/PX4-Autopilot/blob/main/msg/{self.filename})
|
||||
|
||||
::: details Click here to see original file
|
||||
|
||||
```c
|
||||
{msg_contents}
|
||||
```
|
||||
|
||||
:::
|
||||
"""
|
||||
|
||||
with open(self.output_file, 'w') as content_file:
|
||||
content_file.write(markdown)
|
||||
|
||||
#exit()
|
||||
|
||||
|
||||
def display_info(self):
|
||||
print(f"UORBMessage: display_info")
|
||||
print(f" name: {self.name}")
|
||||
print(f" filename: {self.filename}, ")
|
||||
print(f" msg_filename: {self.msg_filename}, ")
|
||||
print(f"self.shortDescription: {self.shortDescription}")
|
||||
print(f"self.longDescription: {self.longDescription}")
|
||||
print(f"self.enums: {self.enums}")
|
||||
|
||||
for enum, enumObject in self.enums.items():
|
||||
enumObject.display_info()
|
||||
|
||||
# Output our data so far
|
||||
for field in self.fields:
|
||||
field.display_info()
|
||||
|
||||
for enumvalue in self.constantFields:
|
||||
print(enumvalue)
|
||||
self.constantFields[enumvalue].display_info()
|
||||
|
||||
def handleField(self, line, line_number, parentMessage):
|
||||
#print(f"debug: handleField: (line): \n {line}")
|
||||
# Note, here we know we don't have a comment or a topic.
|
||||
# We expect it to be a field.
|
||||
|
||||
# Check field doesn't have leading whitespace (trailing spaces already checked)
|
||||
if line[:1].isspace(): # Returns True for ' ', '\t', '\n', '\r', etc.
|
||||
#print("First character is whitespace")
|
||||
error = Error("leading_whitespace_field_or_constant", self.filename, line_number, line)
|
||||
if not "leading_whitespace_field_or_constant" in self.errors:
|
||||
self.errors["leading_whitespace_field_or_constant"] = []
|
||||
self.errors["leading_whitespace_field_or_constant"].append(error)
|
||||
|
||||
# Now we can parse the stripped line
|
||||
fieldOrConstant = line.strip()
|
||||
|
||||
# Check that the field or constant has only single whitespace separators
|
||||
stripped_fieldOrConstant = re.sub(r'\s+', ' ', fieldOrConstant) # Collapse all spaces to a single space (LHS already stripped).
|
||||
if stripped_fieldOrConstant != fieldOrConstant:
|
||||
#print("Field/Constant has multiple whitespace characters") # Since the collapsed version shows them.
|
||||
error = Error("field_or_constant_has_multiple_whitepsace", self.filename, line_number, line)
|
||||
if not "field_or_constant_has_multiple_whitepsace" in self.errors:
|
||||
self.errors["field_or_constant_has_multiple_whitepsace"] = []
|
||||
self.errors["field_or_constant_has_multiple_whitepsace"].append(error)
|
||||
|
||||
fieldOrConstant = stripped_fieldOrConstant
|
||||
|
||||
|
||||
|
||||
comment = None
|
||||
if "#" in line:
|
||||
commentExtract = line.split("#", 1) # Split once on left-most '#'
|
||||
fieldOrConstant = commentExtract[0].strip()
|
||||
comment = commentExtract[-1].strip()
|
||||
|
||||
if "=" not in fieldOrConstant:
|
||||
# Is a field:
|
||||
field = fieldOrConstant.split(" ")
|
||||
type = field[0].strip()
|
||||
name = field[1].strip()
|
||||
field = MessageField(name, type, comment, line_number, parentMessage)
|
||||
self.fields.append(field)
|
||||
else:
|
||||
temp = fieldOrConstant.split("=")
|
||||
value = temp[-1]
|
||||
typeAndName = temp[0].split(" ")
|
||||
type = typeAndName[0]
|
||||
name = typeAndName[1]
|
||||
if name.startswith("VEHICLE_CMD_") and parentMessage.name == 'VehicleCommand': #it's a command.
|
||||
#print(f"DEBUG: startswith VEHICLE_CMD_ {name}")
|
||||
commandConstant = CommandConstant(name, type, value, comment, line_number, parentMessage)
|
||||
#commandConstant.display_info()
|
||||
self.commandConstants[name]=commandConstant
|
||||
else: #it's a constant (or part of an enum)
|
||||
constantField = ConstantValue(name, type, value, comment, line_number)
|
||||
self.constantFields[name]=constantField
|
||||
|
||||
|
||||
def parseFile(self):
|
||||
initial_block_lines = []
|
||||
#stopping_token = None
|
||||
found_first_relevant_content = False
|
||||
gettingInitialComments = False
|
||||
gettingFields = False
|
||||
|
||||
with open(self.msg_filename, 'r', encoding='utf-8') as uorbfile:
|
||||
lines = uorbfile.read().splitlines()
|
||||
for line_number, line in enumerate(lines, 1):
|
||||
|
||||
if line != line.rstrip():
|
||||
#print(f"[{self.filename}] Trailing whitespace on line {line_number}: XX{line}YY")
|
||||
error = Error("trailing_whitespace", self.filename, line_number, line)
|
||||
if not "trailing_whitespace" in self.errors:
|
||||
self.errors["trailing_whitespace"] = []
|
||||
self.errors["trailing_whitespace"].append(error)
|
||||
|
||||
#print(f"line: {line}")
|
||||
stripped_line = re.sub(r'\s+', ' ', line).strip() # Collapse all spaces to a single space and strip stuff off end.
|
||||
#print(f"stripped_line: {stripped_line}")
|
||||
# TODO? Perhaps report whitespace if the size of those two is different and it is empty
|
||||
# Or perhaps we just fix it on request
|
||||
|
||||
isEmptyLine = False if line.strip() else True
|
||||
if not found_first_relevant_content and isEmptyLine: #Empty line
|
||||
#print(f"{self.filename}: Empty line at start of file: [{line_number}]\n {line}")
|
||||
error = Error("empty_start_line", self.filename, line_number, line)
|
||||
if not "empty_start_line" in self.errors:
|
||||
self.errors["empty_start_line"] = []
|
||||
self.errors["empty_start_line"].append(error)
|
||||
#error.display_error()
|
||||
continue
|
||||
if not found_first_relevant_content and not isEmptyLine:
|
||||
found_first_relevant_content = True
|
||||
|
||||
if stripped_line.startswith("#"):
|
||||
gettingInitialComments = True
|
||||
else:
|
||||
gettingInitialComments = False
|
||||
gettingFields = True
|
||||
|
||||
if gettingInitialComments and stripped_line.startswith("#"):
|
||||
stripped_line=stripped_line[1:].strip()
|
||||
#print(f"DEBUG: gettingInitialComments: comment line: {stripped_line}")
|
||||
initial_block_lines.append(stripped_line)
|
||||
else:
|
||||
gettingInitialComments = False
|
||||
gettingFields = True #Getting fields and constants
|
||||
if gettingFields:
|
||||
if isEmptyLine:
|
||||
continue # empty line
|
||||
if stripped_line.startswith("# TOPICS "):
|
||||
stripped_line = stripped_line[9:]
|
||||
stripped_line = stripped_line.split(" ")
|
||||
self.topics+= stripped_line
|
||||
# Note, default topic and topic errors handled after all lines parsed
|
||||
continue
|
||||
if stripped_line.startswith("#"):
|
||||
# Its an internal comment
|
||||
stripped_line=stripped_line[1:].strip()
|
||||
|
||||
if stripped_line:
|
||||
#print(f"{self.filename}: Internal comment: [{line_number}]\n {line}")
|
||||
error = Error("internal_comment", self.filename, line_number, line)
|
||||
if not "internal_comment" in self.errors:
|
||||
self.errors["internal_comment"] = []
|
||||
self.errors["internal_comment"].append(error)
|
||||
else:
|
||||
#print(f"{self.filename}: Empty internal comment: [{line_number}]\n {line}")
|
||||
error = Error("internal_comment_empty", self.filename, line_number, line)
|
||||
if not "internal_comment_empty" in self.errors:
|
||||
self.errors["internal_comment_empty"] = []
|
||||
self.errors["internal_comment_empty"].append(error)
|
||||
#pass # Empty comment
|
||||
continue
|
||||
|
||||
# Must be a field or a comment.
|
||||
self.handleField(line, line_number, parentMessage=self)
|
||||
|
||||
# Fix up topics if the topic is empty
|
||||
def camel_to_snake(name):
|
||||
# Match upper case not at start of string
|
||||
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
|
||||
# Handle cases with multiple capital first letter
|
||||
return re.sub('([A-Z]+)([A-Z][a-z]*)', r'\1_\2', s1).lower()
|
||||
|
||||
defaultTopic = camel_to_snake(self.name)
|
||||
if len(self.topics) == 0:
|
||||
# We have no topic declared, so set the default topic
|
||||
self.topics.append(defaultTopic)
|
||||
elif len(self.topics) == 1:
|
||||
# We have 1 topic declared - either it is default or there is some issue.
|
||||
if defaultTopic in self.topics:
|
||||
# Declared topic is default topic
|
||||
error = Error("topic_error", self.filename, "", f"WARNING: TOPIC {defaultTopic} unnecessarily declared for {self.name}")
|
||||
else:
|
||||
# Declared topic is not default topic
|
||||
error = Error("topic_error", self.filename, "", f"NOTE: TOPIC {self.topics[1]}: Only Declared topic is not default topic {defaultTopic} for {self.name}")
|
||||
if not "topic_error" in self.errors:
|
||||
self.errors["topic_error"] = []
|
||||
self.errors["topic_error"].append(error)
|
||||
elif len(self.topics) > 1:
|
||||
if defaultTopic not in self.topics:
|
||||
error = Error("topic_error", self.filename, "", f"NOTE: TOPIC - Default topic {defaultTopic} for {self.name} not in {self.topics}")
|
||||
|
||||
# Parse our short and long description
|
||||
#print(f"DEBUG: initial_block_lines: {initial_block_lines}")
|
||||
doingLongDescription = False
|
||||
for summaryline in initial_block_lines:
|
||||
if not self.shortDescription and summaryline.strip() == '':
|
||||
continue
|
||||
if not doingLongDescription and not summaryline.strip() == '':
|
||||
self.shortDescription += f" {summaryline}"
|
||||
self.shortDescription = self.shortDescription.strip()
|
||||
if not self.shortDescription[-1:] == ".": # Add terminating fullstop if not present.
|
||||
self.shortDescription += "."
|
||||
if not doingLongDescription and summaryline.strip() == '':
|
||||
doingLongDescription = True
|
||||
continue
|
||||
if doingLongDescription:
|
||||
self.longDescription += f"{summaryline}\n"
|
||||
|
||||
if self.longDescription:
|
||||
self.longDescription.strip()
|
||||
|
||||
if not self.shortDescription:
|
||||
# Summary has not been defined
|
||||
error = Error("summary_missing", self.filename)
|
||||
if not "summary_missing" in self.errors:
|
||||
self.errors["summary_missing"] = []
|
||||
self.errors["summary_missing"].append(error)
|
||||
|
||||
|
||||
# TODO Parse our constantValues into enums, leaving only constants
|
||||
constantValuesToRemove = []
|
||||
#print(f"DEBUG: Self.enums: {self.enums}")
|
||||
for enumName, enumObject in self.enums.items():
|
||||
for enumValueName, enumValueObject in self.constantFields.items():
|
||||
if enumValueName.startswith(enumName):
|
||||
# Copy this value into the object (cant be duplicate because parent is dict)
|
||||
enumObject.enumValues[enumValueName]=enumValueObject
|
||||
constantValuesToRemove.append(enumValueName)
|
||||
# Now delete the original enumvalues
|
||||
for enumValName in constantValuesToRemove:
|
||||
del self.constantFields[enumValName]
|
||||
constantsNotAssignedToEnums = len(self.constantFields)
|
||||
if constantsNotAssignedToEnums > 0:
|
||||
#print(f"Debug: WARNING constantsNotAssignedToEnums: {constantsNotAssignedToEnums}")
|
||||
for enumValueName, enumValue in self.constantFields.items():
|
||||
if enumValueName in ALLOWED_CONSTANTS_NOT_IN_ENUM: # Ignore constants
|
||||
pass
|
||||
else:
|
||||
error = Error("constant_not_in_assigned_enum", self.filename, enumValue.line_number, enumValueName)
|
||||
if not "constant_not_in_assigned_enum" in self.errors:
|
||||
self.errors["constant_not_in_assigned_enum"] = []
|
||||
self.errors["constant_not_in_assigned_enum"].append(error)
|
||||
# TODO Maybe present as list of possible enums.
|
||||
|
||||
|
||||
import yaml
|
||||
@@ -924,50 +127,83 @@ if __name__ == "__main__":
|
||||
|
||||
parser = argparse.ArgumentParser(description='Generate docs from .msg files')
|
||||
parser.add_argument('-d', dest='dir', help='output directory', required=True)
|
||||
parser.add_argument('-e', dest='errors', action='store_true', help='Report errors')
|
||||
parser.add_argument('-m', dest='error_messages', help='Message to report errors against (by default all)')
|
||||
args = parser.parse_args()
|
||||
|
||||
output_dir = args.dir
|
||||
if not os.path.isdir(output_dir):
|
||||
print(f"making output_dir {output_dir}")
|
||||
os.mkdir(output_dir)
|
||||
|
||||
msg_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"../../msg")
|
||||
msg_files = get_msgs_list(msg_path)
|
||||
|
||||
msg_files.sort()
|
||||
|
||||
versioned_msgs_list = ''
|
||||
unversioned_msgs_list = ''
|
||||
msgTypes = set()
|
||||
|
||||
for msg_file in msg_files:
|
||||
# Add messages to set of allowed types (compound types)
|
||||
#msg_type = msg_file.rsplit('/')[-1]
|
||||
#msg_type = msg_type.rsplit('\\')[-1]
|
||||
#msg_type = msg_type.rsplit('.')[0]
|
||||
msg_name = os.path.splitext(os.path.basename(msg_file))[0]
|
||||
msgTypes.add(msg_name)
|
||||
output_file = os.path.join(output_dir, msg_name+'.md')
|
||||
msg_filename = os.path.join(msg_path, msg_file)
|
||||
print("{:} -> {:}".format(msg_filename, output_file))
|
||||
|
||||
for msg_file in msg_files:
|
||||
message = UORBMessage(msg_file)
|
||||
# Any additional tests that can't be in UORBMessage parser go here.
|
||||
message.markdown_out()
|
||||
#Format msg url
|
||||
msg_url="[source file](https://github.com/PX4/PX4-Autopilot/blob/main/msg/%s)" % msg_file
|
||||
|
||||
msg_description = ""
|
||||
summary_description = ""
|
||||
|
||||
#Get msg description (first non-empty comment line from top of msg)
|
||||
with open(msg_filename, 'r') as lineparser:
|
||||
line = lineparser.readline()
|
||||
while line.startswith('#') or (line.strip() == ''):
|
||||
print('DEBUG: line: %s' % line)
|
||||
line=line[1:].strip()+'\n'
|
||||
stripped_line=line.strip()
|
||||
if msg_description and not summary_description and stripped_line=='':
|
||||
summary_description = msg_description.strip()
|
||||
|
||||
msg_description+=line
|
||||
line = lineparser.readline()
|
||||
msg_description=msg_description.strip()
|
||||
if not summary_description and msg_description:
|
||||
summary_description = msg_description
|
||||
print('msg_description: Z%sZ' % msg_description)
|
||||
print('summary_description: Z%sZ' % summary_description)
|
||||
summary_description
|
||||
msg_contents = ""
|
||||
#Get msg contents (read the file)
|
||||
with open(msg_filename, 'r') as source_file:
|
||||
msg_contents = source_file.read()
|
||||
|
||||
#Format markdown using msg name, comment, url, contents.
|
||||
markdown_output="""# %s (UORB message)
|
||||
|
||||
%s
|
||||
|
||||
%s
|
||||
|
||||
```c
|
||||
%s
|
||||
```
|
||||
""" % (msg_name, msg_description, msg_url, msg_contents)
|
||||
|
||||
with open(output_file, 'w') as content_file:
|
||||
content_file.write(markdown_output)
|
||||
|
||||
# Categorize as versioned or unversioned
|
||||
if "versioned" in msg_file:
|
||||
versioned_msgs_list += f"- [{message.name}]({message.name}.md)"
|
||||
if message.shortDescription:
|
||||
versioned_msgs_list += f" — {message.shortDescription}"
|
||||
versioned_msgs_list += '- [%s](%s.md)' % (msg_name, msg_name)
|
||||
if summary_description:
|
||||
versioned_msgs_list += " — %s" % summary_description
|
||||
versioned_msgs_list += "\n"
|
||||
else:
|
||||
unversioned_msgs_list += f"- [{message.name}]({message.name}.md)"
|
||||
if message.shortDescription:
|
||||
unversioned_msgs_list += f" — {message.shortDescription}"
|
||||
unversioned_msgs_list += '- [%s](%s.md)' % (msg_name, msg_name)
|
||||
if summary_description:
|
||||
unversioned_msgs_list += " — %s" % summary_description
|
||||
unversioned_msgs_list += "\n"
|
||||
|
||||
# Write out the index.md file
|
||||
index_text=f"""# uORB Message Reference
|
||||
index_text="""# uORB Message Reference
|
||||
|
||||
::: info
|
||||
This list is [auto-generated](https://github.com/PX4/PX4-Autopilot/blob/main/Tools/msg/generate_msg_docs.py) from the source code.
|
||||
@@ -982,14 +218,14 @@ Graphs showing how these are used [can be found here](../middleware/uorb_graph.m
|
||||
|
||||
## Versioned Messages
|
||||
|
||||
{versioned_msgs_list}
|
||||
%s
|
||||
|
||||
## Unversioned Messages
|
||||
|
||||
{unversioned_msgs_list}
|
||||
"""
|
||||
%s
|
||||
""" % (versioned_msgs_list, unversioned_msgs_list)
|
||||
index_file = os.path.join(output_dir, 'index.md')
|
||||
with open(index_file, 'w', encoding='utf-8') as content_file:
|
||||
with open(index_file, 'w') as content_file:
|
||||
content_file.write(index_text)
|
||||
|
||||
generate_dds_yaml_doc(msg_files)
|
||||
|
||||
@@ -1138,8 +1138,6 @@ if num_mags >= 1:
|
||||
|
||||
if not math.isnan(sensor_mag_0['temperature'][0]):
|
||||
|
||||
mag_0_params['TC_M0_ID'] = int(np.median(sensor_mag_0['device_id']))
|
||||
|
||||
# find the min, max and reference temperature
|
||||
mag_0_params['TC_M0_TMIN'] = np.amin(sensor_mag_0['temperature'])
|
||||
mag_0_params['TC_M0_TMAX'] = np.amax(sensor_mag_0['temperature'])
|
||||
@@ -1658,9 +1656,9 @@ sensor_baro_0['pressure'] = median_filter(sensor_baro_0['pressure'])
|
||||
# fit data
|
||||
median_pressure = np.median(sensor_baro_0['pressure'])
|
||||
if noResample:
|
||||
coef_baro_0_x = np.polyfit(temp_rel,(sensor_baro_0['pressure']-median_pressure),5) # pressure in Pascal
|
||||
coef_baro_0_x = np.polyfit(temp_rel,100*(sensor_baro_0['pressure']-median_pressure),5) # convert from hPa to Pa
|
||||
else:
|
||||
temperature, baro = resampleWithDeltaX(temp_rel,(sensor_baro_0['pressure']-median_pressure)) # pressure in Pascal
|
||||
temperature, baro = resampleWithDeltaX(temp_rel,100*(sensor_baro_0['pressure']-median_pressure)) # convert from hPa to Pa
|
||||
coef_baro_0_x = np.polyfit(temperature,baro,5)
|
||||
|
||||
baro_0_params['TC_B0_X5'] = coef_baro_0_x[0]
|
||||
@@ -1677,7 +1675,7 @@ baro_0_x_resample = fit_coef_baro_0_x(temp_rel_resample)
|
||||
plt.figure(13,figsize=(20,13))
|
||||
|
||||
# draw plots
|
||||
plt.plot(sensor_baro_0['temperature'],sensor_baro_0['pressure']-median_pressure,'b')
|
||||
plt.plot(sensor_baro_0['temperature'],100*sensor_baro_0['pressure']-100*median_pressure,'b')
|
||||
plt.plot(temp_resample,baro_0_x_resample,'r')
|
||||
plt.title('Baro 0 ({}) Bias vs Temperature'.format(baro_0_params['TC_B0_ID']))
|
||||
plt.ylabel('Z bias (Pa)')
|
||||
@@ -1719,9 +1717,9 @@ if num_baros >= 2:
|
||||
# fit data
|
||||
median_pressure = np.median(sensor_baro_1['pressure'])
|
||||
if noResample:
|
||||
coef_baro_1_x = np.polyfit(temp_rel,(sensor_baro_1['pressure']-median_pressure),5) # pressure in Pascal
|
||||
coef_baro_1_x = np.polyfit(temp_rel,100*(sensor_baro_1['pressure']-median_pressure),5) # convert from hPa to Pa
|
||||
else:
|
||||
temperature, baro = resampleWithDeltaX(temp_rel,(sensor_baro_1['pressure']-median_pressure)) # pressure in Pascal
|
||||
temperature, baro = resampleWithDeltaX(temp_rel,100*(sensor_baro_1['pressure']-median_pressure)) # convert from hPa to Pa
|
||||
coef_baro_1_x = np.polyfit(temperature,baro,5)
|
||||
|
||||
baro_1_params['TC_B1_X5'] = coef_baro_1_x[0]
|
||||
@@ -1738,7 +1736,7 @@ if num_baros >= 2:
|
||||
plt.figure(14,figsize=(20,13))
|
||||
|
||||
# draw plots
|
||||
plt.plot(sensor_baro_1['temperature'],sensor_baro_1['pressure']-median_pressure,'b')
|
||||
plt.plot(sensor_baro_1['temperature'],100*sensor_baro_1['pressure']-100*median_pressure,'b')
|
||||
plt.plot(temp_resample,baro_1_x_resample,'r')
|
||||
plt.title('Baro 1 ({}) Bias vs Temperature'.format(baro_1_params['TC_B1_ID']))
|
||||
plt.ylabel('Z bias (Pa)')
|
||||
@@ -1780,9 +1778,9 @@ if num_baros >= 3:
|
||||
# fit data
|
||||
median_pressure = np.median(sensor_baro_2['pressure'])
|
||||
if noResample:
|
||||
coef_baro_2_x = np.polyfit(temp_rel,(sensor_baro_2['pressure']-median_pressure),5) # pressure in Pascal
|
||||
coef_baro_2_x = np.polyfit(temp_rel,100*(sensor_baro_2['pressure']-median_pressure),5) # convert from hPa to Pa
|
||||
else:
|
||||
temperature, baro = resampleWithDeltaX(temp_rel,(sensor_baro_2['pressure']-median_pressure)) # pressure in Pascal
|
||||
temperature, baro = resampleWithDeltaX(temp_rel,100*(sensor_baro_2['pressure']-median_pressure)) # convert from hPa to Pa
|
||||
coef_baro_2_x = np.polyfit(temperature,baro,5)
|
||||
|
||||
baro_2_params['TC_B2_X5'] = coef_baro_2_x[0]
|
||||
@@ -1799,7 +1797,7 @@ if num_baros >= 3:
|
||||
plt.figure(15,figsize=(20,13))
|
||||
|
||||
# draw plots
|
||||
plt.plot(sensor_baro_2['temperature'],sensor_baro_2['pressure']-median_pressure,'b')
|
||||
plt.plot(sensor_baro_2['temperature'],100*sensor_baro_2['pressure']-100*median_pressure,'b')
|
||||
plt.plot(temp_resample,baro_2_x_resample,'r')
|
||||
plt.title('Baro 2 ({}) Bias vs Temperature'.format(baro_2_params['TC_B2_ID']))
|
||||
plt.ylabel('Z bias (Pa)')
|
||||
@@ -1840,7 +1838,7 @@ if num_baros >= 4:
|
||||
|
||||
# fit data
|
||||
median_pressure = np.median(sensor_baro_3['pressure'])
|
||||
coef_baro_3_x = np.polyfit(temp_rel,(sensor_baro_3['pressure']-median_pressure),5) # pressure in Pascal
|
||||
coef_baro_3_x = np.polyfit(temp_rel,100*(sensor_baro_3['pressure']-median_pressure),5) # convert from hPa to Pa
|
||||
baro_3_params['TC_B3_X5'] = coef_baro_3_x[0]
|
||||
baro_3_params['TC_B3_X4'] = coef_baro_3_x[1]
|
||||
baro_3_params['TC_B3_X3'] = coef_baro_3_x[2]
|
||||
@@ -1855,7 +1853,7 @@ if num_baros >= 4:
|
||||
plt.figure(16,figsize=(20,13))
|
||||
|
||||
# draw plots
|
||||
plt.plot(sensor_baro_3['temperature'],sensor_baro_3['pressure']-median_pressure,'b')
|
||||
plt.plot(sensor_baro_3['temperature'],100*sensor_baro_3['pressure']-100*median_pressure,'b')
|
||||
plt.plot(temp_resample,baro_3_x_resample,'r')
|
||||
plt.title('Baro 3 ({}) Bias vs Temperature'.format(baro_3_params['TC_B3_ID']))
|
||||
plt.ylabel('Z bias (Pa)')
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,7 +15,7 @@ class ModuleDocumentation(object):
|
||||
# TOC in https://github.com/PX4/PX4-Autopilot/blob/main/docs/en/SUMMARY.md
|
||||
valid_categories = ['driver', 'estimator', 'controller', 'system',
|
||||
'communication', 'command', 'template', 'simulation', 'autotune']
|
||||
valid_subcategories = ['', 'adc', 'camera', 'distance_sensor', 'imu', 'ins', 'airspeed_sensor',
|
||||
valid_subcategories = ['', 'camera', 'distance_sensor', 'imu', 'ins', 'airspeed_sensor',
|
||||
'magnetometer', 'baro', 'optical_flow', 'radio_control','rpm_sensor', 'transponder']
|
||||
|
||||
max_line_length = 80 # wrap lines that are longer than this
|
||||
|
||||
Executable
+983
@@ -0,0 +1,983 @@
|
||||
#!/usr/bin/env python3
|
||||
############################################################################
|
||||
#
|
||||
# Copyright (c) 2012-2024 PX4 Development Team. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# 3. Neither the name PX4 nor the names of its contributors may be
|
||||
# used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
#
|
||||
# Serial firmware uploader for the PX4FMU bootloader
|
||||
#
|
||||
# The PX4 firmware file is a JSON-encoded Python object, containing
|
||||
# metadata fields and a zlib-compressed base64-encoded firmware image.
|
||||
#
|
||||
# The uploader uses the following fields from the firmware file:
|
||||
#
|
||||
# image
|
||||
# The firmware that will be uploaded.
|
||||
# image_size
|
||||
# The size of the firmware in bytes.
|
||||
# board_id
|
||||
# The board for which the firmware is intended.
|
||||
# board_revision
|
||||
# Currently only used for informational purposes.
|
||||
#
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
import binascii
|
||||
import socket
|
||||
import struct
|
||||
import json
|
||||
import zlib
|
||||
import base64
|
||||
import time
|
||||
import array
|
||||
import os
|
||||
|
||||
from sys import platform as _platform
|
||||
|
||||
try:
|
||||
import serial
|
||||
except ImportError as e:
|
||||
print(f"Failed to import serial: {e}")
|
||||
print("")
|
||||
print("You may need to install it using:")
|
||||
print(" python -m pip install pyserial")
|
||||
print("")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# Detect python version
|
||||
if sys.version_info[0] < 3:
|
||||
raise RuntimeError("Python 2 is not supported. Please try again using Python 3.")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# Use monotonic time where available
|
||||
def _time():
|
||||
try:
|
||||
return time.monotonic()
|
||||
except Exception:
|
||||
return time.time()
|
||||
|
||||
class FirmwareNotSuitableException(Exception):
|
||||
def __init__(self, message):
|
||||
super(FirmwareNotSuitableException, self).__init__(message)
|
||||
|
||||
|
||||
class firmware(object):
|
||||
'''Loads a firmware file'''
|
||||
|
||||
desc = {}
|
||||
image = bytes()
|
||||
crctab = array.array('I', [
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
|
||||
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
|
||||
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
|
||||
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
|
||||
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
|
||||
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
|
||||
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
|
||||
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
|
||||
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
|
||||
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
|
||||
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
|
||||
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
|
||||
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
|
||||
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
|
||||
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
|
||||
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
|
||||
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
|
||||
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
|
||||
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
|
||||
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
||||
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d])
|
||||
crcpad = bytearray(b'\xff\xff\xff\xff')
|
||||
|
||||
def __init__(self, path):
|
||||
|
||||
# read the file
|
||||
f = open(path, "r")
|
||||
self.desc = json.load(f)
|
||||
f.close()
|
||||
|
||||
self.image = bytearray(zlib.decompress(base64.b64decode(self.desc['image'])))
|
||||
|
||||
# pad image to 4-byte length
|
||||
while ((len(self.image) % 4) != 0):
|
||||
self.image.extend(b'\xff')
|
||||
|
||||
def property(self, propname):
|
||||
return self.desc[propname]
|
||||
|
||||
def __crc32(self, bytes, state):
|
||||
for byte in bytes:
|
||||
index = (state ^ byte) & 0xff
|
||||
state = self.crctab[index] ^ (state >> 8)
|
||||
return state
|
||||
|
||||
def crc(self, padlen):
|
||||
state = self.__crc32(self.image, int(0))
|
||||
for _ in range(len(self.image), (padlen - 1), 4):
|
||||
state = self.__crc32(self.crcpad, state)
|
||||
return state
|
||||
|
||||
|
||||
class uploader:
|
||||
'''Uploads a firmware file to the PX4 bootloader'''
|
||||
|
||||
# protocol bytes
|
||||
INSYNC = b'\x12'
|
||||
EOC = b'\x20'
|
||||
|
||||
# reply bytes
|
||||
OK = b'\x10'
|
||||
FAILED = b'\x11'
|
||||
INVALID = b'\x13' # rev3+
|
||||
BAD_SILICON_REV = b'\x14' # rev5+
|
||||
|
||||
# command bytes
|
||||
NOP = b'\x00' # guaranteed to be discarded by the bootloader
|
||||
GET_SYNC = b'\x21'
|
||||
GET_DEVICE = b'\x22'
|
||||
CHIP_ERASE = b'\x23'
|
||||
CHIP_VERIFY = b'\x24' # rev2 only
|
||||
PROG_MULTI = b'\x27'
|
||||
READ_MULTI = b'\x28' # rev2 only
|
||||
GET_CRC = b'\x29' # rev3+
|
||||
GET_OTP = b'\x2a' # rev4+ , get a word from OTP area
|
||||
GET_SN = b'\x2b' # rev4+ , get a word from SN area
|
||||
GET_CHIP = b'\x2c' # rev5+ , get chip version
|
||||
SET_BOOT_DELAY = b'\x2d' # rev5+ , set boot delay
|
||||
GET_CHIP_DES = b'\x2e' # rev5+ , get chip description in ASCII
|
||||
GET_VERSION = b'\x2f' # rev5+ , get bootloader version in ASCII
|
||||
CHIP_FULL_ERASE = b'\x40' # full erase of flash, rev6+
|
||||
MAX_DES_LENGTH = 20
|
||||
|
||||
REBOOT = b'\x30'
|
||||
|
||||
INFO_BL_REV = b'\x01' # bootloader protocol revision
|
||||
BL_REV_MIN = 2 # minimum supported bootloader protocol
|
||||
BL_REV_MAX = 5 # maximum supported bootloader protocol
|
||||
INFO_BOARD_ID = b'\x02' # board type
|
||||
INFO_BOARD_REV = b'\x03' # board revision
|
||||
INFO_FLASH_SIZE = b'\x04' # max firmware size in bytes
|
||||
|
||||
PROG_MULTI_MAX = 252 # protocol max is 255, must be multiple of 4
|
||||
READ_MULTI_MAX = 252 # protocol max is 255
|
||||
|
||||
NSH_INIT = bytearray(b'\x0d\x0d\x0d')
|
||||
NSH_REBOOT_BL = b"reboot -b\n"
|
||||
NSH_REBOOT = b"reboot\n"
|
||||
MAVLINK_REBOOT_ID1 = bytearray(b'\xfe\x21\x72\xff\x00\x4c\x00\x00\x40\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x00\x01\x00\x00\x53\x6b')
|
||||
MAVLINK_REBOOT_ID0 = bytearray(b'\xfe\x21\x45\xff\x00\x4c\x00\x00\x40\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x00\x00\x00\x00\xcc\x37')
|
||||
|
||||
MAX_FLASH_PRGRAM_TIME = 0.001 # Time on an F7 to send SYNC, RESULT from last data in multi RXed
|
||||
|
||||
def __init__(self, portname, baudrate_bootloader, baudrate_flightstack):
|
||||
# Open the port, keep the default timeout short so we can poll quickly.
|
||||
# On some systems writes can suddenly get stuck without having a
|
||||
# write_timeout > 0 set.
|
||||
# chartime 8n1 * bit rate is us
|
||||
self.chartime = 10 * (1.0 / baudrate_bootloader)
|
||||
|
||||
# we use a window approche to SYNC,<result> gathring
|
||||
self.window = 0
|
||||
self.window_max = 256
|
||||
self.window_per = 2 # Sync,<result>
|
||||
self.ackWindowedMode = False # Assume Non Widowed mode for all USB CDC
|
||||
self.port = serial.Serial(portname, baudrate_bootloader, timeout=0.5, write_timeout=0)
|
||||
self.otp = b''
|
||||
self.sn = b''
|
||||
self.baudrate_bootloader = baudrate_bootloader
|
||||
self.baudrate_flightstack = baudrate_flightstack
|
||||
self.baudrate_flightstack_idx = -1
|
||||
self.force_erase = False
|
||||
|
||||
def close(self):
|
||||
if self.port is not None:
|
||||
self.port.close()
|
||||
|
||||
def open(self):
|
||||
# upload timeout
|
||||
timeout = _time() + 0.2
|
||||
|
||||
# attempt to open the port while it exists and until timeout occurs
|
||||
while self.port is not None:
|
||||
portopen = True
|
||||
try:
|
||||
portopen = self.port.is_open
|
||||
except AttributeError:
|
||||
portopen = self.port.isOpen()
|
||||
|
||||
if not portopen and _time() < timeout:
|
||||
try:
|
||||
self.port.open()
|
||||
except OSError:
|
||||
# wait for the port to be ready
|
||||
time.sleep(0.04)
|
||||
except serial.SerialException:
|
||||
# if open fails, try again later
|
||||
time.sleep(0.04)
|
||||
else:
|
||||
break
|
||||
|
||||
# debugging code
|
||||
def __probe(self, state):
|
||||
# self.port.setRTS(state)
|
||||
return
|
||||
|
||||
def __send(self, c):
|
||||
# print("send " + binascii.hexlify(c))
|
||||
self.port.write(c)
|
||||
|
||||
def __recv(self, count=1):
|
||||
c = self.port.read(count)
|
||||
if len(c) < 1:
|
||||
raise RuntimeError("timeout waiting for data (%u bytes)" % count)
|
||||
# print("recv " + binascii.hexlify(c))
|
||||
return c
|
||||
|
||||
def __recv_int(self):
|
||||
raw = self.__recv(4)
|
||||
val = struct.unpack("<I", raw)
|
||||
return val[0]
|
||||
|
||||
def __getSync(self, doFlush=True):
|
||||
if (doFlush):
|
||||
self.port.flush()
|
||||
c = bytes(self.__recv())
|
||||
if c != self.INSYNC:
|
||||
raise RuntimeError("unexpected %s instead of INSYNC" % c)
|
||||
c = self.__recv()
|
||||
if c == self.INVALID:
|
||||
raise RuntimeError("bootloader reports INVALID OPERATION")
|
||||
if c == self.FAILED:
|
||||
raise RuntimeError("bootloader reports OPERATION FAILED")
|
||||
if c != self.OK:
|
||||
raise RuntimeError("unexpected response 0x%x instead of OK" % ord(c))
|
||||
|
||||
# The control flow for receiving Sync is on the order of 16 Ms per Sync
|
||||
# This will validate all the SYNC,<results> for a window of programing
|
||||
# in about 13.81 Ms for 256 blocks written
|
||||
def __ackSyncWindow(self, count):
|
||||
if (count > 0):
|
||||
data = bytearray(bytes(self.__recv(count)))
|
||||
if (len(data) != count):
|
||||
raise RuntimeError("Ack Window %i not %i " % (len(data), count))
|
||||
for i in range(0, len(data), 2):
|
||||
if bytes([data[i]]) != self.INSYNC:
|
||||
raise RuntimeError("unexpected %s instead of INSYNC" % data[i])
|
||||
if bytes([data[i+1]]) == self.INVALID:
|
||||
raise RuntimeError("bootloader reports INVALID OPERATION")
|
||||
if bytes([data[i+1]]) == self.FAILED:
|
||||
raise RuntimeError("bootloader reports OPERATION FAILED")
|
||||
if bytes([data[i+1]]) != self.OK:
|
||||
raise RuntimeError("unexpected response 0x%x instead of OK" % ord(data[i+1]))
|
||||
|
||||
# attempt to get back into sync with the bootloader
|
||||
def __sync(self):
|
||||
# send a stream of ignored bytes longer than the longest possible conversation
|
||||
# that we might still have in progress
|
||||
# self.__send(uploader.NOP * (uploader.PROG_MULTI_MAX + 2))
|
||||
self.port.flushInput()
|
||||
self.__send(uploader.GET_SYNC +
|
||||
uploader.EOC)
|
||||
self.__getSync()
|
||||
|
||||
def __trySync(self):
|
||||
try:
|
||||
self.port.flush()
|
||||
if (self.__recv() != self.INSYNC):
|
||||
# print("unexpected 0x%x instead of INSYNC" % ord(c))
|
||||
return False
|
||||
c = self.__recv()
|
||||
if (c == self.BAD_SILICON_REV):
|
||||
raise NotImplementedError()
|
||||
if (c != self.OK):
|
||||
# print("unexpected 0x%x instead of OK" % ord(c))
|
||||
return False
|
||||
return True
|
||||
|
||||
except NotImplementedError:
|
||||
raise RuntimeError("Programing not supported for this version of silicon!\n"
|
||||
"See https://docs.px4.io/main/en/flight_controller/silicon_errata.html")
|
||||
except RuntimeError:
|
||||
# timeout, no response yet
|
||||
return False
|
||||
|
||||
# attempt to determins if the device is CDCACM or A FTDI
|
||||
def __determineInterface(self):
|
||||
self.port.flushInput()
|
||||
# Set a baudrate that can not work on a real serial port
|
||||
# in that it is 233% off.
|
||||
try:
|
||||
self.port.baudrate = self.baudrate_bootloader * 2.33
|
||||
except NotImplementedError as e:
|
||||
# This error can occur because pySerial on Windows does not support odd baudrates
|
||||
print(f"{e} -> could not check for FTDI device, assuming USB connection")
|
||||
return
|
||||
|
||||
self.__send(uploader.GET_SYNC +
|
||||
uploader.EOC)
|
||||
try:
|
||||
self.__getSync(False)
|
||||
except RuntimeError:
|
||||
# if it fails we are on a real serial port - only leave this enabled on Windows
|
||||
if sys.platform.startswith('win'):
|
||||
self.ackWindowedMode = True
|
||||
finally:
|
||||
try:
|
||||
self.port.baudrate = self.baudrate_bootloader
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# send the GET_DEVICE command and wait for an info parameter
|
||||
def __getInfo(self, param):
|
||||
self.__send(uploader.GET_DEVICE + param + uploader.EOC)
|
||||
value = self.__recv_int()
|
||||
self.__getSync()
|
||||
return value
|
||||
|
||||
# send the GET_OTP command and wait for an info parameter
|
||||
def __getOTP(self, param):
|
||||
t = struct.pack("I", param) # int param as 32bit ( 4 byte ) char array.
|
||||
self.__send(uploader.GET_OTP + t + uploader.EOC)
|
||||
value = self.__recv(4)
|
||||
self.__getSync()
|
||||
return value
|
||||
|
||||
# send the GET_SN command and wait for an info parameter
|
||||
def __getSN(self, param):
|
||||
t = struct.pack("I", param) # int param as 32bit ( 4 byte ) char array.
|
||||
self.__send(uploader.GET_SN + t + uploader.EOC)
|
||||
value = self.__recv(4)
|
||||
self.__getSync()
|
||||
return value
|
||||
|
||||
# send the GET_CHIP command
|
||||
def __getCHIP(self):
|
||||
self.__send(uploader.GET_CHIP + uploader.EOC)
|
||||
value = self.__recv_int()
|
||||
self.__getSync()
|
||||
return value
|
||||
|
||||
# send the GET_CHIP command
|
||||
def __getCHIPDes(self):
|
||||
self.__send(uploader.GET_CHIP_DES + uploader.EOC)
|
||||
length = self.__recv_int()
|
||||
value = self.__recv(length)
|
||||
self.__getSync()
|
||||
pieces = value.split(b",")
|
||||
return pieces
|
||||
|
||||
def __getVersion(self):
|
||||
self.__send(uploader.GET_VERSION + uploader.EOC)
|
||||
try:
|
||||
length = self.__recv_int()
|
||||
value = self.__recv(length)
|
||||
self.__getSync()
|
||||
except RuntimeError:
|
||||
# Bootloader doesn't support version call
|
||||
return "unknown"
|
||||
return value.decode()
|
||||
|
||||
def __drawProgressBar(self, label, progress, maxVal):
|
||||
if maxVal < progress:
|
||||
progress = maxVal
|
||||
|
||||
percent = (float(progress) / float(maxVal)) * 100.0
|
||||
|
||||
redraw = "\r" if sys.stdout.isatty() else "\n"
|
||||
sys.stdout.write("%s%s: [%-20s] %.1f%%" % (redraw, label, '='*int(percent/5.0), percent))
|
||||
sys.stdout.flush()
|
||||
|
||||
# send the CHIP_ERASE command and wait for the bootloader to become ready
|
||||
def __erase(self, label):
|
||||
print(f"Windowed mode: {self.ackWindowedMode}")
|
||||
print("\n", end='')
|
||||
|
||||
if self.force_erase:
|
||||
print("Trying force erase of full chip...\n")
|
||||
self.__send(uploader.CHIP_FULL_ERASE +
|
||||
uploader.EOC)
|
||||
else:
|
||||
self.__send(uploader.CHIP_ERASE +
|
||||
uploader.EOC)
|
||||
|
||||
# erase is very slow, give it 30s
|
||||
deadline = _time() + 30.0
|
||||
while _time() < deadline:
|
||||
|
||||
usualEraseDuration = 15.0
|
||||
estimatedTimeRemaining = deadline-_time()
|
||||
if estimatedTimeRemaining >= usualEraseDuration:
|
||||
self.__drawProgressBar(label, 30.0-estimatedTimeRemaining, usualEraseDuration)
|
||||
else:
|
||||
self.__drawProgressBar(label, 10.0, 10.0)
|
||||
sys.stdout.write(" (timeout: %d seconds) " % int(deadline-_time()))
|
||||
sys.stdout.flush()
|
||||
|
||||
if self.__trySync():
|
||||
self.__drawProgressBar(label, 10.0, 10.0)
|
||||
if self.force_erase:
|
||||
print("\nForce erase done.\n")
|
||||
return
|
||||
|
||||
if self.force_erase:
|
||||
raise RuntimeError("timed out waiting for erase, force erase is likely not supported by bootloader!")
|
||||
else:
|
||||
raise RuntimeError("timed out waiting for erase")
|
||||
|
||||
# send a PROG_MULTI command to write a collection of bytes
|
||||
def __program_multi(self, data, windowMode):
|
||||
|
||||
length = len(data).to_bytes(1, byteorder='big')
|
||||
|
||||
self.__send(uploader.PROG_MULTI)
|
||||
self.__send(length)
|
||||
self.__send(data)
|
||||
self.__send(uploader.EOC)
|
||||
if (not windowMode):
|
||||
self.__getSync(False)
|
||||
else:
|
||||
# The following is done to have minimum delay on the transmission
|
||||
# of the ne fw. The per block cost of __getSync was about 16 mS per.
|
||||
# Passively wait on Sync and Result using board rates and
|
||||
# N.B. attempts to activly wait on InWating still carried 8 mS of overhead
|
||||
self.__probe(False)
|
||||
self.__probe(True)
|
||||
time.sleep((ord(length) * self.chartime) + uploader.MAX_FLASH_PRGRAM_TIME)
|
||||
self.__probe(False)
|
||||
|
||||
# verify multiple bytes in flash
|
||||
def __verify_multi(self, data):
|
||||
|
||||
length = len(data).to_bytes(1, byteorder='big')
|
||||
|
||||
self.__send(uploader.READ_MULTI)
|
||||
self.__send(length)
|
||||
self.__send(uploader.EOC)
|
||||
self.port.flush()
|
||||
programmed = self.__recv(len(data))
|
||||
if programmed != data:
|
||||
print("got " + binascii.hexlify(programmed))
|
||||
print("expect " + binascii.hexlify(data))
|
||||
return False
|
||||
self.__getSync()
|
||||
return True
|
||||
|
||||
# send the reboot command
|
||||
def __reboot(self):
|
||||
self.__send(uploader.REBOOT +
|
||||
uploader.EOC)
|
||||
self.port.flush()
|
||||
|
||||
# v3+ can report failure if the first word flash fails
|
||||
if self.bl_rev >= 3:
|
||||
self.__getSync()
|
||||
|
||||
# split a sequence into a list of size-constrained pieces
|
||||
def __split_len(self, seq, length):
|
||||
return [seq[i:i+length] for i in range(0, len(seq), length)]
|
||||
|
||||
# upload code
|
||||
def __program(self, label, fw):
|
||||
self.__probe(False)
|
||||
print("\n", end='')
|
||||
code = fw.image
|
||||
groups = self.__split_len(code, uploader.PROG_MULTI_MAX)
|
||||
# Give imedate feedback
|
||||
self.__drawProgressBar(label, 0, len(groups))
|
||||
uploadProgress = 0
|
||||
for bytes in groups:
|
||||
self.__program_multi(bytes, self.ackWindowedMode)
|
||||
# If in Window mode, extend the window size for the __ackSyncWindow
|
||||
if self.ackWindowedMode:
|
||||
self.window += self.window_per
|
||||
|
||||
# Print upload progress (throttled, so it does not delay upload progress)
|
||||
uploadProgress += 1
|
||||
if uploadProgress % 256 == 0:
|
||||
self.__probe(True)
|
||||
self.__probe(False)
|
||||
self.__probe(True)
|
||||
self.__ackSyncWindow(self.window)
|
||||
self.__probe(False)
|
||||
self.window = 0
|
||||
self.__drawProgressBar(label, uploadProgress, len(groups))
|
||||
|
||||
# Do any remaining fragment
|
||||
self.__ackSyncWindow(self.window)
|
||||
self.window = 0
|
||||
self.__drawProgressBar(label, 100, 100)
|
||||
|
||||
# verify code
|
||||
def __verify_v2(self, label, fw):
|
||||
print("\n", end='')
|
||||
self.__send(uploader.CHIP_VERIFY +
|
||||
uploader.EOC)
|
||||
self.__getSync()
|
||||
code = fw.image
|
||||
groups = self.__split_len(code, uploader.READ_MULTI_MAX)
|
||||
verifyProgress = 0
|
||||
for bytes in groups:
|
||||
verifyProgress += 1
|
||||
if verifyProgress % 256 == 0:
|
||||
self.__drawProgressBar(label, verifyProgress, len(groups))
|
||||
if (not self.__verify_multi(bytes)):
|
||||
raise RuntimeError("Verification failed")
|
||||
self.__drawProgressBar(label, 100, 100)
|
||||
|
||||
def __verify_v3(self, label, fw):
|
||||
print("\n", end='')
|
||||
self.__drawProgressBar(label, 1, 100)
|
||||
expect_crc = fw.crc(self.fw_maxsize)
|
||||
self.__send(uploader.GET_CRC + uploader.EOC)
|
||||
time.sleep(0.5)
|
||||
report_crc = self.__recv_int()
|
||||
self.__getSync()
|
||||
if report_crc != expect_crc:
|
||||
print("Expected 0x%x" % expect_crc)
|
||||
print("Got 0x%x" % report_crc)
|
||||
raise RuntimeError("Program CRC failed")
|
||||
self.__drawProgressBar(label, 100, 100)
|
||||
|
||||
def __set_boot_delay(self, boot_delay):
|
||||
self.__send(uploader.SET_BOOT_DELAY +
|
||||
struct.pack("b", boot_delay) +
|
||||
uploader.EOC)
|
||||
self.__getSync()
|
||||
|
||||
# get basic data about the board
|
||||
def identify(self):
|
||||
self.__determineInterface()
|
||||
# make sure we are in sync before starting
|
||||
self.__sync()
|
||||
|
||||
# get the bootloader protocol ID first
|
||||
self.bl_rev = self.__getInfo(uploader.INFO_BL_REV)
|
||||
if (self.bl_rev < uploader.BL_REV_MIN) or (self.bl_rev > uploader.BL_REV_MAX):
|
||||
print("Unsupported bootloader protocol %d" % uploader.INFO_BL_REV)
|
||||
raise RuntimeError("Bootloader protocol mismatch")
|
||||
|
||||
self.board_type = self.__getInfo(uploader.INFO_BOARD_ID)
|
||||
self.board_rev = self.__getInfo(uploader.INFO_BOARD_REV)
|
||||
self.fw_maxsize = self.__getInfo(uploader.INFO_FLASH_SIZE)
|
||||
|
||||
self.version = self.__getVersion()
|
||||
|
||||
# upload the firmware
|
||||
def upload(self, fw_list, force=False, boot_delay=None, boot_check=False, force_erase=False):
|
||||
self.force_erase = force_erase
|
||||
# select correct binary
|
||||
found_suitable_firmware = False
|
||||
for file in fw_list:
|
||||
fw = firmware(file)
|
||||
if self.board_type == fw.property('board_id'):
|
||||
if len(fw_list) > 1: print("using firmware binary {}".format(file))
|
||||
found_suitable_firmware = True
|
||||
break
|
||||
|
||||
if not found_suitable_firmware:
|
||||
msg = "Firmware not suitable for this board (Firmware board_type=%u board_id=%u)" % (
|
||||
self.board_type, fw.property('board_id'))
|
||||
print("WARNING: %s" % msg)
|
||||
if force:
|
||||
if len(fw_list) > 1:
|
||||
raise FirmwareNotSuitableException("force flashing failed, more than one file provided, none suitable")
|
||||
print("FORCED WRITE, FLASHING ANYWAY!")
|
||||
else:
|
||||
raise FirmwareNotSuitableException(msg)
|
||||
|
||||
percent = fw.property('image_size') / fw.property('image_maxsize')
|
||||
binary_size = float(fw.property('image_size'))
|
||||
binary_max_size = float(fw.property('image_maxsize'))
|
||||
percent = (binary_size / binary_max_size) * 100
|
||||
|
||||
print("Loaded firmware for board id: %s,%s size: %d bytes (%.2f%%) " % (fw.property('board_id'), fw.property('board_revision'), fw.property('image_size'), percent))
|
||||
print()
|
||||
|
||||
print(f"Bootloader version: {self.version}")
|
||||
|
||||
# Make sure we are doing the right thing
|
||||
start = _time()
|
||||
if self.board_type != fw.property('board_id'):
|
||||
msg = "Firmware not suitable for this board (Firmware board_type=%u board_id=%u)" % (
|
||||
self.board_type, fw.property('board_id'))
|
||||
print("WARNING: %s" % msg)
|
||||
if force:
|
||||
print("FORCED WRITE, FLASHING ANYWAY!")
|
||||
else:
|
||||
raise FirmwareNotSuitableException(msg)
|
||||
|
||||
# Prevent uploads where the image would overflow the flash
|
||||
if self.fw_maxsize < fw.property('image_size'):
|
||||
raise RuntimeError("Firmware image is too large for this board")
|
||||
|
||||
# OTP added in v4:
|
||||
if self.bl_rev >= 4:
|
||||
for byte in range(0, 32*6, 4):
|
||||
x = self.__getOTP(byte)
|
||||
self.otp = self.otp + x
|
||||
# print(binascii.hexlify(x).decode('Latin-1') + ' ', end='')
|
||||
# see src/modules/systemlib/otp.h in px4 code:
|
||||
self.otp_id = self.otp[0:4]
|
||||
self.otp_idtype = self.otp[4:5]
|
||||
self.otp_vid = self.otp[8:4:-1]
|
||||
self.otp_pid = self.otp[12:8:-1]
|
||||
self.otp_coa = self.otp[32:160]
|
||||
# show user:
|
||||
try:
|
||||
print("Sn: ", end='')
|
||||
for byte in range(0, 12, 4):
|
||||
x = self.__getSN(byte)
|
||||
x = x[::-1] # reverse the bytes
|
||||
self.sn = self.sn + x
|
||||
print(binascii.hexlify(x).decode('Latin-1'), end='') # show user
|
||||
print('')
|
||||
print("Chip: %08x" % self.__getCHIP())
|
||||
|
||||
otp_id = self.otp_id.decode('Latin-1')
|
||||
if ("PX4" in otp_id):
|
||||
print("OTP id: " + otp_id)
|
||||
print("OTP idtype: " + binascii.b2a_qp(self.otp_idtype).decode('Latin-1'))
|
||||
print("OTP vid: " + binascii.hexlify(self.otp_vid).decode('Latin-1'))
|
||||
print("OTP pid: " + binascii.hexlify(self.otp_pid).decode('Latin-1'))
|
||||
print("OTP coa: " + binascii.b2a_base64(self.otp_coa).decode('Latin-1'))
|
||||
|
||||
except Exception as e:
|
||||
# ignore bad character encodings
|
||||
print(f"Exception ignored: {e}")
|
||||
pass
|
||||
|
||||
# Silicon errata check was added in v5
|
||||
if (self.bl_rev >= 5):
|
||||
des = self.__getCHIPDes()
|
||||
if (len(des) == 2):
|
||||
family, revision = des
|
||||
print(f"Family: {family.decode()}")
|
||||
print(f"Revision: {revision.decode()}")
|
||||
print(f"Flash: {self.fw_maxsize} bytes")
|
||||
|
||||
# Prevent uploads where the maximum image size of the board config is smaller than the flash
|
||||
# of the board. This is a hint the user chose the wrong config and will lack features
|
||||
# for this particular board.
|
||||
|
||||
# This check should also check if the revision is an unaffected revision
|
||||
# and thus can support the full flash, see
|
||||
# https://github.com/PX4/Firmware/blob/master/src/drivers/boards/common/stm32/board_mcu_version.c#L125-L144
|
||||
|
||||
if self.fw_maxsize > fw.property('image_maxsize') and not force:
|
||||
print(f"WARNING: Board can accept larger flash images ({self.fw_maxsize} bytes) than board config ({fw.property('image_maxsize')} bytes)")
|
||||
else:
|
||||
# If we're still on bootloader v4 on a Pixhawk, we don't know if we
|
||||
# have the silicon errata and therefore need to flash px4_fmu-v2
|
||||
# with 1MB flash or if it supports px4_fmu-v3 with 2MB flash.
|
||||
if fw.property('board_id') == 9 \
|
||||
and fw.property('image_size') > 1032192 \
|
||||
and not force:
|
||||
raise RuntimeError("\nThe Board uses bootloader revision 4 and can therefore not determine\n"
|
||||
"if flashing more than 1 MB (px4_fmu-v3_default) is safe, chances are\n"
|
||||
"high that it is not safe! If unsure, use px4_fmu-v2_default.\n"
|
||||
"\n"
|
||||
"If you know you that the board does not have the silicon errata, use\n"
|
||||
"this script with --force, or update the bootloader. If you are invoking\n"
|
||||
"upload using make, you can use force-upload target to force the upload.\n")
|
||||
self.__erase("Erase ")
|
||||
self.__program("Program", fw)
|
||||
|
||||
if self.bl_rev == 2:
|
||||
self.__verify_v2("Verify ", fw)
|
||||
else:
|
||||
self.__verify_v3("Verify ", fw)
|
||||
|
||||
if boot_delay is not None:
|
||||
self.__set_boot_delay(boot_delay)
|
||||
|
||||
print("\nRebooting.", end='')
|
||||
self.__reboot()
|
||||
self.port.close()
|
||||
print(" Elapsed Time %3.3f\n" % (_time() - start))
|
||||
|
||||
def __next_baud_flightstack(self):
|
||||
if self.baudrate_flightstack_idx + 1 >= len(self.baudrate_flightstack):
|
||||
return False
|
||||
try:
|
||||
self.port.baudrate = self.baudrate_flightstack[self.baudrate_flightstack_idx + 1]
|
||||
self.baudrate_flightstack_idx = self.baudrate_flightstack_idx + 1
|
||||
except serial.SerialException:
|
||||
# Sometimes _configure_port fails
|
||||
time.sleep(0.04)
|
||||
|
||||
return True
|
||||
|
||||
def send_protocol_splitter_format(self, data):
|
||||
# Header Structure:
|
||||
# bits: 1 2 3 4 5 6 7 8
|
||||
# header[0] - | Magic | (='S')
|
||||
# header[1] - |T| LenH | (T - 0: mavlink; 1: rtps)
|
||||
# header[2] - | LenL |
|
||||
# header[3] - | Checksum |
|
||||
|
||||
MAGIC = 83
|
||||
|
||||
len_bytes = len(data).to_bytes(2, "big")
|
||||
LEN_H = len_bytes[0] & 127
|
||||
LEN_L = len_bytes[1] & 255
|
||||
CHECKSUM = MAGIC ^ LEN_H ^ LEN_L
|
||||
|
||||
header_ints = [MAGIC, LEN_H, LEN_L, CHECKSUM]
|
||||
header_bytes = struct.pack("{}B".format(len(header_ints)), *header_ints)
|
||||
|
||||
self.__send(header_bytes)
|
||||
self.__send(data)
|
||||
|
||||
def send_reboot(self, use_protocol_splitter_format=False):
|
||||
if (not self.__next_baud_flightstack()):
|
||||
return False
|
||||
|
||||
print("Attempting reboot on %s with baudrate=%d..." % (self.port.port, self.port.baudrate), file=sys.stderr)
|
||||
if "ttyS" in self.port.port:
|
||||
print("If the board does not respond, check the connection to the Flight Controller")
|
||||
else:
|
||||
print("If the board does not respond, unplug and re-plug the USB connector.", file=sys.stderr)
|
||||
|
||||
try:
|
||||
send_fct = self.__send
|
||||
if use_protocol_splitter_format:
|
||||
send_fct = self.send_protocol_splitter_format
|
||||
|
||||
# try MAVLINK command first
|
||||
self.port.flush()
|
||||
send_fct(uploader.MAVLINK_REBOOT_ID1)
|
||||
send_fct(uploader.MAVLINK_REBOOT_ID0)
|
||||
# then try reboot via NSH
|
||||
send_fct(uploader.NSH_INIT)
|
||||
send_fct(uploader.NSH_REBOOT_BL)
|
||||
send_fct(uploader.NSH_INIT)
|
||||
send_fct(uploader.NSH_REBOOT)
|
||||
self.port.flush()
|
||||
self.port.baudrate = self.baudrate_bootloader
|
||||
except Exception:
|
||||
try:
|
||||
self.port.flush()
|
||||
self.port.baudrate = self.baudrate_bootloader
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
# Parse commandline arguments
|
||||
parser = argparse.ArgumentParser(description="Firmware uploader for the PX autopilot system.")
|
||||
parser.add_argument('--port', action="store", required=True, help="Comma-separated list of serial port(s) to which the FMU may be attached")
|
||||
parser.add_argument('--baud-bootloader', action="store", type=int, default=115200, help="Baud rate of the serial port (default is 115200) when communicating with bootloader, only required for true serial ports.")
|
||||
parser.add_argument('--baud-flightstack', action="store", default="57600", help="Comma-separated list of baud rate of the serial port (default is 57600) when communicating with flight stack (Mavlink or NSH), only required for true serial ports.")
|
||||
parser.add_argument('--force', action='store_true', default=False, help='Override board type check, or silicon errata checks and continue loading')
|
||||
parser.add_argument('--force-erase', action="store_true", help="Do not perform the blank check, always erase every sector of the application space")
|
||||
parser.add_argument('--boot-delay', type=int, default=None, help='minimum boot delay to store in flash')
|
||||
parser.add_argument('--use-protocol-splitter-format', action='store_true', help='use protocol splitter format for reboot')
|
||||
parser.add_argument('firmware', action="store", nargs='+', help="Firmware file(s)")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.use_protocol_splitter_format:
|
||||
print("Using protocol splitter format to reboot pixhawk!")
|
||||
|
||||
# warn people about ModemManager which interferes badly with Pixhawk
|
||||
if os.path.exists("/usr/sbin/ModemManager"):
|
||||
print("==========================================================================================================")
|
||||
print("WARNING: You should uninstall ModemManager as it conflicts with any non-modem serial device (like Pixhawk)")
|
||||
print("==========================================================================================================")
|
||||
|
||||
print("Waiting for bootloader...")
|
||||
# tell any GCS that might be connected to the autopilot to give up
|
||||
# control of the serial port
|
||||
|
||||
# send to localhost and default GCS port
|
||||
ipaddr = '127.0.0.1'
|
||||
portnum = 14550
|
||||
|
||||
# COMMAND_LONG in MAVLink 1
|
||||
heartbeatpacket = bytearray.fromhex('fe097001010000000100020c5103033c8a')
|
||||
commandpacket = bytearray.fromhex('fe210101014c00000000000000000000000000000000000000000000803f00000000f6000000008459')
|
||||
|
||||
# initialize an UDP socket
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
|
||||
# send heartbeat to initialize connection and command to free the link
|
||||
s.sendto(heartbeatpacket, (ipaddr, portnum))
|
||||
s.sendto(commandpacket, (ipaddr, portnum))
|
||||
|
||||
# close the socket
|
||||
s.close()
|
||||
|
||||
# Spin waiting for a device to show up
|
||||
try:
|
||||
while True:
|
||||
portlist = []
|
||||
patterns = args.port.split(",")
|
||||
# on unix-like platforms use glob to support wildcard ports. This allows
|
||||
# the use of /dev/serial/by-id/usb-3D_Robotics on Linux, which prevents the upload from
|
||||
# causing modem hangups etc
|
||||
if "linux" in _platform or "darwin" in _platform or "cygwin" in _platform:
|
||||
import glob
|
||||
for pattern in patterns:
|
||||
portlist += glob.glob(pattern)
|
||||
else:
|
||||
portlist = patterns
|
||||
|
||||
baud_flightstack = [int(x) for x in args.baud_flightstack.split(',')]
|
||||
|
||||
successful = False
|
||||
unsuitable_board = False
|
||||
for port in portlist:
|
||||
|
||||
# print("Trying %s" % port)
|
||||
|
||||
# create an uploader attached to the port
|
||||
try:
|
||||
if "linux" in _platform:
|
||||
# Linux, don't open Mac OS and Win ports
|
||||
if "COM" not in port and "tty.usb" not in port:
|
||||
up = uploader(port, args.baud_bootloader, baud_flightstack)
|
||||
elif "darwin" in _platform:
|
||||
# OS X, don't open Windows and Linux ports
|
||||
if "COM" not in port and "ACM" not in port:
|
||||
up = uploader(port, args.baud_bootloader, baud_flightstack)
|
||||
elif "cygwin" in _platform:
|
||||
# Cygwin, don't open native Windows COM and Linux ports
|
||||
if "COM" not in port and "ACM" not in port:
|
||||
up = uploader(port, args.baud_bootloader, baud_flightstack)
|
||||
elif "win" in _platform:
|
||||
# Windows, don't open POSIX ports
|
||||
if "/" not in port:
|
||||
up = uploader(port, args.baud_bootloader, baud_flightstack)
|
||||
except Exception as e:
|
||||
# open failed, rate-limit our attempts
|
||||
time.sleep(0.05)
|
||||
print(f"Exception ignored: {e}")
|
||||
|
||||
# and loop to the next port
|
||||
continue
|
||||
|
||||
found_bootloader = False
|
||||
while True:
|
||||
up.open()
|
||||
|
||||
# port is open, try talking to it
|
||||
try:
|
||||
# identify the bootloader
|
||||
up.identify()
|
||||
found_bootloader = True
|
||||
print()
|
||||
print(f"Found board id: {up.board_type},{up.board_rev} bootloader protocol revision {up.bl_rev} on {port}")
|
||||
break
|
||||
|
||||
except (RuntimeError, serial.SerialException):
|
||||
|
||||
if not up.send_reboot(args.use_protocol_splitter_format):
|
||||
break
|
||||
|
||||
# wait for the reboot, without we might run into Serial I/O Error 5
|
||||
time.sleep(0.25)
|
||||
|
||||
# always close the port
|
||||
up.close()
|
||||
|
||||
# wait for the close, without we might run into Serial I/O Error 6
|
||||
time.sleep(0.3)
|
||||
|
||||
if not found_bootloader:
|
||||
# Go to the next port
|
||||
continue
|
||||
|
||||
try:
|
||||
# ok, we have a bootloader, try flashing it
|
||||
up.upload(args.firmware, force=args.force, boot_delay=args.boot_delay, force_erase=args.force_erase)
|
||||
|
||||
# if we made this far without raising exceptions, the upload was successful
|
||||
successful = True
|
||||
|
||||
except RuntimeError as e:
|
||||
# print the error
|
||||
print(f"\n\nError: {e}")
|
||||
|
||||
except FirmwareNotSuitableException:
|
||||
unsuitable_board = True
|
||||
up.close()
|
||||
continue
|
||||
|
||||
except IOError:
|
||||
up.close()
|
||||
continue
|
||||
|
||||
finally:
|
||||
# always close the port
|
||||
up.close()
|
||||
|
||||
# we could loop here if we wanted to wait for more boards...
|
||||
if successful:
|
||||
sys.exit(0)
|
||||
else:
|
||||
sys.exit(1)
|
||||
|
||||
if unsuitable_board:
|
||||
# If we land here, we went through all ports, did not flash any
|
||||
# board and found at least one unsuitable board.
|
||||
# Exit with 2, so a caller can distinguish from other errors
|
||||
sys.exit(2)
|
||||
|
||||
# Delay retries to < 20 Hz to prevent spin-lock from hogging the CPU
|
||||
time.sleep(0.05)
|
||||
|
||||
# CTRL+C aborts the upload/spin-lock by interrupt mechanics
|
||||
except KeyboardInterrupt:
|
||||
print("\n Upload aborted by user.")
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
||||
@@ -6,7 +6,6 @@ future
|
||||
jinja2>=2.8
|
||||
jsonschema
|
||||
kconfiglib
|
||||
lark
|
||||
lxml
|
||||
matplotlib>=3.0
|
||||
numpy>=1.13
|
||||
@@ -15,8 +14,8 @@ packaging
|
||||
pandas>=0.21
|
||||
pkgconfig
|
||||
psutil
|
||||
pycryptodome
|
||||
pygments
|
||||
wheel>=0.31.1
|
||||
pymavlink
|
||||
pyros-genmsg
|
||||
pyserial
|
||||
@@ -25,6 +24,7 @@ pyyaml
|
||||
requests
|
||||
setuptools>=39.2.0
|
||||
six>=1.12.0
|
||||
sympy>=1.10.1
|
||||
toml>=0.9
|
||||
wheel>=0.31.1
|
||||
sympy>=1.10.1
|
||||
pycryptodome
|
||||
lark
|
||||
|
||||
@@ -176,10 +176,8 @@ if [[ $INSTALL_NUTTX == "true" ]]; then
|
||||
|
||||
echo
|
||||
echo "Fetching Xtensa compilers"
|
||||
XTENSA_FILE_NAME=xtensa-esp-elf-13.2.0_20240530-x86_64-linux-gnu.tar.xz
|
||||
wget -q -P $DIR https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/$XTENSA_FILE_NAME
|
||||
sudo tar -xf $DIR/$XTENSA_FILE_NAME -C /opt
|
||||
rm $DIR/$XTENSA_FILE_NAME
|
||||
wget -q -P $DIR https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-x86_64-linux-gnu.tar.xz
|
||||
sudo tar -xf $DIR/xtensa-esp-elf-13.2.0_20240530-x86_64-linux-gnu.tar.xz -C /opt
|
||||
echo 'export PATH=$PATH:/opt/xtensa-esp-elf/bin/' >> /home/$USER/.bashrc
|
||||
fi
|
||||
|
||||
|
||||
Submodule Tools/simulation/gazebo-classic/sitl_gazebo-classic updated: 5b6966ed57...6697ab169c
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user