diff --git a/git-main/developer-guide/style-guide/index.html b/git-main/developer-guide/style-guide/index.html index 2be6c4d..49a1292 100644 --- a/git-main/developer-guide/style-guide/index.html +++ b/git-main/developer-guide/style-guide/index.html @@ -798,15 +798,6 @@ - - -
The focus of anyone contributing to this project should be to write code that is easily understood by anyone, including people who have little experience with ROSflight or coding in general. So, we ask that contributions adhere to the following style guidelines.
+The focus of anyone contributing to this project should be to write code that is easily understood by anyone, including people who have little experience with ROSflight or coding in general. +So, we ask that contributions adhere to the following style guidelines.
Well written and clear code should be easy to understand even without comments. However, since this project is intended to be as accessible as possible, we ask that you write both clear code and clear comments. Don't use comments to explain code that would be difficult to understand without comments, but instead use them to make clear code even more understandable.
+Well written and clear code should be easy to understand even without comments. +However, since this project is intended to be as accessible as possible, we ask that you write both clear code and clear comments. +Don't use comments to explain code that would be difficult to understand without comments, but instead use them to make clear code even more understandable.
Doxygen comments should be added pretty much anywhere where it makes sense. Please include at least a brief for anything you write. For methods and functions, also include explanations of all arguments and the return value. More detailed explanations are encouraged for non-trivial methods and objects.
+Doxygen comments should be added pretty much anywhere where it makes sense. +Please include at least a brief for anything you write. +For methods and functions, also include explanations of all arguments and the return value. +See the below example for the Doxygen style you should use. +
/**
+ * @brief Converts an LLA coordinate to NED coordinates
+ *
+ * @param lla: Array of floats of size 3, with [latitude, longitude, altitude]
+ * @return Array of doubles corresponding to the NED coordinates measured from the origin
+ */
+std::array<double, 3> lla2ned(std::array<float, 3> lla);
+
More detailed explanations are encouraged for non-trivial methods and objects.
+For single-line Doxygen comments, three slashes is acceptable, e.g., /// Comment here
.
Please try not to commit anything that only changes white space or line endings. To check if that's going to happen, run git diff --check
before you stage your files.
Please try not to commit anything that only changes white space or line endings.
+To check if that's going to happen, run git diff --check
before you stage your files.
ROSflight follows the ROS2 C++ style guide, with some more specific guidelines below. Please follow first the style guidelines below and then the ROS2 guidelines. A .clang-format file and format-correcting script is provided in most ROSflight repositories that can be used to auto-format your code to help you find things you might have missed. Format checks on pull requests using this .clang-format file may also exist.
+ROSflight follows the ROS2 C++ style guide, with some more specific guidelines below. +Please follow first the style guidelines below and then the ROS2 guidelines. +A .clang-format file and format-correcting script is provided in most ROSflight repositories that can be used to auto-format your code to help you find things you might have missed.
Indentation should be 2 spaces (no tabs). Case statements in switch blocks should not be indented, e.g.
-switch (variable)
-{
-case 1:
- // do something
- break;
-default:
- break;
-}
-
Indentation should be 2 spaces (no tabs).
There should be a space between if
, for
, or while
and the condition, e.g. while (true)
, not while(true)
.
There should be a space between if
, for
, or while
and the condition.
+
// Correct
+while (true) { ... }
+
+// Incorrect
+while(true) { ... }
+
StateManager
).StateManager
).data_
).set_error()
).true
or false
, not 0
or 1
.Primitive data types (int
, float
, etc.) should always be passed by value. Other types (e.g. classes) should be passed by reference and should maintain proper const-correctness. Arguments that are modified by the function should be passed by pointer instead of reference, to make the fact that the argument will be changed clearer in the calling code. For example:
void do_something(float dt, const MyClass& data, int* output);
-
This function would be called as
-float dt = 0.01f;
-MyClass my_class;
-int value;
-
-do_something(dt, my_class, &value);
-
This makes it clear the value
is modified by the function call.
All modules should be defined as a self-contained class. All member variables should be declared as "private," named with a post-pended underscore, and accessed through inline accessor functions. All accessible data should be encapsulated in a struct. For example, here is a snippet from the Sensors
module in the firmware:
All modules should be defined as a self-contained class.
+All member variables should be declared as "private," named with a post-pended underscore.
+All accessible data should be encapsulated in a struct.
+For example, here is a snippet from the Sensors
module in the firmware:
class Sensors
{
public:
@@ -1653,7 +1642,7 @@ Classes Data data_;
}
Note that data_
is a private member variable, but the Data
struct is declared publicly and data_
is accessed through an inline const
accessor to prevent another module from changing data_
.
Note that data_
is a private member variable, but the Data
struct is declared publicly.
Enums should be declared using the following style:
enum ArmedState
@@ -1674,7 +1663,8 @@ StructsGlobals¶
-The use of global variables should be limited to when absolutely necessary (such as linking to interrupt routines or hardware peripherals). This should only occur in board support layers and not in the core ROSflight libary code.
+The use of global variables should be limited to when absolutely necessary (such as linking to interrupt routines or hardware peripherals).
+This should only occur in board support layers and not in the core ROSflight libary code, ROSplane, or ROScopter.
Include Order¶
Include files at the top of your file in the following order:
@@ -1683,8 +1673,13 @@ Include OrderOther header files from this project (e.g. "rosflight.h"
)
- The header file for this specific source file
-Group the includes according to the above list with an empty line between each group. (For external libraries, you may subdivide group 2 into a group for each library.) The first two groups should use angle brackets (<>
), and the last two groups should use quotation marks (""
). Files from external libraries should be namespaced by the library name (e.g. <breezystm32/breezystm32.h>
, not <breezystm32.h>
).
-Alphabetize the files within each group. Do not change the include order to fix build errors; if you have to do that it means you are not including a file somewhere that you should. Please fix it by including all the right files.
+Group the includes according to the above list with an empty line between each group.
+(For external libraries, you may subdivide group 2 into a group for each library.)
+The first two groups should use angle brackets (<>
), and the last two groups should use quotation marks (""
).
+Files from external libraries should be namespaced by the library name (e.g. <breezystm32/breezystm32.h>
, not <breezystm32.h>
).
+Alphabetize the files within each group.
+Do not change the include order to fix build errors; if you have to do that it means you are not including a file somewhere that you should.
+Please fix it by including all the right files.
Include C standard library headers using the C++ style (#include <cmath>
) instead of the C style (#include <math.h>
).
For example, in sensors.c
I might have:
#include <cstdbool>
diff --git a/git-main/search/search_index.json b/git-main/search/search_index.json
index d3a77a2..b7ef310 100644
--- a/git-main/search/search_index.json
+++ b/git-main/search/search_index.json
@@ -1 +1 @@
-{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Welcome to ROSflight","text":"The ROS2 updates for ROSflight are still under development. Please use with discretion.
"},{"location":"#what-is-rosflight","title":"What is ROSflight?","text":"ROSflight is a lean and adaptable autopilot system designed from the ground up with researchers in mind. Its purpose is to enable researchers to quickly and easily try out new ideas with minimal effort. Some of ROSflight's key feature are:
- Lightweight, modular, and well documented code that is easy to understand and modify.
- Most of the autopilot exists on a Linux computer rather than a microcontroller, enabling easier development with increased capabilities.
- Seamless switching between simulation and hardware: no part of the autopilot knows if it is running in simulation or not.
- Built on a ROS2 framework, allowing easy integration with ROS2 based projects.
See the user guide for more details on ROSflight.
"},{"location":"#why-rosflight","title":"Why ROSflight?","text":"There are a lot of excellent autopilots out there with a lot of great firmware options. Why did we feel like the world needed ROSflight? Because in our experience none of the other available options satisfied our research needs. Existing autopilots commonly used by researchers tend to have massive codebases under constant development that run primarily on microcontrollers.
This presents a number of problems. First, we are limited in our ability to understand and control everything occurring within the autonomy stack, making much of the autopilot an untouchable black box. Second, we are limited to the abilities of microcontrollers and can't take advantage of the more powerful hardware and software that can be found on Linux computers. Third, maintaining up-to-date support for software or hardware projects becomes a lot of work as things are frequently changing.
ROSflight is intended to fix these problems by being a lightweight, modular, and well documented codebase that offloads as much as possible to a ROS2 based framework running on a Linux computer.
"},{"location":"#our-vision","title":"Our Vision","text":"Perhaps more important than what we are trying to accomplish is what we are not trying to accomplish. ROSflight is not intended to be a fully-featured autopilot with all the same functions of other autopilots, but instead serve as a core foundation that can easily be adapted to any use case.
Therefore, one of our primary objectives is to avoid feature creep and remain lean. We hope that others will extend our code and build on top of it, and would love to hear about your successes. But for the most part, we will not be incorporating these new features back into the main project. Instead, we hope that ROSflight will remain a lean, core code base that will continue to serve as a launch pad for exciting new projects and applications.
"},{"location":"developer-guide/contribution-guidelines/","title":"Contribution Guidelines","text":"ROSflight is intended to be a streamlined, bare-bones autopilot. We welcome any bug fixes, cleanup, or other contributions which do not add complexity or detract from the readability and simplified nature of the project. In an attempt to avoid \"feature creep,\" we will be very discriminatory in merging pull requests whose purpose is to simply add features. Forking the repository in order to add features is totally acceptable and encouraged, just recognize us as the original authors of the autopilot (per the agreement in the BSD-3 license).
In addition, we strive to maintain a very high standard of quality in terms of code style, variable naming, and the like. By maintaining a high standard, we hope that the code will continue to be useful, understandable, and cohesive in nature. Please don't be offended if we ask you to modify the formatting of your code before approving a pull request.
Although we strive for complete in-code documentation, in practice this sometimes gets left behind for the sake of rapid development. If you, as a potential developer, find some portion of documentation unsatisfactory, we welcome questions on the appropriate GitHub issues page or forum, and encourage you to submit pull requests which improve documentation. Several new developers have started with first improving the documentation to get a handle on how things work.
"},{"location":"developer-guide/contribution-guidelines/#key-goals-of-rosflight","title":"Key Goals of ROSflight","text":"Here is a summary of the key goals and philosophies behind ROSflight. As you look to make contributions to the project, keep these in mind.
-
Only include the things that most people will need. The goal of this would be to do most of the work so people can get a MAV in the air quickly and easily, but not overcomplicate the code with features that only a small portion of users would need.
-
Be modular and adaptable for many research-centric use cases. This will be accomplished by putting the majority of the autopilot in a well-designed ROS2 framework. That which needs to be on the microcontroller will need to be done so carefully with good coding practices. Additionally, microcontroller code that is the most likely to be expanded upon should include clear interfaces and instructions for doing so.
-
Keep everything simple and well documented. The key goal here is to minimize the amount of time and effort it takes someone to go from knowing nothing about ROSflight to being able to implement their own features and making meaningful progress with their research.
"},{"location":"developer-guide/contribution-guidelines/#communication","title":"Communication","text":"There are two channels to communicate with the developer team. For bug reports, feature requests, and anything to do with code, please open an issue on the appropriate GitHub issue page. For questions and other discussions, please use the forum.
"},{"location":"developer-guide/style-guide/","title":"Style Guide","text":"The focus of anyone contributing to this project should be to write code that is easily understood by anyone, including people who have little experience with ROSflight or coding in general. So, we ask that contributions adhere to the following style guidelines.
"},{"location":"developer-guide/style-guide/#comments","title":"Comments","text":"Well written and clear code should be easy to understand even without comments. However, since this project is intended to be as accessible as possible, we ask that you write both clear code and clear comments. Don't use comments to explain code that would be difficult to understand without comments, but instead use them to make clear code even more understandable.
"},{"location":"developer-guide/style-guide/#doxygen","title":"Doxygen","text":"Doxygen comments should be added pretty much anywhere where it makes sense. Please include at least a brief for anything you write. For methods and functions, also include explanations of all arguments and the return value. More detailed explanations are encouraged for non-trivial methods and objects.
"},{"location":"developer-guide/style-guide/#white-space-and-line-endings","title":"White Space and Line Endings","text":"Please try not to commit anything that only changes white space or line endings. To check if that's going to happen, run git diff --check
before you stage your files.
"},{"location":"developer-guide/style-guide/#code-style","title":"Code Style","text":"ROSflight follows the ROS2 C++ style guide, with some more specific guidelines below. Please follow first the style guidelines below and then the ROS2 guidelines. A .clang-format file and format-correcting script is provided in most ROSflight repositories that can be used to auto-format your code to help you find things you might have missed. Format checks on pull requests using this .clang-format file may also exist.
"},{"location":"developer-guide/style-guide/#indentation","title":"Indentation","text":"Indentation should be 2 spaces (no tabs). Case statements in switch blocks should not be indented, e.g.
switch (variable)\n{\ncase 1:\n // do something\n break;\ndefault:\n break;\n}\n
"},{"location":"developer-guide/style-guide/#spaces","title":"Spaces","text":"There should be a space between if
, for
, or while
and the condition, e.g. while (true)
, not while(true)
.
"},{"location":"developer-guide/style-guide/#naming-conventions","title":"Naming Conventions","text":" - Class names should be capitalized with no spaces (i.e.
StateManager
). - Member variables should contain a post-pended underscore (i.e.
data_
). - Member functions should be all lower case with underscores (i.e.
set_error()
). - Boolean values should be assigned
true
or false
, not 0
or 1
.
"},{"location":"developer-guide/style-guide/#function-arguments","title":"Function Arguments","text":"Primitive data types (int
, float
, etc.) should always be passed by value. Other types (e.g. classes) should be passed by reference and should maintain proper const-correctness. Arguments that are modified by the function should be passed by pointer instead of reference, to make the fact that the argument will be changed clearer in the calling code. For example:
void do_something(float dt, const MyClass& data, int* output);\n
This function would be called as
float dt = 0.01f;\nMyClass my_class;\nint value;\n\ndo_something(dt, my_class, &value);\n
This makes it clear the value
is modified by the function call.
"},{"location":"developer-guide/style-guide/#classes","title":"Classes","text":"All modules should be defined as a self-contained class. All member variables should be declared as \"private,\" named with a post-pended underscore, and accessed through inline accessor functions. All accessible data should be encapsulated in a struct. For example, here is a snippet from the Sensors
module in the firmware:
class Sensors\n{\npublic:\n struct Data\n {\n vector_t accel = {0, 0, 0};\n vector_t gyro = {0, 0, 0};\n float imu_temperature = 0;\n uint64_t imu_time = 0;\n\n float diff_pressure_velocity = 0;\n float diff_pressure = 0;\n float diff_pressure_temp = 0;\n bool diff_pressure_valid = false;\n\n float baro_altitude = 0;\n float baro_pressure = 0;\n float baro_temperature = 0;\n bool baro_valid = false;\n\n float sonar_range = 0;\n bool sonar_range_valid = false;\n\n vector_t mag = {0, 0, 0};\n\n bool baro_present = false;\n bool mag_present = false;\n bool sonar_present = false;\n bool diff_pressure_present = false;\n };\n\n Sensors(ROSflight& rosflight);\n\n inline const Data & data() const { return data_; }\n\nprivate:\n Data data_;\n}\n
Note that data_
is a private member variable, but the Data
struct is declared publicly and data_
is accessed through an inline const
accessor to prevent another module from changing data_
.
"},{"location":"developer-guide/style-guide/#enums","title":"Enums","text":"Enums should be declared using the following style:
enum ArmedState\n{\n ARMED_STATE_INIT,\n ARMED_STATE_DISARMED,\n ARMED_STATE_ARMED\n};\n
The name of the enum should be in CamelCase, and the names of its members should be ALL_CAPS. Where practical, have the members of the enum begin with the name of the enum.
"},{"location":"developer-guide/style-guide/#structs","title":"Structs","text":"Structs should be declared using the following style:
struct SomeValue\n{\n int v1;\n int v2;\n};\n
Struct type names should be in CamelCase."},{"location":"developer-guide/style-guide/#globals","title":"Globals","text":"The use of global variables should be limited to when absolutely necessary (such as linking to interrupt routines or hardware peripherals). This should only occur in board support layers and not in the core ROSflight libary code.
"},{"location":"developer-guide/style-guide/#include-order","title":"Include Order","text":"Include files at the top of your file in the following order:
- Standard library (e.g.
<cstdint>
) - Files from external libraries included in the project (e.g.
<breezystm32/breezystm32.h>
, <mavlink/v1.0/common/mavlink.h>
) - Other header files from this project (e.g.
\"rosflight.h\"
) - The header file for this specific source file
Group the includes according to the above list with an empty line between each group. (For external libraries, you may subdivide group 2 into a group for each library.) The first two groups should use angle brackets (<>
), and the last two groups should use quotation marks (\"\"
). Files from external libraries should be namespaced by the library name (e.g. <breezystm32/breezystm32.h>
, not <breezystm32.h>
).
Alphabetize the files within each group. Do not change the include order to fix build errors; if you have to do that it means you are not including a file somewhere that you should. Please fix it by including all the right files.
Include C standard library headers using the C++ style (#include <cmath>
) instead of the C style (#include <math.h>
).
For example, in sensors.c
I might have:
#include <cstdbool>\n#include <cstdint>\n\n#include <breezystm32/breezystm32.h>\n#include <breezystm32/drv_mpu6050.h>\n\n#include \"param.h\"\n\n#include \"sensors.h\"\n
"},{"location":"developer-guide/style-guide/#namespacing","title":"Namespacing","text":"All modules should be encapsulated in a package namespace that is unique and consistent within the package (like rosflight_firmware
for anything in the firmware package).
"},{"location":"developer-guide/firmware/building-and-flashing/","title":"Building and Flashing the Firmware","text":"This guide assumes you are running Ubuntu 22.04 LTS, which is the currently supported development environment.
"},{"location":"developer-guide/firmware/building-and-flashing/#installing-the-arm-embedded-toolchain","title":"Installing the ARM Embedded Toolchain","text":"sudo apt install gcc-arm-none-eabi\n
You can test the installation and check which version is installed by running arm-none-eabi-gcc --version
.
"},{"location":"developer-guide/firmware/building-and-flashing/#building-the-firmware-from-source","title":"Building the Firmware from Source","text":"Now that we have the compiler installed, simply clone the ROSflight firmware repository, pull down the submodules, and build:
git clone --recursive https://github.com/rosflight/rosflight_firmware\ncd rosflight_firmware\nmkdir build \ncd build \ncmake .. -DBUILD_VARMINT=TRUE\nmake\n
"},{"location":"developer-guide/firmware/building-and-flashing/#flashing-newly-built-firmware","title":"Flashing Newly-Built Firmware","text":"TODO
Update this when hardware support is finalized.
First, make sure you have configured your computer as described in the Serial Port Configuration section of the user guide.
"},{"location":"developer-guide/firmware/building-and-flashing/#f4","title":"F4","text":"Flash the firmware to the board by running make BOARD=REVO flash
. If necessary, specify the serial port with make BOARD=REVO SERIAL_DEVICE=/dev/ttyACM0 flash
.
"},{"location":"developer-guide/firmware/code-architecture/","title":"Code Architecture","text":"The firmware is divided into two main components: the core library, and a collection of board implementations. This division is intended to allow the same core flight code to run on any processor or platform, either an embedded flight controller or a desktop environment for a software-in-the-loop (SIL) simulation. The interface between these two components is called the hardware abstraction layer (HAL). This architecture is illustrated in the following diagram:
"},{"location":"developer-guide/firmware/code-architecture/#firmware-core-library","title":"Firmware Core Library","text":"The firmware core library consists of all the code in the include
and src
directories of the firmware repository. This includes the code for what is termed the \"flight stack,\" which consists of the core components (such as the estimator, controller, state manager, etc.) required for flight. It also includes the interface definition for the hardware abstraction layer, which is defined by the abstract Board
class in include/board.h
. The communications link (MAVLink) is also abstracted, with the interface defined by the CommLink
class in include/comm_link.h
. External libraries are contained in the lib
folder.
"},{"location":"developer-guide/firmware/code-architecture/#board-abstraction","title":"Board Abstraction","text":"The hardware abstraction implementations are contained in the boards
directory, organized in subdirectories according to the hardware driver layer. Each board implementation is required to provide an implementation of the hardware abstraction layer interface, which is passed by reference to the flight stack. The Varmint implementation in the boards/varmint
shows how this is done for an embedded flight controller. Examples of board implementations for SIL simulation are found in the rosflight_sim
ROS2 package available here.
The flight stack is encapsulated in the ROSflight
class defined at include/rosflight.h
. This class contains two public functions: init()
and run()
. Its constructor requires two arguments: an implementation of the Board
interface, and an implementation of the CommLink
interface.
Each board implementation is required to implement the entire Board class.
"},{"location":"developer-guide/firmware/code-architecture/#comm-link-abstraction","title":"Comm Link Abstraction","text":"The purpose of the comm link abstraction layer is to allow communication protocols other than MAVLink to be used if desired. The comm link abstraction implementations are contained in the comms
directory, organized in subdirectories by protocol. The implementations translate between the messages that the firmware expects to send and receive, and the messages defined by the communication protocol. Currently, only MAVLink is implemented.
"},{"location":"developer-guide/firmware/code-architecture/#flight-stack","title":"Flight Stack","text":"The flight stack is encapsulated by the ROSflight
class defined in include/rosflight.h
. It consists of a collection of modules. Each of these modules is implemented as a C++ class, and encapsulates a cohesive piece of the autopilot functionality. The following diagram illustrates these modules and the data flow between them. Rectangular blocks represent modules in the flight stack, and ellipses represent hardware functionality implemented in the board support layer:
We'll describe each of these modules in the following sections:
"},{"location":"developer-guide/firmware/code-architecture/#state-manager","title":"State Manager","text":"This module is in charge of keeping track of the internal state (armed status, error codes, failsafe, etc.) of the vehicle. While only the comm manager data flow is illustrated on the diagram, all other modules query the state manager to determine the status and act appropriately based on that status.
The operation of the state manager is defined by the following finite state machine:
The state manager also includes functionality for recovering from hard faults. In the case of a hard fault, the firmware writes a small amount of data to backup memory then reboots. This backup memory location is checked and then cleared after every reboot. The backup memory includes the armed state of the flight controller. On reboot, the firmware will initialize then, if this armed-state flag is set, immediately transition back into the armed state. This functionality allows for continued RC control in the case of a hard fault. Hard faults are not expected with the stable firmware code base, but this feature adds an additional layer of safety if experimental changes are being made to the firmware itself.
"},{"location":"developer-guide/firmware/code-architecture/#parameter-server","title":"Parameter Server","text":"This module handles all parameters for the flight stack. It supports the getting and setting of integer and floating-point parameters, and the saving of these parameters to non-volatile memory. Setting and getting of parameters from the companion computer is done through the serial communication interface. While no other data flow lines are shown on the diagram, all of the other modules interact with the parameter server.
"},{"location":"developer-guide/firmware/code-architecture/#comm-manager","title":"Comm Manager","text":"This module handles all serial communication between the flight controller and companion computer. This includes streaming data and receiving offboard control setpoints and other commands from the computer. This module primarily collects data from the sensors, estimator, state manager, and parameters modules, and sends offboard control setpoints to the command manager and parameter requests to the parameter server.
The actual communication protocol used is abstracted by the interface in include/comm_link.h. A new protocol can be used by implementing a wrapper around the protocol that inherits from this interface. Currently, only MAVLink has been implemented. The implementation is found in comms/mavlink/mavlink.h and comms/mavlink/mavlink.cpp.
"},{"location":"developer-guide/firmware/code-architecture/#sensors","title":"Sensors","text":"This module is in charge of managing the various sensors (IMU, magnetometer, barometer, differential pressure sensor, sonar altimeter, etc.). Its responsibilities include updating sensor data at appropriate rates, and computing and applying calibration parameters.
"},{"location":"developer-guide/firmware/code-architecture/#estimator","title":"Estimator","text":"This module is responsible for estimating the attitude and attitude rates of the vehicle from the sensor data.
"},{"location":"developer-guide/firmware/code-architecture/#rc","title":"RC","text":"The RC module is responsible for interpreting the RC signals coming from the transmitter via the receiver. This includes mapping channels to their appropriate functions and reversing directions if necessary.
"},{"location":"developer-guide/firmware/code-architecture/#command-manager","title":"Command Manager","text":"The command manager combines inputs from the RC and comm manager modules to produce a control setpoint. Its main purpose is to handle the interaction between offboard commands and the RC safety pilot, as well as to enforce the failsafe command if the state manager reports failsafe mode.
"},{"location":"developer-guide/firmware/code-architecture/#controller","title":"Controller","text":"The controller uses the inputs from the command manager and estimator to compute a control output. This control output is computed in a generic form (x, y, and z torques, and force F), and is later converted into actual motor commands by the mixer.
"},{"location":"developer-guide/firmware/code-architecture/#mixer","title":"Mixer","text":"The mixer takes the generic outputs computed by the controller and maps them to actual motor commands depending on the configuration of the vehicle.
"},{"location":"developer-guide/firmware/debugging/","title":"Using an In-Circuit Debugger","text":"TODO
Update this when hardware support is finalized.
Debugging an STM32-based board is accomplished with an ST-LINK/V2 in-circuit debugger and programmer. We have had the best luck with the official version from STMicroelectronics. These devices are reasonably priced, and are available directly from STMicroelectronics or from vendors such as Digi-Key, Mouser, and Newark.
The following guide will show you how to get the in-circuit debugger running with either the Visual Studio Code or QtCreator IDE. Start with the steps in the General Setup section, then move on to either the VS Code or STM32cubeIDE sections depending on your choice of IDE.
This guide assumes you are running Ubuntu 22.04 LTS, which is the currently supported development environment.
"},{"location":"developer-guide/firmware/debugging/#general-setup","title":"General Setup","text":"Follow the guide in Building and Flashing to install the compiler toolchain.
Also make sure you have configured your computer as described in the Serial Port Configuration section of the user guide.
"},{"location":"developer-guide/firmware/debugging/#connect-debugger-to-flight-controller","title":"Connect debugger to flight controller","text":"The ST-LINK/V2 connects to the microcontroller using the Serial Wire Debug (SWD) interface. You will need to connect the GND
, NRST
, SWDIO
, and SWCLK
lines of the ST-LINK/V2 to your flight controller. On many F4 boards, these lines are pinned out through a 4-position JST SH connector, although that connector is not always populated. Refer to the documentation for your specific board for details.
The official ST-LINK/V2 also needs a target voltage reference on pin 1 or 2, which for the F4 boards is 3.3V. However, there is no externally accessible 3.3V pinout on the F4 boards. An easy solution to this is to connect pin 19 (VDD 3.3V) of the ST-LINK/V2 to pin 1 or 2 of the ST-LINK/V2 (Target VCC) to provide the voltage reference. You will also need to power the board from another source, either through the USB port or over the servo rail. Note that this connection is not required for the cheap clone versions of the ST-LINK/V2.
"},{"location":"developer-guide/firmware/debugging/#vs-code","title":"VS Code","text":"You can install Visual Studio Code by downloading the latest version from their website. Follow the steps below to configure debugging with the in-circuit debugger.
You should open the root firmware directory for editing and debugging, e.g. code /path/to/rosflight_firmware
.
"},{"location":"developer-guide/firmware/debugging/#install-openocd","title":"Install OpenOCD","text":"OpenOCD (On-Chip Debugger) is the software that will control the debugger. Install from the apt
repositories:
sudo apt install openocd\n
"},{"location":"developer-guide/firmware/debugging/#install-cortex-debug-extension","title":"Install Cortex-Debug extension","text":"The embedded debugging functionality is provided by the Cortex-Debug
extension. Install using the VS Code GUI, or from VS Code press Ctrl+P
then type ext install marus25.cortex-debug
.
Steps for configuring this extension are described next.
"},{"location":"developer-guide/firmware/debugging/#download-svd-file","title":"Download SVD file","text":"A System View Description (SVD) file describes the configuration (CPU, peripherals, registers, etc.) of the microcontroller. The Cortex-Debug extension can make use of an SVD file to provide more detailed debugging information, such as the ability to inspect register values.
SVD files can be downloaded from STMicroelectronics. The files for the F4 are contained in the ZIP file that can be downloaded here, and the relevant file is STM32F405.svd
. The files for the F1 are contained in the ZIP file that can be downloaded here, and the relevant file is STM32F103.svd
. Put those files in a convenient location.
"},{"location":"developer-guide/firmware/debugging/#configure-build-step","title":"Configure build step","text":"You can configure VS Code to run make
for you when you press Ctrl+Shift+B
. To do this, put the following in .vscode/tasks.json
inside your firmware working directory:
{\n // See https://go.microsoft.com/fwlink/?LinkId=733558\n // for the documentation about the tasks.json format\n \"version\": \"2.0.0\",\n \"tasks\": [\n {\n \"type\": \"shell\",\n \"label\": \"make\",\n \"command\": \"make\",\n \"args\": [\"DEBUG=GDB\"],\n \"group\": {\n \"kind\": \"build\",\n \"isDefault\": true\n }\n }\n ]\n}\n
Note that by default, this will only build the F4 (Revo) firmware. To build the F1 firmware, you will need to edit this to add the argument BOARD=NAZE
.
"},{"location":"developer-guide/firmware/debugging/#configure-debugging","title":"Configure debugging","text":"To configure in-circuit debugging of F4 and F1 targets, put something like the following in .vscode/launch.json
inside your firmware working repository:
{\n // Use IntelliSense to learn about possible attributes.\n // Hover to view descriptions of existing attributes.\n // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n \"version\": \"0.2.0\",\n \"configurations\": [\n {\n \"name\": \"STM32F405\",\n \"type\": \"cortex-debug\",\n \"request\": \"launch\",\n \"servertype\": \"openocd\",\n \"cwd\": \"${workspaceRoot}\",\n \"executable\": \"${workspaceRoot}/boards/airbourne/build/rosflight_REVO_Debug.elf\",\n \"device\": \"STM32F405\",\n \"svdFile\": \"/path/to/STM32F405.svd\",\n \"configFiles\": [\n \"interface/stlink-v2.cfg\",\n \"target/stm32f4x.cfg\"\n ],\n \"runToMain\": true\n },\n {\n \"name\": \"STM32F103\",\n \"type\": \"cortex-debug\",\n \"request\": \"launch\",\n \"servertype\": \"openocd\",\n \"cwd\": \"${workspaceRoot}\",\n \"executable\": \"${workspaceRoot}/boards/breezy/build/rosflight_NAZE_Debug.elf\",\n \"device\": \"STM32F103\",\n \"svdFile\": \"/path/to/STM32F103.svd\",\n \"configFiles\": [\n \"interface/stlink-v2.cfg\",\n \"target/stm32f1x.cfg\"\n ],\n \"runToMain\": true\n }\n ]\n}\n
Be sure to edit the values of \"svdFile\"
to point to the respective SVD files you downloaded earlier.
To start debugging, enter the debug pane in VS Code, select the desired configuration, then click the green arrow to start debugging. The shortcut key F5
will also launch the last-selected debug configuration.
More details on the configuration and use of the Cortex-Debug
extension can be found here and here.
"},{"location":"developer-guide/firmware/debugging/#stm32cubeide","title":"STM32cubeIDE","text":""},{"location":"developer-guide/firmware/unit-tests/","title":"Building and Running Unit Tests","text":"Contributions will need to pass our continuous integration unit tests before merging. To test your contributions against these tests, you'll first need to install Eigen and gtest:
sudo apt install build-essential libgtest-dev libeigen3-dev cmake\n
"},{"location":"developer-guide/firmware/unit-tests/#compile-gtest","title":"Compile gtest","text":"You just downloaded a bunch of source files, which you now have to go build
cd /usr/src/gtest\nsudo cmake CMakeLists.txt\nsudo make\n
Copy the archive files you just built to the /usr/lib
directory so CMake can find them later:
sudo cp ./lib/libgtest*.a /usr/lib\n
"},{"location":"developer-guide/firmware/unit-tests/#run-the-test-script","title":"Run the Test Script","text":"The simplest way to run the unit tests is to use the testing script. This script first checks that the firmware compiles, then runs the unit tests. This is the same script used on the continuous integration server, so this is a great way to check that your code will pass the tests before opening a pull request. Run the test script with
cd <firmware_directory>\n./scripts/run_tests.sh\n
"},{"location":"developer-guide/firmware/unit-tests/#manually-build-and-run-the-unit-tests","title":"Manually Build and Run the Unit Tests","text":"If you want to manually build and run the unit tests, first build them with the following commands:
cd <firmware_directory>\nmkdir build\ncd build\ncmake .. -DBUILD_TEST=TRUE\nmake\n
Then run them with:
./test/unit_tests\n
"},{"location":"developer-guide/rosplane/parameter-management/","title":"Parameter Management","text":""},{"location":"developer-guide/rosplane/parameter-management/#overview","title":"Overview","text":"In ROSplane, all internal variables are represented as ROS2 parameters. This enables easy loading, tuning, and saving parameters of various ROSplane modules without needing to rebuild. ROS2 parameters can also be changed dynamically, enabling live editing and tuning of the system.
For a good introduction to ROS2 parameters and the CLI tools, see the ROS2 parameter CLI documentation. For an introduction to the parameter system using the ROS2 client libraries, see ROS2 parameter client libraries documentation.
"},{"location":"developer-guide/rosplane/parameter-management/#parameter-manager-class","title":"Parameter Manager class","text":"A param_manager
class has been created to manage the ROS interface required when dealing with parameters. Specifically, a param_manager
object handles the declaration and updates of parameters. Since a base class publicly owns the param_manager
, derived classes will have access to any parent class's parameters, if needed. This also allows derived classes to define parameters close to where they will be used in the derived class, helping with readability.
For example, the controller_base
class declares a frequency
variable, which defines the rate of the control loops. This same parameter is needed in other derived classes, like the controller_successive_loop
class. Since we declare the parameter in the controller_base
class, the controller_successive_loop
class will have access to the frequency
parameter without having to redefine it.
"},{"location":"developer-guide/rosplane/parameter-management/#usage","title":"Usage","text":""},{"location":"developer-guide/rosplane/parameter-management/#declaration","title":"Declaration","text":"To use the param_manager
to define your own parameters, do the following:
- Declare an instance of
param_manager
in your class, or ensure that a parent class has a public or protected instance of param_manager
. - Initialize the
param_manager
object with a pointer to the ROS2 node object associated with the parameters. - In the constructor, use
param_manager::declare_param(std::string <PARAM_NAME>, <PARAM>)
to declare parameters of type double, bool, or string, where <PARAM>
is the default value for the parameter. - Use
param_manager::declare_int(std::string <PARAM_NAME>, <PARAM>)
to declare an integer parameter.
- In the constructor, use
param_manager::set_parameters()
to load any parameters that have changed on launch to the param_manager
object.
Note
The param_manager::set_parameters()
call is important when a node is loaded with parameters from a file on launch. Not making this call will mean that the parameters stored in the param_manager
object are out of sync with the ROS2 parameters.
These steps will register your parameters with ROS2, allowing you to change them dynamically or load them from a launch file.
"},{"location":"developer-guide/rosplane/parameter-management/#using-parameters-in-code","title":"Using parameters in code","text":"After declaring the parameters with param_manager::declare_param
or param_manager::declare_int
, you need to allocate variables in your code to hold the values of the parameters. Get the parameter value by using the appropriate function call:
param_manager::get_double(std::string <PARAM_NAME>)
param_manager::get_bool(std::string <PARAM_NAME>)
param_manager::get_string(std::string <PARAM_NAME>)
param_manager::get_int(std::string <PARAM_NAME>)
Note that the return type of param_manager::get_int
is int_64
, since that is how ROS2 internally stores integers.
"},{"location":"developer-guide/rosplane/parameter-management/#defining-parameters-with-a-parameter-file","title":"Defining parameters with a parameter file","text":"We recommend using a YAML file to hold all of the parameters for a given node. This file can be loaded at launch time so that all parameters are updated with the values in the launch file. This means you don't have to change the default values in code (which would require a rebuild) to make sure a node gets launched with the correct values.
To do this, add the parameters=[\"/path/to/parameter/file\"]
to a node's launch argument. See rosplane.launch.py
for an example.
"},{"location":"developer-guide/rosplane/parameter-management/#updating-parameters","title":"Updating Parameters","text":"Parameters can be updated from the command line using normal ROS2 commands. See the ROS2 parameter CLI tools documentation for more information on how to interface with these parameters from the command line.
Note
Be sure to create a callback for your parameter changes, especially if you use a param_manager
object. ROS2 will send a list of changed parameters to this callback when the parameters are changed, allowing you to update the internally stored value in the param_manager
. Otherwise, your internally stored values will be out of sync with the ROS2 parameters, and it will likely not function correctly. See the controller_base
or estimator_base
or path_planner
code for an example of the callbacks.
"},{"location":"developer-guide/rosplane/controller/controller-base/","title":"Controller Base","text":""},{"location":"developer-guide/rosplane/controller/controller-base/#overview","title":"Overview","text":"The controller base implements the basic ROS interfaces for the controller. This includes setting up subscribers, publishers and initializing parameter management. The idea of the base class, is that all interfacing with ROS and shared resources across all inheritance levels happens or are contained in this class.
"},{"location":"developer-guide/rosplane/controller/controller-base/#ros-interfaces","title":"ROS interfaces","text":"The controller base has the following ROS interactions.
Figure 1: Controller's ROS interactions. The controller has four ROS interfaces that are tracked as member variables of the class. These interfaces are the only points of contact that influence the every layer of the controller along side the node parameters. Each of the callbacks for the subscribers are also contained in controller_base
.
ROS Interface Topic Explanation Message Type actuators_pub_
/command
Publishes the acutator commands for the aircraft. The publishing rate is controller by the timer_
object. Command.msg internals_pub_
/controller_inners_debug
Publishes the intermediate values created by the outer control loops. Published simultaneously as the commands when there is at least one subscriber to the topic. ControllerInnersDebug.msg controller_commands_sub_
/controller_commands
Subscribes to the commands for the controller. ControllerCommands.msg vehicle_state_sub_
/estimated_state
Subscribes to the estimated state of the aircraft. State.msg Note
The command message is from the rosflight_msgs
package not the rosplane_msgs
package.
"},{"location":"developer-guide/rosplane/controller/controller-base/#parameter-management","title":"Parameter Management","text":"See the Parameter Management page for more details on how parameter management works.
"},{"location":"developer-guide/rosplane/controller/controller-base/#list-of-parameters","title":"List of Parameters","text":"Parameter Explanation Range pwm_rad_e Radian to PWM conversion for the elevator. \\geq 1.0 (double) pwm_rad_a Radian to PWM conversion for the ailerons. \\geq 1.0 (double) pwm_rad_r Radian to PWM conversion for the rudder. \\geq 1.0 (double) frequency Frequency of the timer, effective control loop closure frequency. \\geq 100 (hertz, int)"},{"location":"developer-guide/rosplane/controller/controller-base/#modifying-controller-base","title":"Modifying Controller Base","text":"The controller_base
class should only contain things that are necessary for each layer of the controller. If you are considering adding something to the controller, but it only applies to one layer, perhaps reconsider. All ROS related items should also be stored here. For example, if you needed to use another topic subscription, the new subscriber should be created and stored in controller_base
.
As shown in the Controller Software Architecture page, you may need to modify the main
function in controller_base.cpp
to use a newly implemented controller.
"},{"location":"developer-guide/rosplane/controller/controller-general-overview/","title":"ROSplane Controller","text":""},{"location":"developer-guide/rosplane/controller/controller-general-overview/#overview","title":"Overview","text":"The ROSplane controller generates the controller commands to achieve the commanded states that the path follower directs. The controller has the basic function of controlling roll, pitch, yaw, airspeed, course and altitude. Higher functions of controlling position and tracking paths is handled by other nodes, the path follower and manager specifically. To gain the best understanding of the Controller and its role, read chapter 1 of the UAV book, or the ROSplane Overview page.
"},{"location":"developer-guide/rosplane/controller/controller-general-overview/#interfaces","title":"Interfaces","text":"Figure 1: Controller's ROS interactions."},{"location":"developer-guide/rosplane/controller/controller-general-overview/#input","title":"Input","text":"The controller receives controller commands using the ControllerCommands message on the \\controller_commands
topic from the path_follower
node. This set of commands are outlined below, along with a short explanation of each.
Message Field Explanation Units header This contains time stamp information. Time in Seconds and Nanoseconds (int) va_c The commanded airspeed. Meters per second (float) h_c The commanded altitude. Meters (float) chi_c The commanded course. Radians (float) phi_ff Feedforward roll term (for orbits) Radians (float) aux[4] Four array of auxiliary commands None (float) aux_valid Indicates whether aux vector contains actual information. True/False (bool) The controller uses these targets to control the aircraft. This drives the aircraft to approach and follow the path as the path_follower commands. See the Path Follower page for more information. See the Successive Loop Closure Controller Outline for more information on how these commands are used specifically.
Note
Poor path performance may be due to controller or the path follower, see the Tuning Guide in the User Guide section for more details.
"},{"location":"developer-guide/rosplane/controller/controller-general-overview/#output","title":"Output","text":"The controller calculates the control surface outputs in percent deflection (based around zero) and throttle. It formats and the publishes these outputs in the Command message on the /command
topic. There are a further four auxiliary channels that can be used in the Command message, however they are unused typically. A summary of the parts of the command message are as follows.
Message Field Explanation Units header This contains time stamp information. Time in Seconds and Nanoseconds (int) mode The control mode (used in multi-rotors) None (int) ignore A bitmask to ignore particular values. None (int) x Aileron Command Percent deflection in direction [-1.0, 1.0] (float) y Elevator Command Percent deflection in direction [-1.0, 1.0] (float) z Rudder Command Percent deflection in direction [-1.0, 1.0] (float) f Throttle Command Percent of full throttle [0.0, 1.0] (float) These are passed to rosflight_io
, which formats them into MAVLink messages and forwards them onto the FCU.
Note
For this to work the parameters on the rosflight_firmware
must be set to work for an airplane. See the User Guide on first time start up or README.md for the repository for more details on firmware setup.
"},{"location":"developer-guide/rosplane/controller/controller-general-overview/#running-the-controller","title":"Running the Controller","text":"As mentioned in the ROSplane ROS overview, the controller is in the main rosplane
ROS package. The ROS executable is rosplane_controller
, yielding the run command:
ros2 run rosplane rosplane_controller
The type of controller used is passed right after the executable name, substitute control_type
for controller being used.
ros2 run rosplane rosplane_controller control_type
To pass a set of parameters for the controller from a yaml file using the --ros-args
option.
ros2 run rosplane rosplane_controller --ros-args --params-file path/to/params.yaml
Putting it all together,
ros2 run rosplane rosplane_controller control_type --ros-args --params-file path/to/params.yaml
A table of arguments and parameter files that work out of the box is given in the following table.
Note
Filepaths will need to be altered to work.
Note
The most common way of running the controller is in through a launch file with the rest of the ROSplane pipeline running as well. See the ROSplane Overview in the Developer and User Guides for more details.
Argument Explanation Values --params-file The parameters file that contains the gains and other important parameters. rosflight_ws/src/rosplane/rosplane/params/anaconda_autopilot_params.yaml
,rosflight_ws/src/rosplane/rosplane/params/skyhunter_autopilot_params.yaml
control_type These arguements are passed directly to the main function defined in the controller. default
, total_energy
"},{"location":"developer-guide/rosplane/controller/controller-outline/","title":"Successive Loop Closure Controller","text":""},{"location":"developer-guide/rosplane/controller/controller-outline/#overview","title":"Overview","text":"The control scheme used by default in ROSplane comes from the book Small Unmannded Aircraft: Theory and Practice by Randal Beard and Timothy McLain. A full and in depth description of the theory behind this controller is outlined in chapter 6. Additionally, many simplifing assumptions are made some of which will be mentioned, but the rationale not explored. These too are found in the book, in chapters 3, 4 and 5. A link to the most up to date book can be found on the GitHub page for the book. This section of the documentation is to briefly outline the important, practical parts of the controller to be useful in understanding how to tune or modify the existing code or algorithm for a developer. A good primer on PID control can be found here.
The control algortihm is split into two parts: Lateral-directional Autopilot and Longitudinal Autopilot. The lateral and longitudinal dynamics are assumed to be decoupled as discussed in Section 6.1 of Small Unmannded Aircraft. This allows us to develop a controller for each set of dynamics to simplify the controller design.
"},{"location":"developer-guide/rosplane/controller/controller-outline/#successive-loop-closure","title":"Successive Loop Closure","text":"For a full discussion of PID successive loop closure, which is used heavily through out the entire controller, read section 6.1 in the book. One major assumption used is that the inner loops are much faster (more than ten times faster) than the outer loops. This means that the bandwidth seperation should be seperated by a factor of 10. See end of section 6.1.1 Course Hold using Commanded Roll in the book for a more thorough discussion. A significant advantage of successive loop closure is that gains are tuned independently. Starting from the inner loops, tune the response and then tune the outer loop.
"},{"location":"developer-guide/rosplane/controller/controller-outline/#nomenclature","title":"Nomenclature","text":"Symbol Meaning Range \\large{\\boldsymbol{\\chi}} Course/Heading [-\\pi,\\pi) \\large{\\boldsymbol{\\phi}} Roll [-\\pi,\\pi) \\large{\\boldsymbol{\\theta}} Theta [-\\pi,\\pi) \\large{\\boldsymbol{\\psi}} Yaw [-\\pi,\\pi) \\large{\\boldsymbol{h}} Altitude \\large{p} Roll Rate \\large{q} Pitch Rate \\large{r} Yaw Rate \\large{V_a} Airspeed \\large{\\boldsymbol{\\delta_i}} Command percent defelection of control surface i [-1.0,1.0] \\large{\\boldsymbol{e_a}} Error in state variable a \\large{\\boldsymbol{a^c}} Commanded value of state variable a \\large{\\boldsymbol{k_{p_{a}}}} Proportional gain for state variable a \\large{\\boldsymbol{k_{d_{a}}}} Derivative gain for state variable a \\large{\\boldsymbol{k_{i_{a}}}} Integral gain for state variable a \\large{\\boldsymbol{p_{wo}}} Washout filter bandwidth \\large{\\boldsymbol{P}} Plant transfer function \\large{\\boldsymbol{s}} Laplace operator"},{"location":"developer-guide/rosplane/controller/controller-outline/#lateral-directional-autopilot","title":"Lateral-directional Autopilot","text":"The autopilot uses induced roll to control changes in course. The Lateral-directional Autopilot also uses a yaw damper to damp the dutch roll mode that can be induced by changes in roll.
"},{"location":"developer-guide/rosplane/controller/controller-outline/#course-loop","title":"Course Loop","text":"In figure 1, the entire control loop for the course is shown. This loop allows for tracking of ramp and step commands in course. Since the inner loop is tuned first and influences the outer loop tune, we will discuss it first.
Figure 1: Lateral-directional Autopilot Control Loop"},{"location":"developer-guide/rosplane/controller/controller-outline/#inner-loop","title":"Inner Loop","text":"The inner loop calculates the required percent deflection in the ailerons, \\boldsymbol{\\delta_a}, to acheive the commanded roll angle generated by the outer loop. This loop is a PD loop, meaning that it uses only a proportional and derivative control.
Note
That the derivative gain does not act on the rate of change of the error but of the direct roll rate, p.
The proportional gain acts on the error given by the estimated roll and the commanded roll. This loop does not use integral contol to ensure that it closes much faster than the outer loop. This bandwidth seperation helps the controller perform smoothly. See the specific page on the Course Loop for details on tuning and common pitfalls. For more details on how the roll rate and the roll angle are calculated, see the Estimator page. The output for the inner loop is routed into the outer loop.
"},{"location":"developer-guide/rosplane/controller/controller-outline/#outer-loop","title":"Outer Loop","text":"The outer loop calculates the commanded roll angle, \\boldsymbol{\\phi}, based on the error in the course, \\boldsymbol{\\chi}. This is a PI loop, meaning that it uses only proportional and integral control. The proportional gain acts on the error between the estimated course \\boldsymbol{\\chi} and the commanded course \\boldsymbol{\\chi}. The integral gain acts on the same error, ensuring that errors in course are driven to zero.
Note
The PI loop allows for only constant error in ramp inputs (orbits) and for no error to step inputs (path following commands).
See the specific page on the Course Loop for details on tuning and common pitfalls. For more details on how course is estimated and measured, see the Estimator page. These loops combine to give complete control of the course of the aircraft.
"},{"location":"developer-guide/rosplane/controller/controller-outline/#yaw-damper","title":"Yaw Damper","text":"The yaw damper allows for effective damping of undesirable yaw modes induced by rolling. This is done by using the rudder to control the yaw rate, r, to zero. Not all yaw rates should be controlled to zero since this would disallow turning. A washout filter is used to only damp high frequency yaw rates. In effect, this control only 'turns on' if the frequency of the yaw rate is high enough. For mor information see the Yaw Damper page.
Figure 2: Yaw Damper Control Loop"},{"location":"developer-guide/rosplane/controller/controller-outline/#longitudinal-autopilot","title":"Longitudinal Autopilot","text":"The longitudinal autopilot controls the longitudinal dynamics of the aircraft. This means that the loop controls altitude, pitch and airspeed.
"},{"location":"developer-guide/rosplane/controller/controller-outline/#altitude-loop","title":"Altitude Loop","text":"The altitude loop utilizes successive loop closure to control altitude. It uses the elevator to control the pitch of the aircraft, and then controls using commanded pitch the altitude. This loop can track step and ramp commands.
Figure 3: Altitude Control Loop"},{"location":"developer-guide/rosplane/controller/controller-outline/#inner-loop_1","title":"Inner Loop","text":"The inner loop controls the pitch, \\boldsymbol{\\theta}. It does so by calculating the necessary \\boldsymbol{\\delta_e} to acheive the commanded pitch. This is a PD loop, this means that there is often a small DC offset to the commanded pitch. This does not affect the performance of the overall altitude loop. Like the inner loop of the course control, the derivative gain acts on the measured pitch rate rather than the error derivative.
"},{"location":"developer-guide/rosplane/controller/controller-outline/#outer-loop_1","title":"Outer Loop","text":"The outer loop is a PI loop. It uses the error in the altitude, h, and integral of the error of altitude to drive the error to zero for steps and for ramps. The commanded altitude is capped using a scheme described in the Altitude Loop page. In practice, the altitude loop is often slower when the commanded altitude is descending and faster when ascending. This is because the airspeed is coupled to the altitude. While descending the controller will attempt to maintain airspeed. This can also result in more overshoot while descending.
"},{"location":"developer-guide/rosplane/controller/controller-outline/#airspeed-loop","title":"Airspeed Loop","text":"The Airspeed loop is a PI loop. It reacts to the straight forward error in commanded airspeed V_a^c given by the waypoint mission. It generates the required throttle, \\delta_t, to acheive the commanded airspeed. This is suffecient because of the natural damping of the drag on the aircraft. In practice, the loop performs well, but is prone to small fluctuations (on the order of \\pm 1 \\frac{m}{s}) due to the differential pressure sensor fluctuating because of wind and other disturbances.
Figure 4: Airspeed using throttle control loop"},{"location":"developer-guide/rosplane/controller/controller-outline/#controller-outputs","title":"Controller Outputs","text":"What the entire controller outputs is a set of 4 control efforts that correspond to the 4 major control surfaces on the aircraft. These are the elevator, ailerons, rudder and the throttle. The controller can easily be switched to outputing up to 8 outputs, using the aux channels of the Commands Message. These outputs are fed directly to rosflight_io and then passed along to the microcontroller and finally actuated on the physical or simulated aircraft. The controller is the exposed portion of ROSplane to ROSflight.
"},{"location":"developer-guide/rosplane/controller/controller-outline/#important-notes","title":"Important Notes","text":"The controller does not directly control the position. In the ROSplane overview page, it shows how the Path Follower feeds into the controller. The Path Follwer generates commands that result in the position control of the aircraft. For a better understanding of this realtionship visit the Path Follower page.
"},{"location":"developer-guide/rosplane/controller/controller-outline/#software-architecture","title":"Software Architecture","text":"The Successive Loop Closure Controller (SLCC) inherits from the state machine class, (see Software Architecture for more details) and implements the state function for each of the states. This state function is then populated with the desired control during each phase of flight (see State Machine for more details on control during each state). The state functions split control into longitudinal and lateral control, this allows for inheritance of this class an only override longitudinal or lateral control (see Total Energy Control for an example of how this is done).
Figure 5: An example of an implementation of a state function, in this case the altitude hold state. The lateral and longitudinal control functions activate particular control loops necessary.
Figure 6: An example of an implementation of a lateral and longitudinal control, in this case during the altitude hold state. Each control loop gets its own function and it follows a specific format. This format is pictured below, but a full outline is given in the .cpp file for the SLCC.
Note
All of the PID is implemented but the gains if not using a particular control (proportional/derivative/integral) are zero.
Figure 7: An example of an implementation of a control loop, in this case the roll loop (inner course loop)."},{"location":"developer-guide/rosplane/controller/controller-outline/#parameters","title":"Parameters","text":"These values are typically held in a .yaml file. For the default values, check the .cpp file.
Parameter Explanation Range max_takeoff_throttle Trottle saturation level during the takeoff zone. (0.0, 1.0) (double) c_kp The proportional gain on the outer course loop. \\geq 0.0 (double) c_kd The derivative gain on the outer course loop. \\leq 0.0 (double) c_ki The integral gain on the outer course loop. \\geq 0.0 (double) max_roll Commanded roll saturation limit. \\geq 0.0 (double)(degrees) cmd_takeoff_pitch Commanded pitch while in takeoff state. \\geq 0.0 (double)(degrees) r_kp The proportional gain on the inner course loop. \\geq 0.0 (double) r_kd The derivative gain on the inner course loop. \\geq 0.0 (double) r_ki The integral gain on the inner course loop. \\geq 0.0 (double) max_a Saturation limit for the ailerons \\geq 0.0 (double) trim_a Trim value for the ailerons. \\geq 0.0 (double) a_kp The proportional gain on the outer altitude loop. \\geq 0.0 (double) a_kd The derivative gain on the outer altitude loop. \\geq 0.0 (double) a_ki The integral gain on the outer altitude loop. \\geq 0.0 (double) max_pitch Commanded pitch saturation limit. \\geq 0.0 (double)(degrees) p_kp The proportional gain on the inner altitude loop. \\leq 0.0 (double) p_kd The derivative gain on the inner altitude loop. \\leq 0.0 (double) p_ki The integral gain on the inner altitude loop. \\leq 0.0 (double) max_e Saturation limit for the elevator \\geq 0.0 (double) trim_e Trim value for the elevator. \\geq 0.0 (double) y_pwo The yaw damper washout filter cutoff frequency. \\leq 0.0 (double)(radians/s) y_kr Control gain on yaw damper. \\leq 0.0 (double) a_t_kp The proportional gain on the airspeed loop. \\geq 0.0 (double) a_t_kd The derivative gain on the airspeed loop. \\geq 0.0 (double) a_t_ki The integral gain on the airspeed loop. \\geq 0.0 (double) max_t Saturation limit for the throttle. \\geq 0.0 (double) trim_t Trim value for the throttle. \\geq 0.0 (double) tau Dirty derivative low pass filter gain for airspeed. \\geq 0.0 (double)"},{"location":"developer-guide/rosplane/controller/controller-software-architecture/","title":"Controller Software Architecture","text":""},{"location":"developer-guide/rosplane/controller/controller-software-architecture/#overview","title":"Overview","text":"The controller makes use of inheritance to make the controller more modular. This creates a hierarchy of classes that each take on a responsibility. This means that a user that modifies the controller only has to inherit from a particular class make the modifications only to the portions of the code that matter to them, and then continue to use the other parts of the controller. An example of this is provided in the code. The total energy controller exemplifies this by inheriting and only changing just a few key functions. The aim of this architecture is to make the developer's job easier.
"},{"location":"developer-guide/rosplane/controller/controller-software-architecture/#inheritance-scheme","title":"Inheritance Scheme","text":"The controller starts off with the controller_base
class. This contains all of the interface with ROS. The next layer, controller_state_machine
, implements a basic state machine for the controller. These states control which commands are happening at what time. An example of how this may be used is, ensuring the aircraft is at altitude before attempting major maneuvers. Following the state machine is the actual control scheme. By default we use a successive loop closure scheme, controller_successive_loop
. This layer calculates the control errors and necessary actuator deflections to track commands.
Figure 1: Controller class inheritance structure.
This scheme was chosen to limit code duplication. A composition structure would have resulted in code duplication between controllers. Guides on how and where to modify each part of this structure can be found on the respective pages in the Developer Guide. This page does go over the basics of how to implement a controller changes in terms of overall architecture.
"},{"location":"developer-guide/rosplane/controller/controller-software-architecture/#implementing-a-new-controller","title":"Implementing A New Controller","text":"Figure 2: Options for implementing a new controller. The total energy controller in the rosplane
package, shows in a practical way how to implement a new controller. This section is meant to only give a high level overview of how this can be done. The first step is to identify where your changes should be made. This means determining which class the change belongs in. Consult the class pages for more information on where the best fit for your controller would be. The next step is to define a new class that inherits from class you are changing. Override the functions of interest. Next if the inherited class is not at the bottom of the inheritance chain, you will have to modify (duplicate but only change the inheritance, this is to not break default behavior) the controller classes further down the chain to inherit from your class rather than the original. This is to avoid a multiple inheritance problem (inheritance diamond).
To add your new controller as an option to be launched you will need to make a few edits. To be clear, you add your new final controller, (new_controller
or copy_of_controller
in the diagram) as an option. These edits are as follows:
- Add new controller to the CMakeLists.txt.
- The best examples are found in the CMakeLists.txt.
- Be sure to include the
.cpp
files.
Figure 3: Location in CMakeLists.txt
to add the new controller's .cpp
file(s).
- First import the new controller by adding its header file to
controller_base.cpp
.
Figure 4: Location in controller_base.cpp
to import new controller's header file.
- Next you need to add the new controller as an option to the
main
function. The argument to the main function is the name/activation string for the control. This is passed in on launch of ROSplane (see Launching ROSplane in the User Guide for more details).
Figure 5: Location in controller_base.cpp
to add option to select control type.
If this is done correctly, then you should be able to simply change between control schemes with only an argument to a launch file. This will allow for easier testing where you can use a more tested controller initially and but swap to a new controller when convenient.
"},{"location":"developer-guide/rosplane/controller/controller-state-machine/","title":"Controller State Machine","text":""},{"location":"developer-guide/rosplane/controller/controller-state-machine/#state-machine-overview","title":"State Machine Overview","text":"The controller state machine uses discrete states to turn on and off particular controls for a more stable flight. These regimes are designed so that particular mission objectives are only activated when particular conditions are met. In the default implementation this is controlled based on the aircraft's altitude. Though, in practice these states could be effected by any input from a ROS topic. The states are pictured below, and the differences in state are explored in the next section.
Figure 1: Controller state machine."},{"location":"developer-guide/rosplane/controller/controller-state-machine/#states","title":"States","text":"This section describes all of the states and what control is active during that phase of flight.
"},{"location":"developer-guide/rosplane/controller/controller-state-machine/#takeoff","title":"Takeoff","text":"In the takeoff state, the commanded airspeed is set to cruise, the commanded pitch is held constant and roll is controlled to zero. This results in a steady takeoff directly along the runway. The deactivation of course control means that the aircraft will not attempt to maneuver while too close to the ground. The takeoff regime is only below a certain cutoff altitude. After passing this threshold it moves into the climb state.
"},{"location":"developer-guide/rosplane/controller/controller-state-machine/#climb","title":"Climb","text":"The climb state commands altitude and airspeed as normal, but still controls roll to zero. This means that the aircraft will proceed directly ahead until it is withing a cutoff (see Params section) of commanded altitude. Deactivating course control allows for the aircraft to gain enough altitude to be clear of all obstacles before attempting to follow the waypoint mission. Once within a cutoff of the commanded altitude, the state transitions to altitude hold. If the aircraft dips beneath the takeoff threshold, it will enter the takeoff state again.
"},{"location":"developer-guide/rosplane/controller/controller-state-machine/#altitude-hold","title":"Altitude Hold","text":"In altitude hold all control loops are closed normally. The aircraft will fly the waypoint mission as normal. If the aircraft dips beneath the takeoff cutoff, the state transitions to takeoff again.
"},{"location":"developer-guide/rosplane/controller/controller-state-machine/#code-architecture","title":"Code Architecture","text":"The state machine's architecture allows for different aspects of the control to be modified. It simply defines a virtual method to be implemented by a child that will control during the particular state the aircraft is in. The state method is implemented in the child, only using the controls necessary for that phase of flight (see the Architecture section of the Successive Loop Closure).
Figure 2: Code snippet from the state machine."},{"location":"developer-guide/rosplane/controller/controller-state-machine/#parameters","title":"Parameters","text":"Parameter Explanation Range alt_toz The altitude of the takeoff zone cutoff. \\geq 0.0 (double) alt_hz The altitude command saturation limit, and difference required to transition into altitude hold. \\geq 0.0 (double)"},{"location":"developer-guide/rosplane/controller/controller-total-energy/","title":"Total Energy Controller","text":""},{"location":"developer-guide/rosplane/controller/controller-total-energy/#overview","title":"Overview","text":"The total energy control system approach (TECS) differs from the successive loop closure controller in its control of airspeed and altitude. It does this by calculating the total energy of the system, both potential and kinetic and controlling it to the desired energy. A more in depth treatment of of TECS see Section 6.2 in the UAV book.
The TECS controller has been included in ROSplane not only to provide control of the aircraft but to also demonstrate how to easily modify the controller (see Software Architecture and the following section for more details). The TECS controller calculates the desired kinetic and potential energy, using references from the commanded airspeed and altitude. It then calculates the current kinetic and potential energies and finds the kinetic and potential errors. It combines these errors, and the throttle control loop uses a PI loop to drive this total energy error to zero. The energy errors are also used to find a balance error. This is the error in the ratio of potential to kinetic energy. Pitch is then controlled by a PI loop to drive the balance error to zero. Essentially the throttle allows for the total energy to rise as it adds or allows drag to subtract energy from the system. The pitch loop controls how much of that input energy is in potential versus kinetic energy
This approach can have advantages because it deals with the coupling of airspeed and altitude. In the successive loop closure controller (SLCC), it assumes a decoupling of airspeed and altitude which can present tuning issues, though they are not insurmountable.
"},{"location":"developer-guide/rosplane/controller/controller-total-energy/#software-architecture","title":"Software Architecture","text":"The TECS controller provides an excellent template on implementing a new controller. Since the changes to the total energy controller are only in the longitudinal control and the rest are the same as the SLCC it inherits directly from controller_successive_loop
and only overrides the longitudinal functions for each state.
Figure 1: Total Energy Controller's overriden longitudinal control for the altitude hold state."},{"location":"developer-guide/rosplane/controller/controller-total-energy/#parameters","title":"Parameters","text":"Parameter Explanation Range e_kp Total energy error proportional gain, used in throttle control. \\geq 0.0 (double) e_ki Total energy error integral gain, used in throttle control. \\geq 0.0 (double) e_kd Total energy error derivative gain, used in throttle control. \\geq 0.0 (double) l_kp Balance energy error proportional gain, used in throttle control. \\geq 0.0 (double) l_ki Balance energy error integral gain, used in throttle control. \\geq 0.0 (double) l_kd Balance energy error derivative gain, used in throttle control. \\geq 0.0 (double) mass The mass of the aircraft, allowing for calculation of energies. \\geq 0.0 (double)(kg) gravity The gravity experienced by the aircraft, allowing for calculation of potential energy. \\geq 0.0 (double)(\\frac{m}{s}) max_alt_error This is the maximum error in altitude that the total energy loop will use to calculate energy error. \\geq 0.0 (double)(meters)"},{"location":"developer-guide/rosplane/navigation/navigation-overview/","title":"Navigation Overview","text":"The path planning methods used in ROSplane is modeled after the architecture presented in Small Unmanned Aircraft: Theory and Practice by Dr. Randal Beard and Dr. Tim McLain.
In their work, the path planning functionality of the aircraft is split into three main parts, as shown in Figure 1.
Note
This is not a full description of the architecture. For example, the state estimator is not shown, and not all of the inputs to each of the blocks is included. These elements were removed from the figure for simplicity.
Figure 1: Path planning architecture - based on Figure 1.1 in Small Unmanned Aircraft: Theory and Practice The high-level path planning is done by the path planner node. The path planner's job is to manage, create, and publish waypoints. Those waypoints are published to the path manager node. The path manager's job is to determine and calculate the appropriate line segments and orbits needed to complete the waypoints. The path manager then publishes these straight lines and waypoints to the path follower. The job of the path follower is to control the course, airspeed, and altitude of the aircraft to follow these lines and orbits.
For more information on each of these nodes, see the related documentation pages for the path planner, the path manager, and the path follower. See also chapters 10-13 of the Small Unmanned Aircraft: Theory and Practice book.
"},{"location":"developer-guide/rosplane/navigation/navigation-overview/#changing-the-navigation-stack","title":"Changing the Navigation Stack","text":"The path planner currently takes in a set of user-defined waypoints and follows those waypoints. This is not useful in all contexts, since in many applications the aircraft needs to take in sensor data and create its own waypoints and paths.
For example, we could replace the path planner block with a vision-based guidance block. The vision-based-guidance block would make decisions based on visual data to create waypoints. However, the interface between the path planner (now the visual-based guidance planner) and the path manager would remain the same.
Similarly, the path manager could be adjusted to follow b-splines instead of straight lines and orbits as currently implemented, without affecting the general waypoint management (path planner) or the underlying path following control loops (path follower).
The modularity of this framework allows users to \"plug in\" their own algorithms for each of the blocks defined in Figure 1, instead of rewriting the whole path planning stack.
Chapter 13 of the Small Unmanned Aircraft: Theory and Practice book contains more detail on implementing a vision-based path planner.
"},{"location":"developer-guide/rosplane/navigation/navigation-overview/#running-the-navigation-stack","title":"Running the Navigation Stack","text":"To launch the navigation stack, you will need to launch 3 ROS2 nodes, one for each part of the navigation stack (path planner, manager, and follower).
Remember to launch these nodes with the appropriate parameter launch file, as seen in the rosplane.launch.py
file.
"},{"location":"developer-guide/rosplane/navigation/path-follower/","title":"Path Follower","text":""},{"location":"developer-guide/rosplane/navigation/path-follower/#overview","title":"Overview","text":"The role of the path follower is to generate the correct airspeed, course, and altitude commands for the autopilot such that the aircraft follows the paths published by path_manager
.
More information on the path_follower
can be found in Small Unmanned Aircraft: Theory and Practice by Dr. Randal Beard and Dr. Tim McLain.
"},{"location":"developer-guide/rosplane/navigation/path-follower/#path-follower-base","title":"Path Follower Base","text":"The path follower base contains all the ROS2 interfaces required for the path follower. A list of these interfaces is below.
The path_follower_base::follow
method is a virtual method that should be implemented by a derived class. The path_follower_base
publishes the controller commands calculated by the implementation of path_follower_base::follow
.
"},{"location":"developer-guide/rosplane/navigation/path-follower/#list-of-ros2-interfaces","title":"List of ROS2 Interfaces","text":"ROS2 Interface Topic or Service Explanation Message or Service Type vehicle_state_sub_
/estimated_state
Subscribes to the estimated aircraft state rosplane_msgs::msg::State
current_path_sub_
/current_path
Subscribes to the current path messages published by path_manager
rosplane_msgs::msg::CurrentPath
controller_commands_pub_
/controller_commands
Publishes control commands to the autopilot rosplane_msgs::msg::ControllerCommand
update_timer_
-- ROS2 timer that controls how frequently controller_commands_pub_
publishes --"},{"location":"developer-guide/rosplane/navigation/path-follower/#interface-with-the-autopilot","title":"Interface with the Autopilot","text":"The path_follower
node interfaces with the MAV autopilot by publishing to the /controller_commands
topic. The /controller_commands
topic contains the following information calculated by the path_follower
:
Member Description Type / units Required header
Standard message header that contains a valid timestamp std_msgs::msg::Header
Yes va_c
Commanded airspeed double
, m/s Yes h_c
Commanded altitude double
, m Yes chi_c
Commanded course double
, rad Yes phi_ff
Feedforward command (for orbits) double
, rad No"},{"location":"developer-guide/rosplane/navigation/path-follower/#path-follower-example","title":"Path Follower Example","text":"The path_follower_example
class contains the implementation of the path_follower_base::follow
method. This method contains the control command computations for straight line and orbit-type paths as outlined in Small Unmanned Aircraft: Theory and Practice.
"},{"location":"developer-guide/rosplane/navigation/path-follower/#parameters","title":"Parameters","text":"See the Parameter Management page for more details on how parameter management works.
"},{"location":"developer-guide/rosplane/navigation/path-follower/#list-of-parameters","title":"List of Parameters","text":"Parameter Explanation Type / Units Range chi_infty
At infinity, the angle at which the aircraft will approach the desired line double (rad) \\frac{\\pi}{2} \\geq \\chi^{\\infty} > 0.0 k_path
Constant that determines how quickly commanded course transitions from \\chi^{\\infty} to 0 during line following double > 0.0 k_orbit
Constant that determines how quickly commanded course transitions from \\lambda \\frac{\\pi}{2} to 0 during an orbit double > 0.0 Since there are two different types of lines generated by the path_manager
(straight lines and orbits), the path_follower
uses different parameters to calculate the control output for each path type.
For line following, path_follower
uses
chi_infty
and k_path
to compute the control commands.
As described in Small Unmanned Aircraft: Theory and Practice, these two parameters define a vector field for the commanded course. The chi_infty
parameter describes the angle at which the aircratft will approach a target line if the aircraft is infinitely far from the target line. For example, if chi_infty
is set to \\frac{\\pi}{2}, then the aircraft will approach the target line at an angle perpindicular to the line when the aircraft is far away.
The k_path
parameter defines how quickly the vectors at chi_infty
\"smooth\" into the target line. When k_path
is large, the transition will be abrupt, and when k_path
is small, the transition will be smoother.
During orbit following, path_follower
uses
k_orbit
to compute the control commands.
If the aircraft is very far away from the orbit, it will align itself so it flies directly at the center of the orbit. The k_orbit
parameter is similar to the k_path
parameter in that it determines how quickly the commanded angle of the aircraft will change from directly toward the center to the orbit direction.
Note
When tuning, make sure you are changing the correct gains for the type of line (straight or orbit) the aircraft is tracking. chi_infty
and k_path
will not affect the orbit performance!
"},{"location":"developer-guide/rosplane/navigation/path-follower/#modifying-the-path-follower","title":"Modifying the Path Follower","text":"Changes to any of the ROS2 interface should be done in the path_follower_base
.
Changes to how path_follower
computes control commands to follow paths given by the path_manager
should be done in the path_manager_example
.
"},{"location":"developer-guide/rosplane/navigation/path-manager/","title":"Path Manager","text":""},{"location":"developer-guide/rosplane/navigation/path-manager/#overview","title":"Overview","text":"The path manager is responsible for calculating and publishing the current path to the path follower. It is split into a base class and an inherited class. The base class handles the ROS2 interfaces (publishing and subscribing) while the inherited class manages the path, i.e., calculates the parameters for the current path.
The path manager is designed this way so that the inherited class (how the paths are managed) can be replaced or rewritten without affecting the overlying ROS2 interface.
Both the path_manager_base
and the path_manager_example
are included in the same ROS2 node when compiled, called path_manager
. Parameters associated with the path_manager_base
or the path_manager_example
will therefore be visible under the path_manager
ROS2 node.
More details about the path manager can be found in Small Unmanned Aircraft: Theory and Practice by Dr. Randal Beard and Dr. Tim McLain.
"},{"location":"developer-guide/rosplane/navigation/path-manager/#path-manager-base","title":"Path Manager Base","text":"The path manager base contains all the ROS2 interfaces required for the path manager. A list of these interfaces is below.
"},{"location":"developer-guide/rosplane/navigation/path-manager/#list-of-ros2-interfaces","title":"List of ROS2 Interfaces","text":"ROS2 Interface Topic or Service Explanation Message or Service Type vehicle_state_sub_
/estimated_state
Subscribes to the estimated aircraft state rosplane_msgs::msg::State
new_waypoint_sub_
/waypoint_path
Subscribes to the waypoint messages published by path_planner
rosplane_msgs::msg::State
current_path_pub_
/current_path
Publishes the parameters of the current path rosplane_msgs::msg::CurrentPath
update_timer_
-- ROS2 timer that controls how frequently current_path_pub_
publishes --"},{"location":"developer-guide/rosplane/navigation/path-manager/#interface-with-the-path-follower","title":"Interface with the Path Follower","text":"The path_manager
node interfaces with the path follower by publishing to the /current_path
topic. These messages contain information about the current trajectory, which are either straight lines or circles.
Note that the only supported path types are straight lines and circles. Depending on how the path_manager
is set up to manage the waypoints, this may not be suitable for your application. See \"Modifying the Path Manager\" for more information. For more information on the path follower, see the Path Follwer documentation.
"},{"location":"developer-guide/rosplane/navigation/path-manager/#path-manager-example","title":"Path Manager Example","text":"The path_manager_example
class inherits from the path_manager_base
class. Specifically, the path_manager_example
overrides the path_manager_base::manage
method to determine how the path is managed.
In the current implementation, path_manager_example
decides to manage a waypoint using straight lines and fillets, orbits, or Dubins paths based on the current state of the aircraft, the values of the current ROS2 parameters, and the waypoints given. For example, if the use_chi
field on a Waypoint object (see Path Planner for more information) is set to true
, then path_manager_example
will use a Dubins path to navigate to the next waypoint. If use_chi
is set to false
, then path_manager_example
will use straight lines when navigating in between waypoints and a fillet to manage the corners. See Figure 1 for an example of a real flight path flown using ROSplane with chi_d
set to false
.
Example flight path from an actual flight test showing the straight lines and fillets path type Note that using fillets to manage the corners often means that the aircraft does not actually achieve the waypoint. If this is undesireable in your application, use Dubins paths or another method for the path_manager
.
"},{"location":"developer-guide/rosplane/navigation/path-manager/#parameters","title":"Parameters","text":"See the Parameter Management page for more details on how parameter management works.
"},{"location":"developer-guide/rosplane/navigation/path-manager/#list-of-parameters","title":"List of Parameters","text":"Parameter Explanation Type Range R_min
Minimum radius for orbit, fillet, and Dubins paths double \\geq 0.0 orbit_last
Specifies whether or not to orbit the last waypoint. If false, param_manager
will fly a circuit bool true
or false
"},{"location":"developer-guide/rosplane/navigation/path-manager/#the-orbit_last-parameter","title":"The orbit_last
Parameter","text":"The path_manager
node has a parameter named orbit_last
. This parameter controls what happens as the aircraft is approaching the last waypoint in the set of waypoints published to the path_manager
. If orbit_last
is set to true
, then path_manager
will follow an orbit around the last waypoint.
The direction of this waypoint (clockwise or counterclockwise) will be chosen based on which direction requires the least amount of turning. In other words, if the aircraft is angled slightly left as it approaches the waypoint, path_manager
will choose to orbit the last waypoint counterclockwise (from a top-down perspective). If the aircraft is pointing slightly right as it approaches the waypoint, it will orbit the waypoint clockwise (from a top-down perspective).
"},{"location":"developer-guide/rosplane/navigation/path-manager/#modifying-the-path-manager","title":"Modifying the Path Manager","text":"Changes or additions to any ROS2 interfaces should be done in the path_manager_base
field.
Changes to how path_manager
\"manages\" the waypoints should be done by overriding the path_manager_base::manage
method. If you wish to change the way paths are defined, make sure that the /current_path
topic is rewritten to contain the required information, and then make sure the path_follower
knows how to handle the new definition.
"},{"location":"developer-guide/rosplane/navigation/path-planner/","title":"Path Planner","text":""},{"location":"developer-guide/rosplane/navigation/path-planner/#overview","title":"Overview","text":"The path planner is responsible for creating, managing, and publishing waypoints. In the current implementation, the path planner simply maintains a list of user-defined waypoints that the user can add to or clear. The path planner then controls when waypoints are published to the path manager.
Another implementation of the path planner (as described in the overview) could include a visual-based path planner. In this case, the path planner would receive sensor input and create and manage its own waypoints instead of a user-defined list of waypoints. However, this new path planner would still be responsible for creating and publishing waypoints. This ensures that the interface between the path planner and the path manager would stay the same, allowing for modularity in the path planner architecture.
"},{"location":"developer-guide/rosplane/navigation/path-planner/#interfaces","title":"Interfaces","text":"The path planner is implemented as a standalone ROS2 node, called path_planner
. This node subscribes to the topics it needs, provides services available to the user and other nodes, and publishes waypoints to the path manager, called path_manager
.
The interface between path_planner
and path_manager
is the /waypoint_path
topic, which publishes messages with the rosplane_msgs::msg::Waypoint
type. This message contains information about the waypoint's location in NED (from the origin) or GNSS (LLA) coordinates, the desired airspeed at the waypoint, and the desired heading of the aircraft at the waypoint.
"},{"location":"developer-guide/rosplane/navigation/path-planner/#about-waypoints","title":"About Waypoints","text":"The following table contains the data members of the rosplane_msgs::msg::Waypoint
objects and a brief description.
Member Description Type Required header
Standard message header that contains a valid timestamp std_msgs::msg::Header
Yes w
Waypoint coordinates in NED or GNSS (LLA) std::array<float32, 3>
Yes lla
Flag to determine if the coordinates are passed in as NED or GNSS bool
Yes chi_d
Desired course at the waypoint double
No use_chi
Flag to use the chi_d
value at the waypoint or not bool
No - defaults to false
va_d
Desired airspeed at the waypoint double
Yes clear_wp_list
Clears all waypoints from path_planner
and path_manager
bool
No"},{"location":"developer-guide/rosplane/navigation/path-planner/#notes-on-the-waypoint-object-fields","title":"Notes on the Waypoint object fields","text":"The w
field contains the coordinates of the waypoint in either NED coordinates (from the origin, defined as the place where ROSplane initialized) or GNSS coordinates given in LLA (latitude, longitude, and altitude). The GNSS coordinates are converted to NED coordinates by path_planner
before sending them to path_manager
.
The lla
field is a flag that tells path_planner
if the coordinates provided are in the NED or world (GNSS) frame. Set it to true
if the coordinates for the waypoint are given in GNSS coordinates. Note that GNSS and relative waypoints can be used together, meaning that one waypoint could be in the NED frame while the next one is in the global frame, since ROSplane converts global coordinates to the NED frame before publishing them to path_manager
.
Note
Make sure that the lla
field is set correctly if you decide to use GNSS coordinates, or your waypoints will be incorrect.
The chi_d
field controls the desired course at the waypoint. Note that this is only used if the use_chi
flag is set to true
.
The use_chi
field determines whether or not the path_manager
should pay attention to the desired course (chi_d
). If use_chi
is set to true
then path_manager
will use a Dubins path framework to manage the waypoint. If use_chi
is set to false
, then path_manager
will ignore the desired course and will intead use straight lines and fillets to manage the transitions between waypoints. See the Path Manager documentation for more information on this behavior.
The clear_wp_list
is used internally by path_planner
when the /clear_waypoints
service is called. It is recommended to use the service call instead of using this field manually.
Warning
The header
, w
, va_d
, and lla
fields must be valid for every waypoint message sent. Failure to add these fields might crash the path planner or your aircraft.
"},{"location":"developer-guide/rosplane/navigation/path-planner/#list-of-ros2-interfaces","title":"List of ROS2 Interfaces","text":"ROS2 Interface Topic or Service Explanation Message or Service Type waypoint_publisher_
/waypoint_path
Publishes the waypoints to the path_manager
rosplane_msgs::msg::Waypoint
state_subscription_
/estimated_state
Subscribes to the estimated state of the aircraft rosplane_msgs::msg::State
next_waypoint_service_
/publish_next_waypoint
Publishes the next stored waypoint std_msgs::srv::Trigger
add_waypoint_service_
/add_waypoint
Adds a new waypoint to list and optionally publishes it rosplane_msgs::srv::AddWaypoint
clear_waypoint_service_
/clear_waypoints
Clears the list of waypoints from the path planner and publishes a clear waypoint command to the path_manager
std_msgs::srv::Trigger
print_waypoints_service_
/print_waypoints
Prints the saved waypoints to the terminal. Can be useful when debugging std_msgs::srv::Trigger
load_mission_service_
/load_mission_from_file
Loads a mission from a YAML file rosflight_msgs::srv::ParamFile
"},{"location":"developer-guide/rosplane/navigation/path-planner/#parameters","title":"Parameters","text":"See the Parameter Management page for more details on how parameter management works.
"},{"location":"developer-guide/rosplane/navigation/path-planner/#list-of-parameters","title":"List of Parameters","text":"Parameter Explanation Type Range num_waypoints_to_publish_at_start
Number of waypoints to immediately publish at launch. If no waypoints are added, it will not publish any. int \\geq 0"},{"location":"developer-guide/rosplane/navigation/path-planner/#recommended-usage","title":"Recommended Usage","text":"We recommend using a YAML file and the /load_mission_from_file
service from the command line to load and fly waypoints. See the example mission YAML file located at /path/to/rosplane/rosplane/params/fixedwing_mission.yaml
.
To call the service, run
ros2 service call /load_mission_from_file rosflight_msgs::srv::ParamFile \"{filename: <FILENAME>}\"\n
where <FILENAME>
is the path to the mission YAML file."},{"location":"user-guide/autonomous-flight/","title":"Autonomous Flight","text":"To perform autonomous flight with ROSflight, we need to send control commands from our companion computer to the firmware. This can be done with ROSplane or ROScopter, which already have completed autonomy stacks developed specifically for ROSflight. We recommend starting with one of these autonomy stacks and building on them to suit your needs. If using a multirotor, follow the ROScopter setup guide to get started. If using a fixed-wing, follow the ROSplane setup guide.
However, ROSplane and ROScopter are optional and an entirely different autonomy stack can be used if desired. To use a different autonomy stack, follow this guide.
"},{"location":"user-guide/autonomous-flight/#provide-control-from-a-companion-computer","title":"Provide Control from a Companion Computer","text":"Control setpoints are sent to the flight controller by publishing to the /command
topic that is advertised by the rosflight_io
node. This topic accepts messages of type rosflight_msgs/Command
, which have the following structure:
std_msgs/Header header\nuint8 mode\nuint8 ignore\nfloat32 x\nfloat32 y\nfloat32 z\nfloat32 f\n
The header
field is a standard ROS2 message header. The x
, y
, z
, and f
fields are the control setpoint values, which are interpreted according to the mode
and ignore
fields.
The following table describes the different values the mode
field can take, as well as how the setpoint values are interpreted for each of these modes:
Value Enum x y z F 0 MODE_PASS_THROUGH
aileron deflection (-1 to 1) elevator deflection (-1 to 1) rudder deflection (-1 to 1) throttle (0 to 1) 1 MODE_ROLLRATE_PITCHRATE_YAWRATE_THROTTLE
roll rate (rad/s) pitch rate (rad/s) yaw rate (rad/s) throttle (0 to 1) 2 MODE_ROLL_PITCH_YAWRATE_THROTTLE
roll angle (rad) pitch angle (rad) yaw rate (rad/s) throttle (0 to 1) The MODE_PASS_THROUGH
mode is used for fixed-wing vehicles to directly specify the control surface deflections and throttle, while the MODE_ROLLRATE_PITCHRATE_YAWRATE_THROTTLE
and MODE_ROLL_PITCH_YAWRATE_THROTTLE
modes are used for multirotor vehicles to specify the attitude rates or angles, respectively.
The ignore
field is used if you want to specify control setpoints for some, but not all, of the axes. For example, I may want to specify throttle setpoints to perform altitude hold, while still letting the RC pilot specify the attitude setpoints. The ignore
field is a bitmask that can be populated by combining the following values:
Value Enum Result 0 IGNORE_NONE
Ignore none of the fields (default) 1 IGNORE_X
Ignore the x
field 2 IGNORE_Y
Ignore the y
field 4 IGNORE_Z
Ignore the z
field 8 IGNORE_F
Ignore the F
field For the previous example, I would set the ignore
field to a value of
ignore = IGNORE_X | IGNORE_Y | IGNORE_Z\n
The best practice is to use enum names rather than the actual numeric values for the mode
and ignore
fields. For example, to specify a multirotor attitude angle command in C++ I might have:
#include <rclcpp/rclcpp.hpp>\n#include <rosflight_msgs/msg/command.hpp>\n\nrosflight_msgs::msg::Command msg;\nmsg.header.stamp = node->get_clock()->now();\nmsg.mode = rosflight_msgs::msg::Command::MODE_ROLL_PITCH_YAWRATE_THROTTLE;\nmsg.ignore = rosflight_msgs::msg::Command::IGNORE_NONE;\nmsg.x = 0.0;\nmsg.y = 0.0;\nmsg.z = 0.0;\nmsg.f = 0.6;\n
In Python I might have:
import rclpy\nfrom rosflight_msgs.msg import Command\n\nmsg = Command()\nmsg.header.stamp = node.get_clock().now().to_msg()\nmsg.mode = Command.MODE_ROLL_PITCH_YAWRATE_THROTTLE\nmsg.ignore = Command.IGNORE_NONE\nmsg.x = 0.0\nmsg.y = 0.0\nmsg.z = 0.0\nmsg.f = 0.6\n
I would then publish this message to the /command
topic to forward it to the embedded flight controller. Note
If the flight controller does not receive a new command for a defined period of time, it will ignore the old commands and revert to RC control. The length of this timeout period is set by the OFFBOARD_TIMEOUT
parameter.
"},{"location":"user-guide/flight-controller-setup/","title":"Flight Controller Setup","text":"Note
This page contains instructions for flashing pre-built firmware binaries. For instructions on building and flashing from source, see Building and Flashing in the Developer Guide.
"},{"location":"user-guide/flight-controller-setup/#compatible-hardware","title":"Compatible Hardware","text":"Currently, the ROSflight firmware only supports an in-development board from AeroVironment, the Varmint. This board is not yet commercially available, but plans are for it to start being sold early 2024.
We also plan to add support for the CubePilot Orange, which uses the same H7 processor as the Varmint.
"},{"location":"user-guide/flight-controller-setup/#serial-port-configuration","title":"Serial Port Configuration","text":"Tip
You can see which groups you are a member of by running groups $USER
on the command line.
The following bullet point is necessary:
- Be sure your user is in the
dialout
and plugdev
groups so you have access to the serial ports. You will need to log out and back in for these changes to take effect. sudo usermod -aG dialout,plugdev $USER\n
If you experience issues, you may need one or both of the next two bullet points:
-
Temporarily stop the modem-manager (Sometimes, Linux thinks the device is a modem -- this command will be effective until next boot, or until you run the command again with start
in place of stop
)
sudo systemctl stop ModemManager.service\n
-
Add the custom udev rule so Linux handles the flight controller properly (copy the following as /etc/udev/rules.d/45-stm32dfu.rules
)
# DFU (Internal bootloader for STM32 MCUs)\nSUBSYSTEM==\"usb\", ATTRS{idVendor}==\"0483\", ATTRS{idProduct}==\"df11\", MODE=\"0664\", GROUP=\"plugdev\"\n
Tip
You can permanently disable the ModemManager if you do not need it, then you won't have to disable it every time you reboot:
sudo systemctl disable ModemManager.service\n
Replace disable
with enable
to revert (i.e. if you find some other program you use needs access to it). Or you can uninstall it entirely from your system: sudo apt purge modemmanager\n
"},{"location":"user-guide/flight-controller-setup/#flashing-firmware","title":"Flashing Firmware","text":"TODO
Update flashing instructions.
"},{"location":"user-guide/flight-controller-setup/#f4-boards","title":"F4 Boards","text":" - Install the dfu-util utility
sudo apt install dfu-util\n
- Download the latest rosflight-F4.bin file, found here
- Put the board in bootloader mode (short the boot pins while restarting the board by cycling power)
Tip
dfu-util auto-detects F4-based boards. Try dfu-util -l
to make sure your board is in bootloader mode
- Flash the firmware to the device
dfu-util -a 0 -s 0x08000000 -D rosflight-F4.bin\n
"},{"location":"user-guide/getting-started/","title":"Getting Started","text":"Reading through the pages in this user guide in order should provide you with the information you need to get a vehicle flying with ROSflight. The following is a summary of the steps you'll need to follow to get your vehicle set up, with links to the corresponding documentation pages:
- Set up your hardware (fixed-wing or multirotor platform, flight controller, and companion computer)
- Flash your flight controller with the latest ROSflight firmware
- Set up your RC transmitter
- Set up ROS2 on your companion computer
- Configure the flight controller for your setup: the configuration checklists below should help guide you through this process
- Run through your preflight checks
- Tune the firmware attitude controller gains (multirotors only)
- Set up autonomous flight via offboard control (optional)
"},{"location":"user-guide/getting-started/#configuration-checklist","title":"Configuration Checklist","text":"The following checklists should help you get a new vehicle set up for the first time. This checklist assumes that your hardware is already set up correctly.
"},{"location":"user-guide/getting-started/#general-setup","title":"General Setup","text":" - Set the
FIXED_WING
parameter (1
if a fixed-wing, 0
if a multirotor) - Set the
RC_TYPE
parameter (0
if PPM, 1
if SBUS) - Set the
MIXER
parameter to the appropriate value described in the Hardware Setup page - Set the
MOTOR_PWM_UPDATE
parameter (typically 490
for SimonK ESCs, 50
for standard servos) - Make sure your RC transmitter is set up correctly
- Set up your RC switches
- If you want to arm/disarm using a switch, set the
ARM_CHANNEL
parameter to the appropriate channel (0-indexed) - If you want to use a switch to enable RC override, set the
RC_ATT_OVRD_CHN
and RC_THR_OVRD_CHN
parameters to the appropriate channel(s) (0-indexed). If you want complete control (attitude and throttle) when you flip the switch, set both these parameters to the same channel.
- Calibrate your IMU: start
rosflight_io
, then run ros2 service call /calibrate_imu std_srvs/srv/Trigger
- Complete the multirotor-specific or fixed-wing-specific checklist below
- Save the parameters (
ros2 service call /param_write std_srvs/srv/Trigger
) - You'll probably want to save a backup of your parameters (call
ros2 service call /param_save_to_file rosflight_msgs/srv/ParamFile \"{filename: \"params.yml\"}\"
) - Make sure you run through the Preflight Checklist before flying
"},{"location":"user-guide/getting-started/#multirotor-specific-setup","title":"Multirotor-specific Setup","text":"Danger
IMPORTANT: Remove all props from the vehicle when calibrating ESCs!!!
-
Calibrate ESCs
- Make sure
MOTOR_MIN_PWM
and MOTOR_MAX_PWM
are correct (usually 1000
and 2000
) - Set
MIXER
param to 0
(ESC calibration mixer) - Set
ARM_SPIN_MOTORS
to 0
-
Perform ESC calibration. For standard ESCs:
- With power disconnected from the motors, arm the flight controller
- Set throttle to maximum
- Connect power to the motors
- Drop the throttle to minimum
-
Set the MIXER
parameter back to the appropriate value for your vehicle (see the Hardware Setup page)
- Set
ARM_SPIN_MOTORS
back to 1
-
The ARM_SPIN_MOTORS
parameter should be set to 1
so the motors spin slowly when armed. The idle throttle setting can be adjusted with the MOTOR_IDLE_THR
parameter.
- You'll most likely want to set the
CAL_GYRO_ARM
param to 1
to enable calibrating gyros before arming - Set the
RC_ATT_MODE
parameter to set RC control mode (0
for rate mode, 1
for angle mode [default]) - Set torque offsets as described in the RC trim calculation section of the Improving Firmware Performance page
- Set the
FAILSAFE_THR
parameter to specify the throttle level the MAV will hold if the transimtter disconnects. Set the parameter to 0
if you just want the MAV to drop, otherwise determine the amount of throttle required to hover the MAV and set the parameter comfortably below that. DO NOT set it above, as this will result in a runaway MAV. We recommended that you test the throttle level in an enclosed space by powering off the transmitter while hovering, if you set this parameter above 0. - Tune the controller gains as described in the Multirotor gain tuning section of the Improving Firmware Performance page
"},{"location":"user-guide/getting-started/#fixed-wing-specific-setup","title":"Fixed-Wing-Specific Setup","text":" - Reverse servo directions if necessary using the
AIL_REV
, ELEVATOR_REV
, and RUDDER_REV
parameters (1
to reverse, 0
to keep current direction) - You'll most likely want to set the
ARM_SPIN_MOTORS
parameter to 0
so that the prop doesn't spin at a minimum throttle setting when you arm, especially if you'll be doing hand launching
"},{"location":"user-guide/hardware-setup/","title":"Hardware Setup","text":""},{"location":"user-guide/hardware-setup/#parts-list","title":"Parts List","text":"To use ROSflight to its full potential, you will need the following system components. Some components are mounted on your MAV (Miniature Aerial Vehicle), while others are on the ground. ROSflight supports both multirotor and fixed-wing vehicles.
Mounted on the MAV
- Aircraft Frame, Motor(s), ESC(s), Battery and Propeller(s)
- Flight Controller (FC)
- Vibration Isolation for FC
- Any external sensors
- R/C Receiver
- Companion Computer
- Wi-Fi Antenna, or access of some kind to ground-station, wireless network (e.g. Ubiquiti Bullet)
Ground Station
- Ground-Station, Wireless Network (e.g. Wi-Fi Router, Ubiquiti Rocket)
- R/C transmitter
- Laptop or base station computer
- Joystick (Xbox controller)
"},{"location":"user-guide/hardware-setup/#frame-motors-escs-battery-and-propeller","title":"Frame, Motors, ESCs, Battery, and Propeller","text":"We do not officially support any specific multirotor or airplane frame, motor, ESC, Battery or Propeller combination. There are a lot of great resources for building your own MAV, and there are a lot of great kits out there that have all of these parts.
If you are designing your own multirotor or airplane, you may want to look at ecalc, an online tool which can help you design a proper ESC/Battery/Motor/Propeller system for your MAV.
Some things to keep in mind as you design or build your MAV.
- Most kits do not include space for a companion computer, cameras, laser scanners or other sensors. Be sure to think about where these components are going to go, and how their placement will affect the CG of the MAV.
- You will likely also need to customize the power circuitry of your MAV to provide power to your companion computer at some specific voltage. Many people like to separate the power electronics (the ESCs and motors), from the computer and companion sensors. This can really come in handy if you are trying to develop code on the MAV, because you can have the computer on and sensors powered, and not worry at all about propellers turning on and causing injury as you move the aircraft about by hand. We will talk about this more when we talk about wiring up your MAV.
- Cheap propellers can cause a huge amount of vibration. Consider buying high-quality propellers, doing a propeller balance, or both. RCGroups, DIY Drones and Youtube have some awesome guides on how to do propeller balancing.
- ESCs will need to be calibrated from 2000 to 1000 us
"},{"location":"user-guide/hardware-setup/#flight-controller","title":"Flight Controller","text":"TODO
Update recommended hardware once supported hardware has been finalized.
"},{"location":"user-guide/hardware-setup/#external-sensors","title":"External Sensors","text":"Additional Sensors you may want for your ROSflight setup include:
- Sonar
- GPS
- Digital Airspeed Sensor (Pitot Tube)
"},{"location":"user-guide/hardware-setup/#vibration-isolation","title":"Vibration Isolation","text":"It is really important to isolate your flight controller from vehicle vibrations, such as those caused by propellers and motors. We recommend using small amounts of Kyosho Zeal to mount a fiberglass plate holding the FC to the MAV. You may also want to try adding mass to the flight control board. We have accomplished this by gluing steel washers to the fiberglass mounting plate.
You may need to experiment with the amount of gel you use, how far apart the gel is spaced, and the amount of mass added to the FC mounting plate. The interaction of these factors is difficult to predict, therefore it takes a little bit of experimentation to get it right.
"},{"location":"user-guide/hardware-setup/#companion-computer","title":"Companion Computer","text":"The only requirement for the companion computer is that it runs Linux (usually an Ubuntu LTS version, but using Docker on other distributions is also an option), ROS2, has at least one USB port, and can be carried by the aircraft. We have had success with the following companion computers, but by no means is this a comprehensive list; it is more by way of suggestion.
- NVIDIA Jetson
- MSI CUBI
- Intel NUC
- Rasberry Pi 3
"},{"location":"user-guide/hardware-setup/#wi-fi","title":"Wi-Fi","text":"You will need Wi-Fi to communicate with your MAV when it is in the air. Because ROS2 communicates over UDP, it is very easy to use ROS2 to view what is going on in your MAV while it is flying by sending commands and reading sensor data. For most applications, a standard Wi-Fi router and dongle will suffice. For long-range applications, you may want to look into Ubiquiti point-to-point Wi-Fi. (We have seen ranges over a mile with these networks.)
"},{"location":"user-guide/hardware-setup/#rc-transmitter-and-receiver","title":"RC Transmitter and Receiver","text":"For RC Control, you will need a transmitter with between 6 and 8 channels. Any additional channels will be wasted. We require RC control for safe operation, and only support arming and disarming via RC control.
ROSflight only supports PPM (pulse position modulation) and SBUS receivers. Individual channel PWM outputs are not supported. Any configurations with PPM or SBUS and 6-8 channels will be sufficient.
"},{"location":"user-guide/hardware-setup/#laptop-or-base-station-computer","title":"Laptop or Base Station Computer","text":"You will need a laptop which can run ROS2 to communicate with the MAV over the ground station wireless network. To do this natively you'll want a recent Ubuntu LTS version, but this can also be done with Docker containers from pretty much any Linux distribution. Linux within a virtual machine can also work, but is not recommended.
"},{"location":"user-guide/hardware-setup/#joystick","title":"Joystick","text":"A joystick is used for software-in-the-loop (SIL) simulations. The joystick is not technically a required component because it is possible to control your MAV from the command line, but it makes things much easier. Our first recommendation is to use the same transmitter you use for hardware as a joystick by plugging it into the computer via USB. We support Taranis QX7 transmitters, Radiomaster TX16s transmitters, RealFlight controllers, and XBOX controllers. Other joysticks can be used, but you may need to create custom axis and button mappings within the ROSflight joystick utility.
"},{"location":"user-guide/hardware-setup/#battery-monitor","title":"Battery Monitor","text":"A battery monitor is an analog sensor that provides battery voltage and/or battery current information. This data can be used to prevent power loss in air or to measure system load. The sensor outputs an analog voltage proportional to the battery voltage and/or current through the battery. Most flight controllers come equipped with a built-in battery monitor, but if not, small PCB sensors are also available that can be connected to the flight controller.
For ROSflight to use a battery monitor, an appropriate multiplier must be set. ROSflight multiplies the analog signal from the monitor by the multiplier to get the final reading. The monitor datasheet should contain the information needed to get the multiplier. For example, the datasheet for the AttoPilot 50V/90A sensor states that it outputs 63.69 mV / V. To get the original battery voltage, the multiplier must be 1/.06369, or 15.7. The multipliers for the voltage and current are set separately, with the BATT_VOLT_MULT
and BATT_CURR_MULT
parameters, respectively.
ROSflight applies a simple low-pass filter to remove noise from the voltage and current measurements. These filters are configurable via the BATT_VOLT_ALPHA
and BATT_CURR_ALPHA
parameters. The alpha value for a given cutoff frequency \\(a\\), can be calulated with: \\( \\alpha = e ^ {-.01a} \\). As battery voltages do not typically change quickly, the default of 0.995 usually suffices.
More information on battery monitor hardware, including determinining appropriate multipliers and creating a simple DIY monitor, can be found on the OpenPilot Wiki.
"},{"location":"user-guide/hardware-setup/#wiring-diagram","title":"Wiring Diagram","text":"Below is an example wiring diagram for a multirotor using an MSI Cubi as a companion computer. This diagram also includes the motor power switch, which allows for the sensors, flight controller, and companion computer to be powered on while the motors are off. This is a safer way to test sensors, code, etc. as the motors are unable to spin while the switch is off.
Your needs will likely be slightly different than what is shown. This is meant as an example only and can be adapted to fit your needs.
"},{"location":"user-guide/hardware-setup/#motor-layouts","title":"Motor Layouts","text":"The desired mixer can be chosen by setting the MIXER
parameter to the following values:
# Mixer 0 ESC calibration 1 Quad + 2 Quad X 3 Hex + 4 Hex X 5 Octo + 6 Octo X 7 Y6 8 X8 9 Tricopter 10 Fixed-wing (traditional AETR) The associated motor layouts are shown below for each mixer. The ESC calibration mixer directly outputs the throttle command equally to each motor, and can be used for calibrating the ESCs.
"},{"location":"user-guide/hardware-setup/#connecting-to-the-flight-controller","title":"Connecting to the Flight Controller","text":"The flight controller communicates with the companion computer over a serial link. ROSflight only supports one serial connection at a time and by default should be the serial link connected to the USB connector on the board.
"},{"location":"user-guide/hardware-setup/#using-secondary-serial-links","title":"Using Secondary Serial Links","text":"In the case of an F4 flight controller, which has a USB peripheral, the highest bandwidth connection will be the USB connector. However, UART3 can also be used to communicate with the companion computer if you desire a more secure connection (micro USB connectors have been known to disconnect in high vibrations).
If a USB connection is detected on the USB peripheral, ROSflight will direct all communication through this port. However, if the PARAM_SERIAL_DEVICE
parameter is set to 3
and the PARAM_BAUD_RATE
parameter is set properly, then UART3 will be enabled when the USB connection is absent.
"},{"location":"user-guide/improving-firmware-performance/","title":"Improving Firmware Performance","text":"ROSflight supplies several methods to improve the performance of your aircraft. Tuning gains, adding feed-forward torques, and tuning the estimator are three ways to get your aircraft flying great!
"},{"location":"user-guide/improving-firmware-performance/#gain-tuning","title":"Gain Tuning","text":"Because there are a wide variety of multirotors out there, no one set of PID controller gains will be optimal for all vehicles. The default set of gains is relatively conservative for most platforms, and should be somewhat airworthy in most cases. However, depending on the inertia-to-torque ratio on your MAV, you may have to change these gains considerably. There are some great tutorials online on multirotor gain tuning; this is another tried-and-true method used to great effect at BYU.
If you are unfamiliar with PIDs, you should probably go read about them before trying to tune a multirotor. Getting an understanding for what is going on will definitely guide your decision making process as you try to find better gains.
While tuning controller gains, it is very likely that the multirotor will oscillate out of control. To handle this scenario, we generally add what we call \"training wheels\" to the multirotors we are tuning. These amount to thin carbon rods in the shape of an X zip-tied to the landing gear. This widens out the base of the multirotor so if you come down on a hard oscillation, chances are the vehicle will land upright, hopefully without a prop strike, or worse, battery damage with a thermal runaway event. If the battery is not tucked inside the main frame, it is wise to add some foam as protection to the battery.
Here is a video of a maiden flight of ROSflight with \"training wheels\" attached.
Now, for the procedure on tuning.
"},{"location":"user-guide/improving-firmware-performance/#tuning-roll-and-pitch-angles","title":"Tuning Roll and Pitch angles","text":"Here is a flowchart describing my PID tuning process for roll and pitch:
You may want to do another D-tuning iteration. Additionally, sometimes it is helpful to do a little tweaking on roll and pitch separately to eek out a little more performance from the differences in roll and pitch dynamics of your vehicle.
Notice that we did not include any I
tuning. As a general rule, try to keep the I
gain as low as possible. It will always slow your response rate to input, and it can induce low frequency oscillations.
You should only have I
gain on roll and pitch if one of the following is true:
- You expect your CG to change, and/or
- You expect your rotor geometry to change
Both of these are pretty rare. Instead, use your RC transmitter to trim the aircraft so it hovers with no stick input. In the RC trim calculation section, we will use the RC trim to calculate a feed-forward torque on the roll, pitch and yaw rates.
"},{"location":"user-guide/improving-firmware-performance/#tuning-yaw-rate","title":"Tuning Yaw rate","text":"Dynamically and algorithmically, using a D
gain in yaw-rate control has no significant advantage. Controlling with derivative requires differentiating gyro measurements, which tends to be pretty noisy. In our experience, putting D
in rate controllers on multirotors has always decreased performance.
Tuning yaw rate is generally pretty easy. Basically, keep cranking it up until you feel like it's \"locked in\". Sometimes, a little bit of I
(on the order of 0.1P) can help with this as well.
The problem with too much P
on yaw rate generally manifests itself in motor saturation. Some, especially larger, multirotors have problems getting enough control authority in yaw with the propellers being aligned flat. After you are done tuning, you might want to look at a plot of motor commands during a fairly aggressive flight. Underactuated yaw will be pretty obvious in these plots, because you will see the motor commands railing. To fix this, you can put shims between the arm mounts and the motors to tilt the motors just a little bit in the direction of yaw for that motor.
"},{"location":"user-guide/improving-firmware-performance/#rc-trim","title":"RC trim","text":"In the vast majority of cases, your multirotor will not be built perfectly. The CG could be slightly off, or your motors, speed controllers and propellers could be slightly different. One way to fix this is by adding an integrator. Integrators get rid of static offsets such as those just mentioned. However, as explained above, integrators also always slow vehicle response. In our case, since this offset is going to be constant, we can instead find a \"feed-forward\", or equilibrium offset, torque that you need to apply to hover without drift.
Use the RC transmitter to find the \"equilibrium torques\" about the x, y, and z axes to keep the multirotor level. This is done by trimming the aircraft with the RC trims. These are usually the little switches next to the sticks on your transmitter. Adjust these until you can hover the multirotor without touching the sticks.
Next, land the multirotor, disarm, center the sticks and perform a trim calibration with ros2 service call /calibrate_rc_trim std_srvs/srv/Trigger
. ROSflight then uses the trim settings on your transmitter to find these feed-forward, or equilibrium, torques that need to be applied post-controller to keep the multirotor level. These torques will be applied to all future commands (both from the companion computer and RC), so you will need to zero out your transmitter trims after calibration.
"},{"location":"user-guide/improving-firmware-performance/#estimator-tuning","title":"Estimator Tuning","text":"ROSflight uses a non-linear complementary filter, based on the quaternion implementation of \"Non-linear complementary filters on the special orthogonal group\" by Robert Mahony1, to estimate attitude and angular rates. The implementation has been improved with suggestions from \"Attitude Representation and Kinematic Propagation for Low-Cost UAVs\" by Robert Casey2. A write-up of the derivation and implementation details can be found in the LaTeX report in reports/estimator.tex
. (You'll need to be able to compile LaTeX sources to view the PDF).
In addition to the complementary filter, accelerometer and gyro measurements are filtered using a simple low-pass filter (LPF) to cut out noise from vibrations. A block diagram of the estimator is shown below for reference. y_{gyro} and y_{acc} are gyro and accelerometer measurements, respectively and \\beta_{gyro} is the estimated gyro biases.
"},{"location":"user-guide/improving-firmware-performance/#tuning-the-low-pass-filter-gains","title":"Tuning the Low-Pass Filter Gains","text":"The ACC_LPF_ALPHA
and GYRO_LPF_ALPHA
parameters are used in the following low-pass-filter implementation (see lines 98-106
of estimator.c
):
x_t = (1-\\alpha)y_t + \\alpha x_{t-1} where y_t is the measurement and x_t is the filtered value. Lowering \\alpha will reduce lag in response, so if you feel like your MAV is sluggish despite all attempts at controller gain tuning, consider reducing \\alpha. Reducing \\alpha too far, however will result in a lot of noise from the sensors making its way into the motors. This can cause motors to get really hot, so make sure you check motor temperature if you are changing the low-pass filter constants.
"},{"location":"user-guide/improving-firmware-performance/#tuning-the-complementary-filter","title":"Tuning the Complementary Filter","text":"The complementary filter has two gains, k_p and k_i. For a complete understanding of how these work, we recommend reading the Mahony Paper, or the technical report in the reports folder. In short, k_p can be thought of as the strength of accelerometer measurements in the filter, and the k_i gain is the integral constant on the gyro bias. These values should probably not be changed. Before you go changing these values, make sure you completely understand how they work in the filter.
If you do decide to change these values, you should stick to the following rule of thumb.
k_i \\approx \\tfrac{k_p}{10}."},{"location":"user-guide/improving-firmware-performance/#external-attitude-measurements","title":"External Attitude Measurements","text":"Because the onboard attitude estimator uses only inertial measurements, the estimates can deviate from truth. This is especially true during extended periods of accelerated flight, during which the gravity vector cannot be measured. Attitude measurements from an external source can be applied to the filter to help improve performance. These external attitude measurements might come from a higher-level estimator running on the companion computer that fuses additional information from GPS, vision, or a motion capture system.
To send these updates to the flight controller, publish a geometry_msgs/Quaternion
message to the external_attitude
topic to which rosflight_io
subscribes. The degree to which this update will be trusted is tuned with the FILTER_KP_EXT
parameter.
-
Mahony, R., Hamel, T. and Pflimlin, J. (2008). Nonlinear Complementary Filters on the Special Orthogonal Group. IEEE Transactions on Automatic Control, 53(5), pp.1203-1218.\u00a0\u21a9
-
Casey, R., Karpenko, M., Curry, R. and Elkaim, G. (2013). Attitude Representation and Kinematic Propagation for Low-Cost UAVs. AIAA Guidance, Navigation, and Control (GNC) Conference.\u00a0\u21a9
"},{"location":"user-guide/overview/","title":"Overview","text":""},{"location":"user-guide/overview/#main-components-of-rosflight","title":"Main Components of ROSflight","text":"ROSflight is intended to be used with both a typical flight controller and a companion Linux computer. Although it can be used with just a flight controller, this setup will not offer most of the advantages of ROSflight.
Note
To avoid confusion, we try to consistently use the following terminology:
- Flight controller: The embedded board that runs the ROSflight firmware and performs I/O with sensors and ESCs
- Companion computer: A Linux computer, running ROS2, that is mounted on the vehicle and has a physical, serial connection with the flight controller
- Offboard control (setpoints): The control setpoints passed from the companion computer to the flight controller. The control is \"offboard\" from the perspective of the flight controller, even though the computer providing those commands is mounted onboard the vehicle.
The following figure illustrates the interactions between the major components of the system:
"},{"location":"user-guide/overview/#firmware","title":"Firmware","text":"The ROSflight firmware is the low level microcontroller code that runs on the flight controller. This communicates directly with sensors and actuators and serves as the bridge between hardware and higher level software. The firmware itself is designed to do as little as possible, offloading most of the work to the companion computer.
Although higher level control is offloaded to the companion computer, enough control and functionality is included in the firmware to enable a safety pilot to fly the UAV through any portion of the flight with or without an operating companion computer.
"},{"location":"user-guide/overview/#rosflight-io","title":"ROSflight IO","text":"ROSflight IO is a ROS2 node that runs on the companion computer that communicates directly with the firmware over a serial connection. This serves as the bridge between the firmware and the rest of ROS2 network.
"},{"location":"user-guide/overview/#rosplane-and-roscopter","title":"ROSplane and ROScopter","text":"ROSplane and ROScopter are ROS2 based autonomy stacks that run on the companion computer and do most of the heavy computation of the autopilot. Each portion of their autonomy stacks are organized into highly modular ROS nodes that can be easily swapped out with custom nodes.
ROSplane and ROScopter are not required for using ROSflight and you could choose to use an entirely different autonomy stack if you so desired.
"},{"location":"user-guide/overview/#rc-safety-pilot","title":"RC Safety Pilot","text":"ROSflight is designed for use with offboard control from experimental and research code. As such, it provides several mechanisms for an RC safety pilot to intervene if something goes wrong with the control setpoints coming from the companion computer:
- RC override switch: The safety pilot can flip a switch on the transmitter to take back RC control. Attitude and throttle override can be mapped independently, meaning you can choose one or the other, put them on separate switches, or put them both on the same switch. Details on these switches are provided on the RC configuration page.
- Stick deviations: If a stick is deviated from its center position, then that channel is overridden by RC control. This allows the safety pilot to take control without flipping a switch. This may be useful to provide a momentary correction on a single axis. The fraction of stick travel needed to activate the RC override is controlled by the
RC_OVRD_DEV
parameter. The OVRD_LAG_TIME
parameter controls the amount of time that the override remains active after the sticks return to center. - Minimum throttle: By default, the flight controller takes the minimum of the two throttle commands from RC and offboard control setpoints. This allows the safety pilot to drop the throttle quickly if needed. This behavior can be turned on or off with the
MIN_THROTTLE
parameter.
"},{"location":"user-guide/overview/#arming-errors-failsafe","title":"Arming, Errors & Failsafe","text":"The flight controller can only be armed and disarmed via RC control. Two mechanisms are provided: sticks (left stick down and right to arm, down and left to disarm) and switch. Only one of these options can be active at a time. Details on configuration are given on the RC configuration page.
The firmware runs a number of error checks before allowing the flight controller to arm. Completing the configuration checklist on the Getting Started page should avoid these errors. In addition to a few internal health checks, the following conditions are checked:
- Mixer: Valid mixer must have been selected (see the Hardware Setup documentation page)
- IMU calibration: The IMU must have been calibrated since firmware was flashed (it is recommended that you recalibrate often)
- RC: There must be an active RC connection
In addition to the error checking before arming, the flight controller enters a failsafe mode if the RC connection is lost during flight while armed. While in failsafe mode the flight controller commands level flight with the throttle value defined by the FAILSAFE_THR
parameter.
The following is a simplified version of the finite state machine that defines logic used for the arming, error checks, and failsafe operations:
The state manager also includes functionality for recovering from hard faults if one were to occur, although this is unlikely with unmodified firmware. If a hard fault occurs while the flight controller is armed, the firmware has the ability to immediately rearm after rebooting to enable continued RC control of the vehicle for recovery.
"},{"location":"user-guide/overview/#leds","title":"LEDs","text":"The meaning of the various LEDs is summarized in the following table. The colors of the LEDs may change depending on your specific board:
LED On Off Slow Blink Fast Blink Power (Blue) Board powered - - - Info (Green) RC control Offboard control - - Warning (Red) Armed Disarmed Error (disarmed) Failsafe (armed)"},{"location":"user-guide/parameter-configuration/","title":"Parameters","text":"The ROSflight firmware has several dozen parameters which it uses to customize performance. Parameters are considered semi-static variables. That is, parameters do not change during flight, but they may change between vehicles. Examples of parameters you may wish to change are:
- Fixed-wing vehicle flag
- PID gains
- Mixer choice
- IMU low-pass filter constant
- RC receiver type (PPM or SBUS)
and so on. Access to all parameters is enabled via ROS2 services advertised by rosflight_io
while the flight controller is connected.
"},{"location":"user-guide/parameter-configuration/#parameter-interface","title":"Parameter Interface","text":""},{"location":"user-guide/parameter-configuration/#getting-parameter-values","title":"Getting Parameter Values","text":"Sometimes it is handy to ask the flight controller what the current value of a parameter is. This is accomplished using the param_get
service. As an example, let's retrieve the roll angle controller proportional (P) gain.
ros2 service call /param_get rosflight_msgs/srv/ParamGet \"{name: \"PID_ROLL_ANG_P\"}\"\n
You should get a response similar to the following (this happens to be the default value with floating-point error):
exists: True\nvalue: 0.15000000596\n
"},{"location":"user-guide/parameter-configuration/#changing-parameters","title":"Changing Parameters","text":"Parameters are changed via the param_set
service. As an example, let's change the roll angle controller P gain. (I will assume that the flight controller is connected and rosflight_io
is running in the root namespace.)
ros2 service call /param_set rosflight_msgs/srv/ParamSet \"{name: \"PID_ROLL_ANG_P\", value: 0.08}\"\n
You should get a prompt from rosflight_io
saying
[ INFO] [1491672408.585339558]: Parameter PID_ROLL_ANG_P has new value 0.08\n[ WARN] [1491672408.585508849]: There are unsaved changes to onboard parameters\n
Notice that the parameters have been set, but not saved. Parameter changes take effect immediately, however they will not persist over a reboot unless you write them to the non-volatile memory. This brings us to the next task.
"},{"location":"user-guide/parameter-configuration/#writing-parameters","title":"Writing Parameters","text":"To ensure that parameter values persist between reboots, you must write the parameters to the non-volatile memory. This is done by calling param_write
ros2 service call /param_write std_srvs/srv/Trigger\n
rosflight_io
should then respond with
[ INFO] [1491672597.123201952]: Param write succeeded\n[ INFO] [1491672597.123452908]: Onboard parameters have been saved\n
Warning
It is highly recommended that you write parameters before arming and flying the vehicle. Among other things, this will ensure that in the rare case that a hard fault is encountered and the flight controller must reboot during flight, the correct configuration will be loaded on reboot.
Error
Parameter writing can only happen if the flight controller is disarmed. If the param write failed for some reason, you may want to make sure your FC is disarmed and try again.
"},{"location":"user-guide/parameter-configuration/#backing-up-and-loading-parameters-from-file","title":"Backing Up and Loading Parameters from File","text":"It is good practice to back up your parameter configuration in case you have to re-flash your firmware or you want to share configurations between vehicles. We can do this via the param_save_to_file
and param_load_from_file
services.
First, let's back up our current parameter configuration:
ros2 service call /param_save_to_file rosflight_msgs/srv/ParamFile \"{filename: \"~/parameters.yaml\"}\"\n
Parameters are saved in YAML format. You must also specify the absolute file name of where you would like your parameters to be saved. The current active set of parameters will be saved, regardless of what is saved in non-volatile memory on the flight controller.
Now, let's say we want to re-load this parameter file
ros2 service call /param_load_from_file rosflight_msgs/srv/ParamFile \"{filename: \"~/parameters.yml\"}\"\n
Again, you must specify the absolute file name of the file to be loaded."},{"location":"user-guide/parameter-configuration/#fixed-wing-parameter-configuration","title":"Fixed-Wing Parameter Configuration","text":"Because ROSflight ships with default parameters for multirotors, you will probably want to change the following parameters if you want to fly a fixed-wing aircraft.
Parameter Description Type Fixed-Wing Value MOTOR_PWM_UPDATE Refresh rate of motor commands to motors and servos (Hz) - See motor documentation int 50 ARM_SPIN_MOTORS Enforce MOTOR_IDLE_PWM int false MOTOR_IDLE_THR min throttle command sent to motors when armed (Set above 0.1 to spin when armed) float 0.1 ARM_CHANNEL RC switch channel mapped to arming [0 indexed, -1 to disable] int 4 FIXED_WING switches on passthrough commands for fixed-wing operation int true MIXER Which mixer to choose - See Mixer documentation int 10 ELEVATOR_REV reverses elevator servo output int 0/1 AIL_REV reverses aileron servo output int 0/1 RUDDER_REV reverses rudder servo output int 0/1 CAL_GYRO_ARM Calibrate gyros when arming - generally only for multirotors int false"},{"location":"user-guide/parameter-configuration/#description-of-all-parameters","title":"Description of all Parameters","text":"This is a list of all ROSflight parameters, including their types, default values, and minimum and maximum recommended values:
Parameter Description Type Default Value Min Max BAUD_RATE Baud rate of MAVlink communication with companion computer int 921600 9600 921600 SERIAL_DEVICE Serial Port (for supported devices) int 0 0 3 SYS_ID Mavlink System ID int 1 1 255 STRM_HRTBT Rate of heartbeat stream (Hz) int 1 0 1000 STRM_STATUS Rate of status stream (Hz) int 10 0 1000 STRM_ATTITUDE Rate of attitude stream (Hz) int 200 0 1000 STRM_IMU Rate of IMU stream (Hz) int 250 0 1000 STRM_MAG Rate of magnetometer stream (Hz) int 50 0 75 STRM_BARO Rate of barometer stream (Hz) int 50 0 100 STRM_AIRSPEED Rate of airspeed stream (Hz) int 50 0 50 STRM_SONAR Rate of sonar stream (Hz) int 40 0 40 STRM_SERVO Rate of raw output stream int 50 0 490 STRM_RC Rate of raw RC input stream int 50 0 50 STRM_GNSS Maximum rate of GNSS data streaming. Higher values allow for lower latency int 1000 0 1000 STRM_GNSS_FULL Maximum rate of fully detailed GNSS data streaming int 0 0 10 STRM_BATTERY Rate of battery status stream int 0 0 50 PARAM_MAX_CMD saturation point for PID controller output float 1.0 0 1.0 PID_ROLL_RATE_P Roll Rate Proportional Gain float 0.070f 0.0 1000.0 PID_ROLL_RATE_I Roll Rate Integral Gain float 0.000f 0.0 1000.0 PID_ROLL_RATE_D Roll Rate Derivative Gain float 0.000f 0.0 1000.0 PID_PITCH_RATE_P Pitch Rate Proportional Gain float 0.070f 0.0 1000.0 PID_PITCH_RATE_I Pitch Rate Integral Gain float 0.0000f 0.0 1000.0 PID_PITCH_RATE_D Pitch Rate Derivative Gain float 0.0000f 0.0 1000.0 PID_YAW_RATE_P Yaw Rate Proportional Gain float 0.25f 0.0 1000.0 PID_YAW_RATE_I Yaw Rate Integral Gain float 0.0f 0.0 1000.0 PID_YAW_RATE_D Yaw Rate Derivative Gain float 0.0f 0.0 1000.0 PID_ROLL_ANG_P Roll Angle Proportional Gain float 0.15f 0.0 1000.0 PID_ROLL_ANG_I Roll Angle Integral Gain float 0.0f 0.0 1000.0 PID_ROLL_ANG_D Roll Angle Derivative Gain float 0.05f 0.0 1000.0 PID_PITCH_ANG_P Pitch Angle Proportional Gain float 0.15f 0.0 1000.0 PID_PITCH_ANG_I Pitch Angle Integral Gain float 0.0f 0.0 1000.0 PID_PITCH_ANG_D Pitch Angle Derivative Gain float 0.05f 0.0 1000.0 X_EQ_TORQUE Equilibrium torque added to output of controller on x axis float 0.0f -1.0 1.0 Y_EQ_TORQUE Equilibrium torque added to output of controller on y axis float 0.0f -1.0 1.0 Z_EQ_TORQUE Equilibrium torque added to output of controller on z axis float 0.0f -1.0 1.0 PID_TAU Dirty Derivative time constant - See controller documentation float 0.05f 0.0 1.0 MOTOR_PWM_UPDATE Overrides default PWM rate specified by mixer if non-zero - Requires reboot to take effect int 0 0 490 MOTOR_IDLE_THR min throttle command sent to motors when armed (Set above 0.1 to spin when armed) float 0.1 0.0 1.0 FAILSAFE_THR Throttle sent to motors in failsafe condition (set just below hover throttle) float 0.3 0.0 1.0 ARM_SPIN_MOTORS Enforce MOTOR_IDLE_THR int true 0 1 FILTER_INIT_T Time in ms to initialize estimator int 3000 0 100000 FILTER_KP estimator proportional gain - See estimator documentation float 0.5f 0 10.0 FILTER_KI estimator integral gain - See estimator documentation float 0.01f 0 1.0 FILTER_KP_COR estimator proportional gain on external attitude correction - See estimator documentation float 10.0f 0 1.0 FILTER_ACCMARGIN allowable accel norm margin around 1g to determine if accel is usable float 0.1f 0 1.0 FILTER_QUAD_INT Perform a quadratic averaging of LPF gyro data prior to integration (adds ~20 us to estimation loop on F1 processors) int 1 0 1 FILTER_MAT_EXP 1 - Use matrix exponential to improve gyro integration (adds ~90 us to estimation loop in F1 processors) 0 - use euler integration int 1 0 1 FILTER_USE_ACC Use accelerometer to correct gyro integration drift (adds ~70 us to estimation loop) int 1 0 1 CAL_GYRO_ARM True if desired to calibrate gyros on arm int false 0 1 GYROXY_LPF_ALPHA Low-pass filter constant on gyro X and Y axes - See estimator documentation float 0.3f 0 1.0 GYROZ_LPF_ALPHA Low-pass filter constant on gyro Z axis - See estimator documentation float 0.3f 0 1.0 ACC_LPF_ALPHA Low-pass filter constant on all accel axes - See estimator documentation float 0.5f 0 1.0 GYRO_X_BIAS Constant x-bias of gyroscope readings float 0.0f -1.0 1.0 GYRO_Y_BIAS Constant y-bias of gyroscope readings float 0.0f -1.0 1.0 GYRO_Z_BIAS Constant z-bias of gyroscope readings float 0.0f -1.0 1.0 ACC_X_BIAS Constant x-bias of accelerometer readings float 0.0f -2.0 2.0 ACC_Y_BIAS Constant y-bias of accelerometer readings float 0.0f -2.0 2.0 ACC_Z_BIAS Constant z-bias of accelerometer readings float 0.0f -2.0 2.0 ACC_X_TEMP_COMP Linear x-axis temperature compensation constant float 0.0f -2.0 2.0 ACC_Y_TEMP_COMP Linear y-axis temperature compensation constant float 0.0f -2.0 2.0 ACC_Z_TEMP_COMP Linear z-axis temperature compensation constant float 0.0f -2.0 2.0 MAG_A11_COMP Soft iron compensation constant float 1.0f -999.0 999.0 MAG_A12_COMP Soft iron compensation constant float 0.0f -999.0 999.0 MAG_A13_COMP Soft iron compensation constant float 0.0f -999.0 999.0 MAG_A21_COMP Soft iron compensation constant float 0.0f -999.0 999.0 MAG_A22_COMP Soft iron compensation constant float 1.0f -999.0 999.0 MAG_A23_COMP Soft iron compensation constant float 0.0f -999.0 999.0 MAG_A31_COMP Soft iron compensation constant float 0.0f -999.0 999.0 MAG_A32_COMP Soft iron compensation constant float 0.0f -999.0 999.0 MAG_A33_COMP Soft iron compensation constant float 1.0f -999.0 999.0 MAG_X_BIAS Hard iron compensation constant float 0.0f -999.0 999.0 MAG_Y_BIAS Hard iron compensation constant float 0.0f -999.0 999.0 MAG_Z_BIAS Hard iron compensation constant float 0.0f -999.0 999.0 BARO_BIAS Barometer measurement bias (Pa) float 0.0f 0 inf GROUND_LEVEL Altitude of ground level (m) float 1387.0f -1000 10000 DIFF_PRESS_BIAS Differential Pressure Bias (Pa) float 0.0f -10 10 RC_TYPE Type of RC input 0 - PPM, 1 - SBUS int 0 0 1 BATT_VOLT_MULT Battery monitor voltage multiplier float 0 0 inf BATT_CURR_MULT Battery monitor current multiplier float 0 0 inf BATT_VOLT_ALPHA Batter monitor voltage filter alpha. Values closer to 1 smooth the signal more. float 0.995 0 1 BATT_CURR_ALPHA Battery monitor current filter alpha. Values closer to 1 smooth the signal more. float 0.995 0 1 RC_X_CHN RC input channel mapped to x-axis commands [0 - indexed] int 0 0 3 RC_Y_CHN RC input channel mapped to y-axis commands [0 - indexed] int 1 0 3 RC_Z_CHN RC input channel mapped to z-axis commands [0 - indexed] int 3 0 3 RC_F_CHN RC input channel mapped to F-axis commands [0 - indexed] int 2 0 3 RC_ATT_OVRD_CHN RC switch mapped to attitude override [0 indexed, -1 to disable] int 4 4 7 RC_THR_OVRD_CHN RC switch channel mapped to throttle override [0 indexed, -1 to disable] int 4 4 7 RC_ATT_CTRL_CHN RC switch channel mapped to attitude control type [0 indexed, -1 to disable] int -1 4 7 ARM_CHANNEL RC switch channel mapped to arming (only if PARAM_ARM_STICKS is false) [0 indexed, -1 to disable] int -1 4 7 RC_NUM_CHN number of RC input channels int 6 1 8 SWITCH_5_DIR RC switch 5 toggle direction int 1 -1 1 SWITCH_6_DIR RC switch 6 toggle direction int 1 -1 1 SWITCH_7_DIR RC switch 7 toggle direction int 1 -1 1 SWITCH_8_DIR RC switch 8 toggle direction int 1 -1 1 RC_OVRD_DEV RC stick deviation from center for override float 0.1 0.0 1.0 OVRD_LAG_TIME RC stick deviation lag time before returning control (ms) int 1000 0 100000 MIN_THROTTLE Take minimum throttle between RC and computer at all times int true 0 1 RC_ATT_MODE Attitude mode for RC sticks (0: rate, 1: angle). Overridden if RC_ATT_CTRL_CHN is set. int 1 0 1 RC_MAX_ROLL Maximum roll angle command sent by full deflection of RC sticks float 0.786f 0.0 3.14159 RC_MAX_PITCH Maximum pitch angle command sent by full stick deflection of RC sticks float 0.786f 0.0 3.14159 RC_MAX_ROLLRATE Maximum roll rate command sent by full stick deflection of RC sticks float 3.14159f 0.0 9.42477796077 RC_MAX_PITCHRATE Maximum pitch command sent by full stick deflection of RC sticks float 3.14159f 0.0 3.14159 RC_MAX_YAWRATE Maximum pitch command sent by full stick deflection of RC sticks float 1.507f 0.0 3.14159 MIXER Which mixer to choose - See Mixer documentation int Mixer::INVALID_MIXER 0 10 FIXED_WING switches on pass-through commands for fixed-wing operation int false 0 1 ELEVATOR_REV reverses elevator servo output int 0 0 1 AIL_REV reverses aileron servo output int 0 0 1 RUDDER_REV reverses rudder servo output int 0 0 1 FC_ROLL roll angle (deg) of flight controller wrt aircraft body float 0.0f 0 360 FC_PITCH pitch angle (deg) of flight controller wrt aircraft body float 0.0f 0 360 FC_YAW yaw angle (deg) of flight controller wrt aircraft body float 0.0f 0 360 ARM_THRESHOLD RC deviation from max/min in yaw and throttle for arming and disarming check (us) float 0.15 0 500 OFFBOARD_TIMEOUT Timeout in milliseconds for offboard commands, after which RC override is activated int 100 0 100000"},{"location":"user-guide/preflight-checks/","title":"Pre-Flight Checklist","text":"This is an example of a ROSflight pre-flight checklist. You will likely need to augment this with checks specific to both (a) your hardware and (b) the code running on your companion computer.
"},{"location":"user-guide/preflight-checks/#before-powering-up-motors","title":"Before powering up motors","text":" - ROS2 is running on the companion computer, communicating with the base station
-
rosflight_io
reports no errors - Sensors are calibrated and publishing
- IMU (re-calibrate every flight):
ros2 service call /calibrate_imu std_srvs/srv/Trigger
- Barometer:
ros2 service call /calibrate_baro std_srvs/srv/Trigger
- Sonar (if attached)
- Airspeed (if attached)
- Estimated attitude is being published and looks accurate
- Published outputs look reasonable
- Parameter Check (if using a fixed-wing, there are about 8 parameters you will need to change from default)
- RC communication
- Failsafe behavior
- Arming and disarming
- RC override behavior
- RC range test
- Wire-wiggle test (wiggle all wires to look for bad connections)
- If desired, logging is turned on (e.g. recording a ros2 bag)
"},{"location":"user-guide/preflight-checks/#after-powering-up-motors","title":"After Powering Up Motors","text":"Danger
Be sure the flight controller is disarmed before powering up motors!!!
- Arm/Disarm test
- Propeller spin test (check directions and response to stick inputs)
- Control surface test (fixed-wing)
- Response to offboard controls
"},{"location":"user-guide/rc-configuration/","title":"RC Configuration","text":""},{"location":"user-guide/rc-configuration/#binding-your-transmitter-to-your-receiver","title":"Binding your Transmitter to your Receiver","text":"Follow the instructions in your user manual to bind your transmitter to your RC receiver. You may also be able to find a guide on YouTube with instructions; just search for your particular transmitter and receiver model.
"},{"location":"user-guide/rc-configuration/#rc-transmitter-calibration","title":"RC Transmitter Calibration","text":"To avoid confusion and to reduce code complexity in the firmware source code, ROSflight does not perform software calibration of RC transmitters. This means that RC calibration must be done on the transmitter itself, as opposed to in software. This is pretty straight-forward for most modern transmitters.
"},{"location":"user-guide/rc-configuration/#configure-the-full-stick-output-for-each-channel","title":"Configure the full stick output for each channel","text":"The easiest way to do this is to enter the \"Servo Setup\" Menu (for Spektrum transmitters) and change the servo travel variable. You can watch the raw RC readings from the flight controller by echoing the rc_raw topic from rosflight_io
ros2 topic echo /rc_raw\n
- Center both sticks on your transmitter
- Apply subtrim until the first four channels all read 1500 exactly (or as close as possible--some RC receivers are worse than others and cannot exactly output 1500 us)
- Set the channel endpoints so that maximum stick deflections result in readings of 1000 and 2000 us.
"},{"location":"user-guide/rc-configuration/#configure-stick-directions-for-roll-pitch-and-yaw-channels","title":"Configure stick directions for roll, pitch, and yaw channels.","text":"You now have to make sure your RC transmitter is sending commands consistent with the north-east-down (NED) frame assumed by ROSflight.
You may find this graphic helpful. It shows all the basic stick positions, and the associated output from the first four channels when looking at a raw AETR (aileron, elevator, throttle, rudder) RC signal from rosflight_io
. Make sure that the stick output is in the correct direction.
It should be noted that channel assignment can be modified via the RC_*_CHN
parameters. So, if you are using something other than AETR assignment, the channel index for each stick may be different, but the direction should be the same.
"},{"location":"user-guide/rc-configuration/#switch-configuration","title":"Switch Configuration","text":"Switches can be configured for the following functions. To disable a switch for a specific, default function, set the corresponding parameter to -1
. Be sure to check that the switch directions operate as you intend, and reverse them in your transmitter if necessary.
"},{"location":"user-guide/rc-configuration/#safety-pilot-configuration","title":"Safety Pilot Configuration","text":"The RC_ATT_OVRD_CHN
parameter maps a switch to override attitude commands with RC control. The RC_THR_OVRD_CHN
parameter maps a switch to override throttle commands with RC control. To override both with a single switch, set both parameters to the same value (this is the default behavior).
"},{"location":"user-guide/rc-configuration/#arming","title":"Arming","text":"By default, arming is done with the sticks (left stick down and right to arm, down and left to disarm). To use a switch instead, set the ARM_CHANNEL
parameter to the desired channel. Setting an arming switch disables arming with the sticks.
"},{"location":"user-guide/rc-configuration/#flight-mode","title":"Flight Mode","text":"If desired, you can map a switch to select between attitude control types (angle and rate) in flight by setting the RC_ATT_CTRL_CHN
parameter to the desired channel. This can be useful if, for example, you are learning rate mode but want to be able to switch back to attitude mode to help stabilize the vehicle. This feature is disabled by default.
"},{"location":"user-guide/ros2-setup/","title":"Installing/Setting up ROS2","text":"You will need to get ROS2 on both the companion computer and the base station laptop. This can be done with a native installation or with Docker. To install ROS2 natively, Check out the official ROS2 Installation page for details. Make sure to install both the ros-humble-desktop
and ros-dev-tools
packages, or the equivalent packages for your version of ROS2. ros-humble-ros-base
can be used instead of ros-humble-desktop
if you don't need GUI tools or the simulation.
We support all fixed-release ROS2 versions that are not EOL, which currently includes ROS2 Humble and ROS2 Iron. ROS2 Rolling is not fixed-release and is therefore not officially supported.
"},{"location":"user-guide/ros2-setup/#installing-rosflight","title":"Installing ROSflight","text":"You will need to install the ROSflight packages on both the companion computer and the base station computer. The companion computer will run the node that actually communicates with the flight controller over a serial connection, while the base station needs the message and service definitions to be able to call services or subscribe and publish to topics.
"},{"location":"user-guide/ros2-setup/#from-source","title":"From Source","text":"First, set up a ROS2 workspace:
mkdir -p ~/rosflight_ws/src\ncd ~/rosflight_ws/src\n
Next, download the source code into your workspace (include the --recursive
argument to download the necessary submodules):
git clone --recursive https://github.com/rosflight/rosflight_ros_pkgs.git\n
Install dependencies:
sudo rosdep init\nrosdep update\nrosdep install --from-path . -y --ignore-src\n
Note
Gazebo does not have an arm64 build target. If using a companion computer with arm64 architecture, append --skip-keys=\"gazebo_dev gazebo_plugins gazebo_ros gazebo\"
to the rosdep install
command above. This will skip installing Gazebo and the compilation of rosflight_sim, which currently requires Gazebo.
Build the packages:
cd ~/rosflight_ws\ncolcon build\n
Source the setup file and set it to be sourced automatically:
source ~/rosflight_ws/install/setup.bash\necho \"source ~/rosflight_ws/install/setup.bash\" >> ~/.bashrc\n
Note
You'll also need to source the file at /usr/share/gazebo/setup.sh
if you plan to use the Gazebo simulator.
"},{"location":"user-guide/ros2-setup/#running-rosflight_io","title":"Running rosflight_io","text":"The rosflight_io
node is the bridge between ROS2 and the MAVLink communication with the flight controller. This node must be run on the computer that has the physical serial connection to your flight controller. To run this node, use something like the following command:
ros2 run rosflight_io rosflight_io --ros-args -p port:=/dev/ttyUSB0\n
Replace /dev/ttyUSB0
with the port your flight controller is connected to."},{"location":"user-guide/ros2-setup/#using-a-docker-container-to-run-ros2","title":"Using a Docker Container to run ROS2","text":"Note
This guide was written for using Linux as the host machine, but theoretically you should be able to use Docker to do the same thing on Mac or Windows. However, the specifics of the commands may be different. Please refer to the Docker documentation for information on how to use Docker on a non-Linux system.
Tip
This guide was written using ROS2 Humble Docker images, but any distribution of ROS can be used. Just replace humble
with the name of the distribution you want to use.
If you aren't running a compatible version of Linux for ROS2, don't want to make changes to your system, want to be able to easily switch between ROS verions, or just want to containerize your applications, then you can use Docker containers. To get started, install Docker Engine, sometimes referred to as Docker server.
Docker works by running self-contained systems called containers, which act kind of like a separate computer system but without all the overhead of a full virtual machine. Docker containers are based on Docker images, which provide the initial operating system, files, and programs for the Docker container. Fortunately, the developers of ROS provide Docker images for nearly all versions of ROS, which makes it very easy to get any version of ROS up and running on your system very quickly.
- To start a Docker container with ROS run this command:
docker run -it ros:humble\n
Once completed, you should enter a bash terminal in a fresh installation of Ubuntu and ROS! However, the container does not have access to any USB devices, source files on your system, or your network to be able to communicate with different computers. To do these things we'll need to add more arguments to the docker run
command.
-
To give access to source file on your system, mount a folder on your system to the docker container with the -v
argument:
docker run -it -v /folder_to_mount_from_host:/location_to_mount_folder_in_container ros:humble\n
-
To give access to a USB device, you need to mount the location of the USB device and give the container sudo access to your host system with --privileged
:
docker run -it -v /dev/usb_to_mount:/dev/USB --privileged ros:humble\n
-
You can also mount the entire /dev
folder to the container if you want to simplify the process of giving access to USB devices by not needing to know the address of the USB device beforehand. However, the more resources you give to the container, the less secure it is:
docker run -it -v /dev:/dev --privileged ros:humble\n
-
To give access to your network, specify the network to use as the host's network with --network host
.
docker run -it --network host ros:humble\n
It is worth noting that every time you use the docker run
command, a new container with those specific arguments are created. So, if you want a container with access to all those things, you need to use all the arguments at once.
- As an example, if I wanted to make a ROS2 Humble container with access to a USB device at
/dev/ttyUSB0
, access to my host network, access to the source files at ~/rosflight_ws
, and give the container a convenient name of rosflight
with the --name
argument, I would use this command: docker run --name rosflight -it -v /dev/ttyUSB0:/dev/ttyUSB0 --privileged --network host -v ~/rosflight_ws:/root/rosflight_ws ros:humble\n
Something the previous commands don't include is the ability to render GUI tools (like rqt_graph and Gazebo). Being able to render GUI tools can be done a number of ways, but an easy way is to give the container access to your system's X11 windowing system. Note that this isn't the most secure method and doesn't include GPU acceleration. (For more information about including GPU acceleration, refer to the guide found here.)
-
To give access to the host's windowing system, use the following commands. Note that the base Docker image is osrf/ros:humble-desktop-full
, as ros:humble
doesn't include GUI tools in the image. Also, xhost +local:root
needs to be run once per login session and is not persistent.
xhost +local:root\ndocker run -it --env=\"DISPLAY\" --env=\"QT_X11_NO_MITSHM=1\" --volume=\"/tmp/.X11-unix:/tmp/.X11-unix:rw\" osrf/ros:humble-desktop-full\n
-
To create a GUI enabled ROS container named rosflight
with access to the host network, source files found at ~/rosflight_ws
, and a USB device, use this command:
xhost +local:root\ndocker run --name rosflight -it -v /dev/ttyUSB0:/dev/ttyUSB0 --privileged --network host -v ~/rosflight_ws:/rosflight_ws --env=\"DISPLAY\" --env=\"QT_X11_NO_MITSHM=1\" --volume=\"/tmp/.X11-unix:/tmp/.X11-unix:rw\" osrf/ros:humble-desktop-full\n
Warning
During testing, we found some strange behavior with ROS when running a GUI enabled container on a system with ROS already installed. If you need a GUI enabled system, try to do so on a system without ROS installed (or at the very least avoid sourcing/using ROS on your system). Also avoid having multiple GUI enabled containers running at once.
Some other useful Docker commands:
-
To see all containers that exist on your system and their names:
docker ps -a\n
-
To start a container named rosflight
that was previously created with the docker run
command:
docker start -i rosflight\n
-
To open another bash terminal in a container named rosflight
that is already running:
docker exec -it rosflight bash\n
-
To delete a container named rosflight
:
docker rm rosflight\n
You should now be able to create Docker containers with everything you need to run ROSflight! Docker is a very powerful tool and there is much more you can do with Docker to improve your development workflow. However, we're not interested in making an exhaustive Docker guide so please refer to the Docker documentation or other online guides to learn more.
"},{"location":"user-guide/roscopter-setup/","title":"ROScopter","text":"ROScopter is still under development. Check the github repo for the latest instructions.
"},{"location":"user-guide/rosplane-setup/","title":"ROSplane Setup","text":"ROSplane v2.0.0-beta is now available! Check the github repo for the latest instructions.
ROSplane is a basic fixed-wing autopilot build around ROS2 for use with the ROSflight autopilot. It is built according to the methods published in Small Unmanned Aircraft: Theory and Practice by Dr. Randy Beard and Dr. Tim McLain.
"},{"location":"user-guide/rosplane-setup/#requirements","title":"Requirements","text":"ROSplane requires a working ROS2 installation on a companion computer. ROSplane will most often be used in conjunction with the ROSflight firmware and the firmware interface (aka rosflight_ros_pkgs
).
Follow the instructions on ROS2 Setup to install and set up ROS2 and rosflight_ros_pkgs
.
"},{"location":"user-guide/rosplane-setup/#installation","title":"Installation","text":"You will need to install ROSplane on the companion computer.
First, navigate to the src directory of the ROS2 workspace and clone the git repository:
cd /path/to/rosflight_ws/src\ngit clone https://github.com/rosflight/rosplane.git\n
Note
Your rosflight_ws
file structure should now look like:
rosflight_ws\n \u2514\u2500\u2500 src \n \u251c\u2500\u2500 rosflight_ros_pkgs\n \u2514\u2500\u2500 rosplane \n
Then navigate to the top of the rosflight_ws
directory and build:
cd ..\ncolcon build\n
Next, source the rosflight_ws
install files. If you already added the source command to your .bashrc
from the ROS2 Setup page, then you can skip this step.
# source the install file\nsource install/setup.bash\n\n# add it to your .bashrc\necho \"source install/setup.bash >> $HOME/.bashrc\"\n
Note that sourcing the setup.bash
file in the rosflight_ws
directory will install all ROS2 packages in any subdirectories.
"},{"location":"user-guide/rosplane-setup/#running-rosplane-sil","title":"Running ROSplane SIL","text":"A controller or a simulated controller can be used to fly the aircraft in simulation. See the README.md
file for the rosflight_ros_pkgs
package for more information on RC controll in simulation.
"},{"location":"user-guide/rosplane-setup/#launching","title":"Launching","text":""},{"location":"user-guide/rosplane-setup/#recommended-method","title":"Recommended Method","text":"A convenience bash script has been included that uses tmux to launch Gazebo, an instance of the ROSflight firmware, and ROSplane. Note that this requires tmux, so you may need to install it with sudo apt install tmux
. Run
./src/rosplane/rosplane/scripts/rosplane_gcs_launch.sh\n
from the rosflight_ws
directory. Note that the script needs options specified, so it will fail. However,it will print out the required configuration options. See the script for more information."},{"location":"user-guide/rosplane-setup/#alternative-method","title":"Alternative Method","text":"Alternatively, you can run each of the commands in the bash script individually:
# Terminal 1 - Launches Gazebo and a simulated instance of the firmware\nros2 launch rosflight_sim fixedwing.launch.py\n\n# Terminal 2 - Runs rosflight_io configured for SIL to interface with the firmware\nros2 run rosflight_io rosflight_io --ros-args -p udp:=true\n\n# Terminal 3 - Launches rosplane with the Anaconda aerodynamic coefficients\nros2 launch rosplane_sim sim.launch.py aircraft:=anaconda\n
You can also replace the first two commands above with the convenience launch file that does both:
ros2 launch rosflight_sim fixedwing_sim_io_joy.launch.py aircraft:=anaconda\n
Remember to launch ROSplane if you use this method."},{"location":"user-guide/rosplane-setup/#additional-setup","title":"Additional Setup","text":""},{"location":"user-guide/rosplane-setup/#recommended-method_1","title":"Recommended Method","text":"If this is your first time launching ROSplane, make sure to run the convenience launch script to initialize the firmware parameters and calibrate the IMU.
ros2 launch rosflight_sim fixedwing_init_firmware.launch.py\n
"},{"location":"user-guide/rosplane-setup/#alternative-method_1","title":"Alternative Method","text":"Alternatively, you can run the following commands to initialize firmware parameters and calibrate the IMU. Firmware parameters should first be loaded using
ros2 service call /param_load_from_file rosflight_msgs/srv/ParamFile \"filename: /path/to/rosflight_ws/src/rosflight_ros_pkgs/rosflight_sim/params/fixedwing_firmware.yaml\"\n
The IMU should then be calibrated to remove the random biases generated at startup. Note that the random number generator used to create these biases is seeded with a constant value, so this calibration should only need to be performed once. See the code to change the way these biases are calculated.
ros2 service call /calibrate_imu std_srvs/srv/Trigger\n
After calibrating, write the parameters to a file using:
ros2 service call /param_write std_srvs/srv/Trigger\n
This command will create a directory named rosflight_memory
where the parameters are written. The ROSflight firmware will automatically check if the rosflight_memory
directory is present when launched and will use those parameters if available. Note
The ROSflight firmware will only look for the rosflight_memory
directory in the directory where the launch command is run. You must launch rosflight_sim
in the same directory to use the saved parameters; otherwise, reload and re-write the parameters.
"},{"location":"user-guide/rosplane-setup/#flying-in-sim","title":"Flying in Sim","text":"Once you have the simulation booted up, use channel 4 of a connected transmitter to arm. If you are using a simulated transmitter, use ros2 service call /toggle_arm std_srvs/srv/Trigger
to toggle arm/disarm.
After arming, the plane will operate under RC control. Verify that the commands are working and that the aircraft is responding as expected.
To fly autonomously, use channel 5 to disable RC override. If using a simulated transmitter, use ros2 service call /toggle_override std_srvs/srv/Trigger
to toggle RC override on/off.
The plane should then take off or fly autonomously in the Gazebo simulator!
"},{"location":"user-guide/rosplane-setup/#running-rosplane-on-hardware","title":"Running ROSplane on Hardware","text":"Ensure rosflight_io
is running on the companion computer, and that the flight controller is connects to the companion computer.
Launch ROSplane using
ros2 launch rosplane rosplane.launch.py\n
Arm the aircraft using channel 4 of the safety RC transmitter. When ready to let ROSplane take control, use channel 5 of the RC transmitter to disable RC override.
Warning
Disabling RC override on hardware will turn control over to ROSplane. A safety pilot should always be ready to take control, especially when running untested code.
"},{"location":"user-guide/rosplane-setup/#flying-waypoint-missions-in-sim-and-hardware","title":"Flying Waypoint Missions (in sim and hardware)","text":"Autonomous waypoint missions can easily be flown using ROSplane. The waypoints of a mission are controlled by the path_planner
node. These waypoints are sent to the path_manager
node. Low level path-following is done by the path_follower
node. See \"Small Unmanned Aircraft: Theory and Practice\" by Dr. Randy Beard and Dr. Tim McLain for more information on the architecture. See Path Planning for more information on how to use and tune the path planner, manager, and follower.
"},{"location":"user-guide/rosplane-setup/#adding-waypoints","title":"Adding waypoints","text":""},{"location":"user-guide/rosplane-setup/#recommended-method_2","title":"Recommended Method","text":"ROSplane initializes with no waypoints added to the path_planner
. We recommend using a mission .yaml file (an example mission can be found in rosplane/params/fixedwing_mission.yaml
). Loading the mission can be done using
ros2 service call /load_mission_from_file rosflight_msgs/srv/ParamFile \"{filename: <FILENAME>}\"\n
where FILENAME
is the absolute path to the mission .yaml file. Note that the origin (0,0,0) is placed at the GNSS location where ROSplane was initialized.
Note
All waypoints must include a valid [X, Y, Z]
, va_d
, and lla
values.
"},{"location":"user-guide/rosplane-setup/#alternative-method_2","title":"Alternative Method","text":"Alternatively, you can add a waypoint one at a time by calling the appropriate service
ros2 service call /add_waypoint rosplane_msgs/srv/AddWaypoint \"{w: [X, Y, Z], chi_d: CHI_D, lla: USE_LLA, use_chi: USE_CHI, va_d: VA_D}\"\n
where [X, Y, Z]
is the NED position of the waypoint from the origin (in meters) OR the GNSS location of the waypoint (LLA), CHI_D
is the desired heading at the waypoint, and VA_D
is the airspeed at the waypoint. Set the lla
field to true
if the waypoint [X, Y, Z]
field is given in GNSS coordinates and false
if given in NED coordinates. Corners in the path are controlled by USE_CHI
, where a value of True
will cause ROSplane to use a Dubins path planner and a value of False
will cause a fillet path planner to be used. Adding waypoints can be done at any time, even after loading from a file.
Clearing waypoints can be done using
ros2 service call /clear_waypoints std_msgs/srv/Trigger\n
"},{"location":"user-guide/rosplane-setup/#publishing-waypoints","title":"Publishing Waypoints","text":"The path_planner
node automatically publishes a small number of waypoints (default is 3) at the beginning of this mission. This number is controlled by the num_waypoints_to_publish_at_start
ROS2 parameter.
Additional waypoints can be published using
ros2 service call /publish_next_waypoint std_srvs/srv/Trigger\n
"},{"location":"user-guide/running-gazebo-simulation/","title":"Running Simulations in Gazebo","text":"ROSflight comes with a useful tool allowing it to perform software-in-the-loop (SIL) simulations of the ROSflight firmware in Gazebo.
"},{"location":"user-guide/running-gazebo-simulation/#architecture-of-the-sil-simulation","title":"Architecture of the SIL Simulation","text":"To best mimic the hardware experience of ROSflight, the SIL plugin for Gazebo actually implements the firmware source code as a library. We just implemented a different \"board layer\" which uses gazebo instead of hardware calls for things like imu_read()
and pwm_write()
. Instead of a serial link over USB to the flight controller, we use a UDP connection bouncing off of localhost to communicate between rosflight_io
and the firmware. This means the interface to the SIL plugin is identical to that of hardware. rosflight_io
is the main gateway to the firmware in simulation, just as it is in hardware.
The following table summarizes the correlation between connections in hardware and simulation:
Connection Type Hardware Simulation Serial communications to rosflight_io
USB / UART UDP RC PPM Receiver ROS2 RC
topic (rosflight_msgs/RCRaw
) Motors PWM Gazebo Plugin Sensors SPI/I2C Gazebo Plugin"},{"location":"user-guide/running-gazebo-simulation/#quick-start-guide-to-sil-simulation","title":"Quick-Start Guide to SIL Simulation","text":"Note
To simulate a fixed-wing mav, just change all instances of multirotor
in the steps below to fixedwing
.
-
Setup ROSflight with the ROS2 Setup guide, making sure to install the -desktop
package of ROS2, not the -ros-base
.
-
Source the Gazebo setup file if you haven't added it to ~/.bashrc
:
source /usr/share/gazebo/setup.sh\n
-
Launch Gazebo with the ROSflight SIL:
ros2 launch rosflight_sim multirotor.launch.py\n
-
Gazebo should now be running, and you should have the following rqt_graph
.
-
At this point, you can't actually do anything because there is no RC connection and no rosflight_io
to talk to the firmware. Let's start by running a rosflight_io
node. In a separate terminal, run:
ros2 run rosflight_io rosflight_io --ros-args -p udp:=true\n
- The
udp
parameter tells rosflight_io
to simulate a serial connection over UDP rather than using the USB connection to hardware
Your rqt_graph
should look something like the following image. This looks funny because ROS2 doesn't actually know that there is a UDP connection between rosflight_io
and gazebo. There is one, though, and you can test it by echoing any of the topics published by rosflight_io
.
- Start up a simulated RC connection. The easiest way to do this is with the ROSflight utility
rc_joy.py
. Connect a joystick to the computer (or transmitter) and run: ros2 run rosflight_sim rc_joy.py --ros-args --remap /RC:=/multirotor/RC\n
This simulates the RC connection in hardware. If everything is mapped correctly, you should now be able to arm, disarm and fly the aircraft in simulation!
Tip
To start the Gazebo sim, rosflight_io node, and rc_joy.py utility all at once, run this command instead of the three commands individually:
ros2 launch rosflight_sim multirotor_sim_io_joy.launch.py \n
Note
It is much easier to fly with a real transmitter than with an Xbox-type controller. FrSky Taranis QX7 transmitters, Radiomaster TX16s transmitters, and RealFlight controllers are also supported. Non-Xbox joysticks may have incorrect mappings. If your joystick does not work, and you write your own mapping, please contribute back your new joystick mapping!
Remember, the SIL tries its best to replicate hardware. That means you have to calibrate and set parameters in the same way you do in hardware. See the Hardware Setup and Parameter Configuration pages in this documentation for instructions on how to perform all preflight configuration before the aircraft will arm. You can also run
ros2 launch rosflight_sim multirotor_init_firmware.launch.py\n
to load all required parameters and perform initial calibrations for a quick simulation setup."}]}
\ No newline at end of file
+{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Welcome to ROSflight","text":"The ROS2 updates for ROSflight are still under development. Please use with discretion.
"},{"location":"#what-is-rosflight","title":"What is ROSflight?","text":"ROSflight is a lean and adaptable autopilot system designed from the ground up with researchers in mind. Its purpose is to enable researchers to quickly and easily try out new ideas with minimal effort. Some of ROSflight's key feature are:
- Lightweight, modular, and well documented code that is easy to understand and modify.
- Most of the autopilot exists on a Linux computer rather than a microcontroller, enabling easier development with increased capabilities.
- Seamless switching between simulation and hardware: no part of the autopilot knows if it is running in simulation or not.
- Built on a ROS2 framework, allowing easy integration with ROS2 based projects.
See the user guide for more details on ROSflight.
"},{"location":"#why-rosflight","title":"Why ROSflight?","text":"There are a lot of excellent autopilots out there with a lot of great firmware options. Why did we feel like the world needed ROSflight? Because in our experience none of the other available options satisfied our research needs. Existing autopilots commonly used by researchers tend to have massive codebases under constant development that run primarily on microcontrollers.
This presents a number of problems. First, we are limited in our ability to understand and control everything occurring within the autonomy stack, making much of the autopilot an untouchable black box. Second, we are limited to the abilities of microcontrollers and can't take advantage of the more powerful hardware and software that can be found on Linux computers. Third, maintaining up-to-date support for software or hardware projects becomes a lot of work as things are frequently changing.
ROSflight is intended to fix these problems by being a lightweight, modular, and well documented codebase that offloads as much as possible to a ROS2 based framework running on a Linux computer.
"},{"location":"#our-vision","title":"Our Vision","text":"Perhaps more important than what we are trying to accomplish is what we are not trying to accomplish. ROSflight is not intended to be a fully-featured autopilot with all the same functions of other autopilots, but instead serve as a core foundation that can easily be adapted to any use case.
Therefore, one of our primary objectives is to avoid feature creep and remain lean. We hope that others will extend our code and build on top of it, and would love to hear about your successes. But for the most part, we will not be incorporating these new features back into the main project. Instead, we hope that ROSflight will remain a lean, core code base that will continue to serve as a launch pad for exciting new projects and applications.
"},{"location":"developer-guide/contribution-guidelines/","title":"Contribution Guidelines","text":"ROSflight is intended to be a streamlined, bare-bones autopilot. We welcome any bug fixes, cleanup, or other contributions which do not add complexity or detract from the readability and simplified nature of the project. In an attempt to avoid \"feature creep,\" we will be very discriminatory in merging pull requests whose purpose is to simply add features. Forking the repository in order to add features is totally acceptable and encouraged, just recognize us as the original authors of the autopilot (per the agreement in the BSD-3 license).
In addition, we strive to maintain a very high standard of quality in terms of code style, variable naming, and the like. By maintaining a high standard, we hope that the code will continue to be useful, understandable, and cohesive in nature. Please don't be offended if we ask you to modify the formatting of your code before approving a pull request.
Although we strive for complete in-code documentation, in practice this sometimes gets left behind for the sake of rapid development. If you, as a potential developer, find some portion of documentation unsatisfactory, we welcome questions on the appropriate GitHub issues page or forum, and encourage you to submit pull requests which improve documentation. Several new developers have started with first improving the documentation to get a handle on how things work.
"},{"location":"developer-guide/contribution-guidelines/#key-goals-of-rosflight","title":"Key Goals of ROSflight","text":"Here is a summary of the key goals and philosophies behind ROSflight. As you look to make contributions to the project, keep these in mind.
-
Only include the things that most people will need. The goal of this would be to do most of the work so people can get a MAV in the air quickly and easily, but not overcomplicate the code with features that only a small portion of users would need.
-
Be modular and adaptable for many research-centric use cases. This will be accomplished by putting the majority of the autopilot in a well-designed ROS2 framework. That which needs to be on the microcontroller will need to be done so carefully with good coding practices. Additionally, microcontroller code that is the most likely to be expanded upon should include clear interfaces and instructions for doing so.
-
Keep everything simple and well documented. The key goal here is to minimize the amount of time and effort it takes someone to go from knowing nothing about ROSflight to being able to implement their own features and making meaningful progress with their research.
"},{"location":"developer-guide/contribution-guidelines/#communication","title":"Communication","text":"There are two channels to communicate with the developer team. For bug reports, feature requests, and anything to do with code, please open an issue on the appropriate GitHub issue page. For questions and other discussions, please use the forum.
"},{"location":"developer-guide/style-guide/","title":"Style Guide","text":"The focus of anyone contributing to this project should be to write code that is easily understood by anyone, including people who have little experience with ROSflight or coding in general. So, we ask that contributions adhere to the following style guidelines.
"},{"location":"developer-guide/style-guide/#comments","title":"Comments","text":"Well written and clear code should be easy to understand even without comments. However, since this project is intended to be as accessible as possible, we ask that you write both clear code and clear comments. Don't use comments to explain code that would be difficult to understand without comments, but instead use them to make clear code even more understandable.
"},{"location":"developer-guide/style-guide/#doxygen","title":"Doxygen","text":"Doxygen comments should be added pretty much anywhere where it makes sense. Please include at least a brief for anything you write. For methods and functions, also include explanations of all arguments and the return value. See the below example for the Doxygen style you should use.
/**\n * @brief Converts an LLA coordinate to NED coordinates\n * \n * @param lla: Array of floats of size 3, with [latitude, longitude, altitude]\n * @return Array of doubles corresponding to the NED coordinates measured from the origin\n */\nstd::array<double, 3> lla2ned(std::array<float, 3> lla);\n
More detailed explanations are encouraged for non-trivial methods and objects. For single-line Doxygen comments, three slashes is acceptable, e.g., /// Comment here
.
"},{"location":"developer-guide/style-guide/#white-space-and-line-endings","title":"White Space and Line Endings","text":"Please try not to commit anything that only changes white space or line endings. To check if that's going to happen, run git diff --check
before you stage your files.
"},{"location":"developer-guide/style-guide/#code-style","title":"Code Style","text":"ROSflight follows the ROS2 C++ style guide, with some more specific guidelines below. Please follow first the style guidelines below and then the ROS2 guidelines. A .clang-format file and format-correcting script is provided in most ROSflight repositories that can be used to auto-format your code to help you find things you might have missed.
"},{"location":"developer-guide/style-guide/#indentation","title":"Indentation","text":"Indentation should be 2 spaces (no tabs).
"},{"location":"developer-guide/style-guide/#spaces","title":"Spaces","text":"There should be a space between if
, for
, or while
and the condition.
// Correct\nwhile (true) { ... }\n\n// Incorrect\nwhile(true) { ... }\n
"},{"location":"developer-guide/style-guide/#naming-conventions","title":"Naming Conventions","text":" - Class names should be CamelCase, that is, capitalized with no spaces (i.e.
StateManager
). - Member variables should contain a post-pended underscore (i.e.
data_
). - Member functions should be all lower case with underscores (i.e.
set_error()
). - Boolean values should be assigned
true
or false
, not 0
or 1
.
"},{"location":"developer-guide/style-guide/#classes","title":"Classes","text":"All modules should be defined as a self-contained class. All member variables should be declared as \"private,\" named with a post-pended underscore. All accessible data should be encapsulated in a struct. For example, here is a snippet from the Sensors
module in the firmware:
class Sensors\n{\npublic:\n struct Data\n {\n vector_t accel = {0, 0, 0};\n vector_t gyro = {0, 0, 0};\n float imu_temperature = 0;\n uint64_t imu_time = 0;\n\n float diff_pressure_velocity = 0;\n float diff_pressure = 0;\n float diff_pressure_temp = 0;\n bool diff_pressure_valid = false;\n\n float baro_altitude = 0;\n float baro_pressure = 0;\n float baro_temperature = 0;\n bool baro_valid = false;\n\n float sonar_range = 0;\n bool sonar_range_valid = false;\n\n vector_t mag = {0, 0, 0};\n\n bool baro_present = false;\n bool mag_present = false;\n bool sonar_present = false;\n bool diff_pressure_present = false;\n };\n\n Sensors(ROSflight& rosflight);\n\n inline const Data & data() const { return data_; }\n\nprivate:\n Data data_;\n}\n
Note that data_
is a private member variable, but the Data
struct is declared publicly.
"},{"location":"developer-guide/style-guide/#enums","title":"Enums","text":"Enums should be declared using the following style:
enum ArmedState\n{\n ARMED_STATE_INIT,\n ARMED_STATE_DISARMED,\n ARMED_STATE_ARMED\n};\n
The name of the enum should be in CamelCase, and the names of its members should be ALL_CAPS. Where practical, have the members of the enum begin with the name of the enum.
"},{"location":"developer-guide/style-guide/#structs","title":"Structs","text":"Structs should be declared using the following style:
struct SomeValue\n{\n int v1;\n int v2;\n};\n
Struct type names should be in CamelCase."},{"location":"developer-guide/style-guide/#globals","title":"Globals","text":"The use of global variables should be limited to when absolutely necessary (such as linking to interrupt routines or hardware peripherals). This should only occur in board support layers and not in the core ROSflight libary code, ROSplane, or ROScopter.
"},{"location":"developer-guide/style-guide/#include-order","title":"Include Order","text":"Include files at the top of your file in the following order:
- Standard library (e.g.
<cstdint>
) - Files from external libraries included in the project (e.g.
<breezystm32/breezystm32.h>
, <mavlink/v1.0/common/mavlink.h>
) - Other header files from this project (e.g.
\"rosflight.h\"
) - The header file for this specific source file
Group the includes according to the above list with an empty line between each group. (For external libraries, you may subdivide group 2 into a group for each library.) The first two groups should use angle brackets (<>
), and the last two groups should use quotation marks (\"\"
). Files from external libraries should be namespaced by the library name (e.g. <breezystm32/breezystm32.h>
, not <breezystm32.h>
).
Alphabetize the files within each group. Do not change the include order to fix build errors; if you have to do that it means you are not including a file somewhere that you should. Please fix it by including all the right files.
Include C standard library headers using the C++ style (#include <cmath>
) instead of the C style (#include <math.h>
).
For example, in sensors.c
I might have:
#include <cstdbool>\n#include <cstdint>\n\n#include <breezystm32/breezystm32.h>\n#include <breezystm32/drv_mpu6050.h>\n\n#include \"param.h\"\n\n#include \"sensors.h\"\n
"},{"location":"developer-guide/style-guide/#namespacing","title":"Namespacing","text":"All modules should be encapsulated in a package namespace that is unique and consistent within the package (like rosflight_firmware
for anything in the firmware package).
"},{"location":"developer-guide/firmware/building-and-flashing/","title":"Building and Flashing the Firmware","text":"This guide assumes you are running Ubuntu 22.04 LTS, which is the currently supported development environment.
"},{"location":"developer-guide/firmware/building-and-flashing/#installing-the-arm-embedded-toolchain","title":"Installing the ARM Embedded Toolchain","text":"sudo apt install gcc-arm-none-eabi\n
You can test the installation and check which version is installed by running arm-none-eabi-gcc --version
.
"},{"location":"developer-guide/firmware/building-and-flashing/#building-the-firmware-from-source","title":"Building the Firmware from Source","text":"Now that we have the compiler installed, simply clone the ROSflight firmware repository, pull down the submodules, and build:
git clone --recursive https://github.com/rosflight/rosflight_firmware\ncd rosflight_firmware\nmkdir build \ncd build \ncmake .. -DBUILD_VARMINT=TRUE\nmake\n
"},{"location":"developer-guide/firmware/building-and-flashing/#flashing-newly-built-firmware","title":"Flashing Newly-Built Firmware","text":"TODO
Update this when hardware support is finalized.
First, make sure you have configured your computer as described in the Serial Port Configuration section of the user guide.
"},{"location":"developer-guide/firmware/building-and-flashing/#f4","title":"F4","text":"Flash the firmware to the board by running make BOARD=REVO flash
. If necessary, specify the serial port with make BOARD=REVO SERIAL_DEVICE=/dev/ttyACM0 flash
.
"},{"location":"developer-guide/firmware/code-architecture/","title":"Code Architecture","text":"The firmware is divided into two main components: the core library, and a collection of board implementations. This division is intended to allow the same core flight code to run on any processor or platform, either an embedded flight controller or a desktop environment for a software-in-the-loop (SIL) simulation. The interface between these two components is called the hardware abstraction layer (HAL). This architecture is illustrated in the following diagram:
"},{"location":"developer-guide/firmware/code-architecture/#firmware-core-library","title":"Firmware Core Library","text":"The firmware core library consists of all the code in the include
and src
directories of the firmware repository. This includes the code for what is termed the \"flight stack,\" which consists of the core components (such as the estimator, controller, state manager, etc.) required for flight. It also includes the interface definition for the hardware abstraction layer, which is defined by the abstract Board
class in include/board.h
. The communications link (MAVLink) is also abstracted, with the interface defined by the CommLink
class in include/comm_link.h
. External libraries are contained in the lib
folder.
"},{"location":"developer-guide/firmware/code-architecture/#board-abstraction","title":"Board Abstraction","text":"The hardware abstraction implementations are contained in the boards
directory, organized in subdirectories according to the hardware driver layer. Each board implementation is required to provide an implementation of the hardware abstraction layer interface, which is passed by reference to the flight stack. The Varmint implementation in the boards/varmint
shows how this is done for an embedded flight controller. Examples of board implementations for SIL simulation are found in the rosflight_sim
ROS2 package available here.
The flight stack is encapsulated in the ROSflight
class defined at include/rosflight.h
. This class contains two public functions: init()
and run()
. Its constructor requires two arguments: an implementation of the Board
interface, and an implementation of the CommLink
interface.
Each board implementation is required to implement the entire Board class.
"},{"location":"developer-guide/firmware/code-architecture/#comm-link-abstraction","title":"Comm Link Abstraction","text":"The purpose of the comm link abstraction layer is to allow communication protocols other than MAVLink to be used if desired. The comm link abstraction implementations are contained in the comms
directory, organized in subdirectories by protocol. The implementations translate between the messages that the firmware expects to send and receive, and the messages defined by the communication protocol. Currently, only MAVLink is implemented.
"},{"location":"developer-guide/firmware/code-architecture/#flight-stack","title":"Flight Stack","text":"The flight stack is encapsulated by the ROSflight
class defined in include/rosflight.h
. It consists of a collection of modules. Each of these modules is implemented as a C++ class, and encapsulates a cohesive piece of the autopilot functionality. The following diagram illustrates these modules and the data flow between them. Rectangular blocks represent modules in the flight stack, and ellipses represent hardware functionality implemented in the board support layer:
We'll describe each of these modules in the following sections:
"},{"location":"developer-guide/firmware/code-architecture/#state-manager","title":"State Manager","text":"This module is in charge of keeping track of the internal state (armed status, error codes, failsafe, etc.) of the vehicle. While only the comm manager data flow is illustrated on the diagram, all other modules query the state manager to determine the status and act appropriately based on that status.
The operation of the state manager is defined by the following finite state machine:
The state manager also includes functionality for recovering from hard faults. In the case of a hard fault, the firmware writes a small amount of data to backup memory then reboots. This backup memory location is checked and then cleared after every reboot. The backup memory includes the armed state of the flight controller. On reboot, the firmware will initialize then, if this armed-state flag is set, immediately transition back into the armed state. This functionality allows for continued RC control in the case of a hard fault. Hard faults are not expected with the stable firmware code base, but this feature adds an additional layer of safety if experimental changes are being made to the firmware itself.
"},{"location":"developer-guide/firmware/code-architecture/#parameter-server","title":"Parameter Server","text":"This module handles all parameters for the flight stack. It supports the getting and setting of integer and floating-point parameters, and the saving of these parameters to non-volatile memory. Setting and getting of parameters from the companion computer is done through the serial communication interface. While no other data flow lines are shown on the diagram, all of the other modules interact with the parameter server.
"},{"location":"developer-guide/firmware/code-architecture/#comm-manager","title":"Comm Manager","text":"This module handles all serial communication between the flight controller and companion computer. This includes streaming data and receiving offboard control setpoints and other commands from the computer. This module primarily collects data from the sensors, estimator, state manager, and parameters modules, and sends offboard control setpoints to the command manager and parameter requests to the parameter server.
The actual communication protocol used is abstracted by the interface in include/comm_link.h. A new protocol can be used by implementing a wrapper around the protocol that inherits from this interface. Currently, only MAVLink has been implemented. The implementation is found in comms/mavlink/mavlink.h and comms/mavlink/mavlink.cpp.
"},{"location":"developer-guide/firmware/code-architecture/#sensors","title":"Sensors","text":"This module is in charge of managing the various sensors (IMU, magnetometer, barometer, differential pressure sensor, sonar altimeter, etc.). Its responsibilities include updating sensor data at appropriate rates, and computing and applying calibration parameters.
"},{"location":"developer-guide/firmware/code-architecture/#estimator","title":"Estimator","text":"This module is responsible for estimating the attitude and attitude rates of the vehicle from the sensor data.
"},{"location":"developer-guide/firmware/code-architecture/#rc","title":"RC","text":"The RC module is responsible for interpreting the RC signals coming from the transmitter via the receiver. This includes mapping channels to their appropriate functions and reversing directions if necessary.
"},{"location":"developer-guide/firmware/code-architecture/#command-manager","title":"Command Manager","text":"The command manager combines inputs from the RC and comm manager modules to produce a control setpoint. Its main purpose is to handle the interaction between offboard commands and the RC safety pilot, as well as to enforce the failsafe command if the state manager reports failsafe mode.
"},{"location":"developer-guide/firmware/code-architecture/#controller","title":"Controller","text":"The controller uses the inputs from the command manager and estimator to compute a control output. This control output is computed in a generic form (x, y, and z torques, and force F), and is later converted into actual motor commands by the mixer.
"},{"location":"developer-guide/firmware/code-architecture/#mixer","title":"Mixer","text":"The mixer takes the generic outputs computed by the controller and maps them to actual motor commands depending on the configuration of the vehicle.
"},{"location":"developer-guide/firmware/debugging/","title":"Using an In-Circuit Debugger","text":"TODO
Update this when hardware support is finalized.
Debugging an STM32-based board is accomplished with an ST-LINK/V2 in-circuit debugger and programmer. We have had the best luck with the official version from STMicroelectronics. These devices are reasonably priced, and are available directly from STMicroelectronics or from vendors such as Digi-Key, Mouser, and Newark.
The following guide will show you how to get the in-circuit debugger running with either the Visual Studio Code or QtCreator IDE. Start with the steps in the General Setup section, then move on to either the VS Code or STM32cubeIDE sections depending on your choice of IDE.
This guide assumes you are running Ubuntu 22.04 LTS, which is the currently supported development environment.
"},{"location":"developer-guide/firmware/debugging/#general-setup","title":"General Setup","text":"Follow the guide in Building and Flashing to install the compiler toolchain.
Also make sure you have configured your computer as described in the Serial Port Configuration section of the user guide.
"},{"location":"developer-guide/firmware/debugging/#connect-debugger-to-flight-controller","title":"Connect debugger to flight controller","text":"The ST-LINK/V2 connects to the microcontroller using the Serial Wire Debug (SWD) interface. You will need to connect the GND
, NRST
, SWDIO
, and SWCLK
lines of the ST-LINK/V2 to your flight controller. On many F4 boards, these lines are pinned out through a 4-position JST SH connector, although that connector is not always populated. Refer to the documentation for your specific board for details.
The official ST-LINK/V2 also needs a target voltage reference on pin 1 or 2, which for the F4 boards is 3.3V. However, there is no externally accessible 3.3V pinout on the F4 boards. An easy solution to this is to connect pin 19 (VDD 3.3V) of the ST-LINK/V2 to pin 1 or 2 of the ST-LINK/V2 (Target VCC) to provide the voltage reference. You will also need to power the board from another source, either through the USB port or over the servo rail. Note that this connection is not required for the cheap clone versions of the ST-LINK/V2.
"},{"location":"developer-guide/firmware/debugging/#vs-code","title":"VS Code","text":"You can install Visual Studio Code by downloading the latest version from their website. Follow the steps below to configure debugging with the in-circuit debugger.
You should open the root firmware directory for editing and debugging, e.g. code /path/to/rosflight_firmware
.
"},{"location":"developer-guide/firmware/debugging/#install-openocd","title":"Install OpenOCD","text":"OpenOCD (On-Chip Debugger) is the software that will control the debugger. Install from the apt
repositories:
sudo apt install openocd\n
"},{"location":"developer-guide/firmware/debugging/#install-cortex-debug-extension","title":"Install Cortex-Debug extension","text":"The embedded debugging functionality is provided by the Cortex-Debug
extension. Install using the VS Code GUI, or from VS Code press Ctrl+P
then type ext install marus25.cortex-debug
.
Steps for configuring this extension are described next.
"},{"location":"developer-guide/firmware/debugging/#download-svd-file","title":"Download SVD file","text":"A System View Description (SVD) file describes the configuration (CPU, peripherals, registers, etc.) of the microcontroller. The Cortex-Debug extension can make use of an SVD file to provide more detailed debugging information, such as the ability to inspect register values.
SVD files can be downloaded from STMicroelectronics. The files for the F4 are contained in the ZIP file that can be downloaded here, and the relevant file is STM32F405.svd
. The files for the F1 are contained in the ZIP file that can be downloaded here, and the relevant file is STM32F103.svd
. Put those files in a convenient location.
"},{"location":"developer-guide/firmware/debugging/#configure-build-step","title":"Configure build step","text":"You can configure VS Code to run make
for you when you press Ctrl+Shift+B
. To do this, put the following in .vscode/tasks.json
inside your firmware working directory:
{\n // See https://go.microsoft.com/fwlink/?LinkId=733558\n // for the documentation about the tasks.json format\n \"version\": \"2.0.0\",\n \"tasks\": [\n {\n \"type\": \"shell\",\n \"label\": \"make\",\n \"command\": \"make\",\n \"args\": [\"DEBUG=GDB\"],\n \"group\": {\n \"kind\": \"build\",\n \"isDefault\": true\n }\n }\n ]\n}\n
Note that by default, this will only build the F4 (Revo) firmware. To build the F1 firmware, you will need to edit this to add the argument BOARD=NAZE
.
"},{"location":"developer-guide/firmware/debugging/#configure-debugging","title":"Configure debugging","text":"To configure in-circuit debugging of F4 and F1 targets, put something like the following in .vscode/launch.json
inside your firmware working repository:
{\n // Use IntelliSense to learn about possible attributes.\n // Hover to view descriptions of existing attributes.\n // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n \"version\": \"0.2.0\",\n \"configurations\": [\n {\n \"name\": \"STM32F405\",\n \"type\": \"cortex-debug\",\n \"request\": \"launch\",\n \"servertype\": \"openocd\",\n \"cwd\": \"${workspaceRoot}\",\n \"executable\": \"${workspaceRoot}/boards/airbourne/build/rosflight_REVO_Debug.elf\",\n \"device\": \"STM32F405\",\n \"svdFile\": \"/path/to/STM32F405.svd\",\n \"configFiles\": [\n \"interface/stlink-v2.cfg\",\n \"target/stm32f4x.cfg\"\n ],\n \"runToMain\": true\n },\n {\n \"name\": \"STM32F103\",\n \"type\": \"cortex-debug\",\n \"request\": \"launch\",\n \"servertype\": \"openocd\",\n \"cwd\": \"${workspaceRoot}\",\n \"executable\": \"${workspaceRoot}/boards/breezy/build/rosflight_NAZE_Debug.elf\",\n \"device\": \"STM32F103\",\n \"svdFile\": \"/path/to/STM32F103.svd\",\n \"configFiles\": [\n \"interface/stlink-v2.cfg\",\n \"target/stm32f1x.cfg\"\n ],\n \"runToMain\": true\n }\n ]\n}\n
Be sure to edit the values of \"svdFile\"
to point to the respective SVD files you downloaded earlier.
To start debugging, enter the debug pane in VS Code, select the desired configuration, then click the green arrow to start debugging. The shortcut key F5
will also launch the last-selected debug configuration.
More details on the configuration and use of the Cortex-Debug
extension can be found here and here.
"},{"location":"developer-guide/firmware/debugging/#stm32cubeide","title":"STM32cubeIDE","text":""},{"location":"developer-guide/firmware/unit-tests/","title":"Building and Running Unit Tests","text":"Contributions will need to pass our continuous integration unit tests before merging. To test your contributions against these tests, you'll first need to install Eigen and gtest:
sudo apt install build-essential libgtest-dev libeigen3-dev cmake\n
"},{"location":"developer-guide/firmware/unit-tests/#compile-gtest","title":"Compile gtest","text":"You just downloaded a bunch of source files, which you now have to go build
cd /usr/src/gtest\nsudo cmake CMakeLists.txt\nsudo make\n
Copy the archive files you just built to the /usr/lib
directory so CMake can find them later:
sudo cp ./lib/libgtest*.a /usr/lib\n
"},{"location":"developer-guide/firmware/unit-tests/#run-the-test-script","title":"Run the Test Script","text":"The simplest way to run the unit tests is to use the testing script. This script first checks that the firmware compiles, then runs the unit tests. This is the same script used on the continuous integration server, so this is a great way to check that your code will pass the tests before opening a pull request. Run the test script with
cd <firmware_directory>\n./scripts/run_tests.sh\n
"},{"location":"developer-guide/firmware/unit-tests/#manually-build-and-run-the-unit-tests","title":"Manually Build and Run the Unit Tests","text":"If you want to manually build and run the unit tests, first build them with the following commands:
cd <firmware_directory>\nmkdir build\ncd build\ncmake .. -DBUILD_TEST=TRUE\nmake\n
Then run them with:
./test/unit_tests\n
"},{"location":"developer-guide/rosplane/parameter-management/","title":"Parameter Management","text":""},{"location":"developer-guide/rosplane/parameter-management/#overview","title":"Overview","text":"In ROSplane, all internal variables are represented as ROS2 parameters. This enables easy loading, tuning, and saving parameters of various ROSplane modules without needing to rebuild. ROS2 parameters can also be changed dynamically, enabling live editing and tuning of the system.
For a good introduction to ROS2 parameters and the CLI tools, see the ROS2 parameter CLI documentation. For an introduction to the parameter system using the ROS2 client libraries, see ROS2 parameter client libraries documentation.
"},{"location":"developer-guide/rosplane/parameter-management/#parameter-manager-class","title":"Parameter Manager class","text":"A param_manager
class has been created to manage the ROS interface required when dealing with parameters. Specifically, a param_manager
object handles the declaration and updates of parameters. Since a base class publicly owns the param_manager
, derived classes will have access to any parent class's parameters, if needed. This also allows derived classes to define parameters close to where they will be used in the derived class, helping with readability.
For example, the controller_base
class declares a frequency
variable, which defines the rate of the control loops. This same parameter is needed in other derived classes, like the controller_successive_loop
class. Since we declare the parameter in the controller_base
class, the controller_successive_loop
class will have access to the frequency
parameter without having to redefine it.
"},{"location":"developer-guide/rosplane/parameter-management/#usage","title":"Usage","text":""},{"location":"developer-guide/rosplane/parameter-management/#declaration","title":"Declaration","text":"To use the param_manager
to define your own parameters, do the following:
- Declare an instance of
param_manager
in your class, or ensure that a parent class has a public or protected instance of param_manager
. - Initialize the
param_manager
object with a pointer to the ROS2 node object associated with the parameters. - In the constructor, use
param_manager::declare_param(std::string <PARAM_NAME>, <PARAM>)
to declare parameters of type double, bool, or string, where <PARAM>
is the default value for the parameter. - Use
param_manager::declare_int(std::string <PARAM_NAME>, <PARAM>)
to declare an integer parameter.
- In the constructor, use
param_manager::set_parameters()
to load any parameters that have changed on launch to the param_manager
object.
Note
The param_manager::set_parameters()
call is important when a node is loaded with parameters from a file on launch. Not making this call will mean that the parameters stored in the param_manager
object are out of sync with the ROS2 parameters.
These steps will register your parameters with ROS2, allowing you to change them dynamically or load them from a launch file.
"},{"location":"developer-guide/rosplane/parameter-management/#using-parameters-in-code","title":"Using parameters in code","text":"After declaring the parameters with param_manager::declare_param
or param_manager::declare_int
, you need to allocate variables in your code to hold the values of the parameters. Get the parameter value by using the appropriate function call:
param_manager::get_double(std::string <PARAM_NAME>)
param_manager::get_bool(std::string <PARAM_NAME>)
param_manager::get_string(std::string <PARAM_NAME>)
param_manager::get_int(std::string <PARAM_NAME>)
Note that the return type of param_manager::get_int
is int_64
, since that is how ROS2 internally stores integers.
"},{"location":"developer-guide/rosplane/parameter-management/#defining-parameters-with-a-parameter-file","title":"Defining parameters with a parameter file","text":"We recommend using a YAML file to hold all of the parameters for a given node. This file can be loaded at launch time so that all parameters are updated with the values in the launch file. This means you don't have to change the default values in code (which would require a rebuild) to make sure a node gets launched with the correct values.
To do this, add the parameters=[\"/path/to/parameter/file\"]
to a node's launch argument. See rosplane.launch.py
for an example.
"},{"location":"developer-guide/rosplane/parameter-management/#updating-parameters","title":"Updating Parameters","text":"Parameters can be updated from the command line using normal ROS2 commands. See the ROS2 parameter CLI tools documentation for more information on how to interface with these parameters from the command line.
Note
Be sure to create a callback for your parameter changes, especially if you use a param_manager
object. ROS2 will send a list of changed parameters to this callback when the parameters are changed, allowing you to update the internally stored value in the param_manager
. Otherwise, your internally stored values will be out of sync with the ROS2 parameters, and it will likely not function correctly. See the controller_base
or estimator_base
or path_planner
code for an example of the callbacks.
"},{"location":"developer-guide/rosplane/controller/controller-base/","title":"Controller Base","text":""},{"location":"developer-guide/rosplane/controller/controller-base/#overview","title":"Overview","text":"The controller base implements the basic ROS interfaces for the controller. This includes setting up subscribers, publishers and initializing parameter management. The idea of the base class, is that all interfacing with ROS and shared resources across all inheritance levels happens or are contained in this class.
"},{"location":"developer-guide/rosplane/controller/controller-base/#ros-interfaces","title":"ROS interfaces","text":"The controller base has the following ROS interactions.
Figure 1: Controller's ROS interactions. The controller has four ROS interfaces that are tracked as member variables of the class. These interfaces are the only points of contact that influence the every layer of the controller along side the node parameters. Each of the callbacks for the subscribers are also contained in controller_base
.
ROS Interface Topic Explanation Message Type actuators_pub_
/command
Publishes the acutator commands for the aircraft. The publishing rate is controller by the timer_
object. Command.msg internals_pub_
/controller_inners_debug
Publishes the intermediate values created by the outer control loops. Published simultaneously as the commands when there is at least one subscriber to the topic. ControllerInnersDebug.msg controller_commands_sub_
/controller_commands
Subscribes to the commands for the controller. ControllerCommands.msg vehicle_state_sub_
/estimated_state
Subscribes to the estimated state of the aircraft. State.msg Note
The command message is from the rosflight_msgs
package not the rosplane_msgs
package.
"},{"location":"developer-guide/rosplane/controller/controller-base/#parameter-management","title":"Parameter Management","text":"See the Parameter Management page for more details on how parameter management works.
"},{"location":"developer-guide/rosplane/controller/controller-base/#list-of-parameters","title":"List of Parameters","text":"Parameter Explanation Range pwm_rad_e Radian to PWM conversion for the elevator. \\geq 1.0 (double) pwm_rad_a Radian to PWM conversion for the ailerons. \\geq 1.0 (double) pwm_rad_r Radian to PWM conversion for the rudder. \\geq 1.0 (double) frequency Frequency of the timer, effective control loop closure frequency. \\geq 100 (hertz, int)"},{"location":"developer-guide/rosplane/controller/controller-base/#modifying-controller-base","title":"Modifying Controller Base","text":"The controller_base
class should only contain things that are necessary for each layer of the controller. If you are considering adding something to the controller, but it only applies to one layer, perhaps reconsider. All ROS related items should also be stored here. For example, if you needed to use another topic subscription, the new subscriber should be created and stored in controller_base
.
As shown in the Controller Software Architecture page, you may need to modify the main
function in controller_base.cpp
to use a newly implemented controller.
"},{"location":"developer-guide/rosplane/controller/controller-general-overview/","title":"ROSplane Controller","text":""},{"location":"developer-guide/rosplane/controller/controller-general-overview/#overview","title":"Overview","text":"The ROSplane controller generates the controller commands to achieve the commanded states that the path follower directs. The controller has the basic function of controlling roll, pitch, yaw, airspeed, course and altitude. Higher functions of controlling position and tracking paths is handled by other nodes, the path follower and manager specifically. To gain the best understanding of the Controller and its role, read chapter 1 of the UAV book, or the ROSplane Overview page.
"},{"location":"developer-guide/rosplane/controller/controller-general-overview/#interfaces","title":"Interfaces","text":"Figure 1: Controller's ROS interactions."},{"location":"developer-guide/rosplane/controller/controller-general-overview/#input","title":"Input","text":"The controller receives controller commands using the ControllerCommands message on the \\controller_commands
topic from the path_follower
node. This set of commands are outlined below, along with a short explanation of each.
Message Field Explanation Units header This contains time stamp information. Time in Seconds and Nanoseconds (int) va_c The commanded airspeed. Meters per second (float) h_c The commanded altitude. Meters (float) chi_c The commanded course. Radians (float) phi_ff Feedforward roll term (for orbits) Radians (float) aux[4] Four array of auxiliary commands None (float) aux_valid Indicates whether aux vector contains actual information. True/False (bool) The controller uses these targets to control the aircraft. This drives the aircraft to approach and follow the path as the path_follower commands. See the Path Follower page for more information. See the Successive Loop Closure Controller Outline for more information on how these commands are used specifically.
Note
Poor path performance may be due to controller or the path follower, see the Tuning Guide in the User Guide section for more details.
"},{"location":"developer-guide/rosplane/controller/controller-general-overview/#output","title":"Output","text":"The controller calculates the control surface outputs in percent deflection (based around zero) and throttle. It formats and the publishes these outputs in the Command message on the /command
topic. There are a further four auxiliary channels that can be used in the Command message, however they are unused typically. A summary of the parts of the command message are as follows.
Message Field Explanation Units header This contains time stamp information. Time in Seconds and Nanoseconds (int) mode The control mode (used in multi-rotors) None (int) ignore A bitmask to ignore particular values. None (int) x Aileron Command Percent deflection in direction [-1.0, 1.0] (float) y Elevator Command Percent deflection in direction [-1.0, 1.0] (float) z Rudder Command Percent deflection in direction [-1.0, 1.0] (float) f Throttle Command Percent of full throttle [0.0, 1.0] (float) These are passed to rosflight_io
, which formats them into MAVLink messages and forwards them onto the FCU.
Note
For this to work the parameters on the rosflight_firmware
must be set to work for an airplane. See the User Guide on first time start up or README.md for the repository for more details on firmware setup.
"},{"location":"developer-guide/rosplane/controller/controller-general-overview/#running-the-controller","title":"Running the Controller","text":"As mentioned in the ROSplane ROS overview, the controller is in the main rosplane
ROS package. The ROS executable is rosplane_controller
, yielding the run command:
ros2 run rosplane rosplane_controller
The type of controller used is passed right after the executable name, substitute control_type
for controller being used.
ros2 run rosplane rosplane_controller control_type
To pass a set of parameters for the controller from a yaml file using the --ros-args
option.
ros2 run rosplane rosplane_controller --ros-args --params-file path/to/params.yaml
Putting it all together,
ros2 run rosplane rosplane_controller control_type --ros-args --params-file path/to/params.yaml
A table of arguments and parameter files that work out of the box is given in the following table.
Note
Filepaths will need to be altered to work.
Note
The most common way of running the controller is in through a launch file with the rest of the ROSplane pipeline running as well. See the ROSplane Overview in the Developer and User Guides for more details.
Argument Explanation Values --params-file The parameters file that contains the gains and other important parameters. rosflight_ws/src/rosplane/rosplane/params/anaconda_autopilot_params.yaml
,rosflight_ws/src/rosplane/rosplane/params/skyhunter_autopilot_params.yaml
control_type These arguements are passed directly to the main function defined in the controller. default
, total_energy
"},{"location":"developer-guide/rosplane/controller/controller-outline/","title":"Successive Loop Closure Controller","text":""},{"location":"developer-guide/rosplane/controller/controller-outline/#overview","title":"Overview","text":"The control scheme used by default in ROSplane comes from the book Small Unmannded Aircraft: Theory and Practice by Randal Beard and Timothy McLain. A full and in depth description of the theory behind this controller is outlined in chapter 6. Additionally, many simplifing assumptions are made some of which will be mentioned, but the rationale not explored. These too are found in the book, in chapters 3, 4 and 5. A link to the most up to date book can be found on the GitHub page for the book. This section of the documentation is to briefly outline the important, practical parts of the controller to be useful in understanding how to tune or modify the existing code or algorithm for a developer. A good primer on PID control can be found here.
The control algortihm is split into two parts: Lateral-directional Autopilot and Longitudinal Autopilot. The lateral and longitudinal dynamics are assumed to be decoupled as discussed in Section 6.1 of Small Unmannded Aircraft. This allows us to develop a controller for each set of dynamics to simplify the controller design.
"},{"location":"developer-guide/rosplane/controller/controller-outline/#successive-loop-closure","title":"Successive Loop Closure","text":"For a full discussion of PID successive loop closure, which is used heavily through out the entire controller, read section 6.1 in the book. One major assumption used is that the inner loops are much faster (more than ten times faster) than the outer loops. This means that the bandwidth seperation should be seperated by a factor of 10. See end of section 6.1.1 Course Hold using Commanded Roll in the book for a more thorough discussion. A significant advantage of successive loop closure is that gains are tuned independently. Starting from the inner loops, tune the response and then tune the outer loop.
"},{"location":"developer-guide/rosplane/controller/controller-outline/#nomenclature","title":"Nomenclature","text":"Symbol Meaning Range \\large{\\boldsymbol{\\chi}} Course/Heading [-\\pi,\\pi) \\large{\\boldsymbol{\\phi}} Roll [-\\pi,\\pi) \\large{\\boldsymbol{\\theta}} Theta [-\\pi,\\pi) \\large{\\boldsymbol{\\psi}} Yaw [-\\pi,\\pi) \\large{\\boldsymbol{h}} Altitude \\large{p} Roll Rate \\large{q} Pitch Rate \\large{r} Yaw Rate \\large{V_a} Airspeed \\large{\\boldsymbol{\\delta_i}} Command percent defelection of control surface i [-1.0,1.0] \\large{\\boldsymbol{e_a}} Error in state variable a \\large{\\boldsymbol{a^c}} Commanded value of state variable a \\large{\\boldsymbol{k_{p_{a}}}} Proportional gain for state variable a \\large{\\boldsymbol{k_{d_{a}}}} Derivative gain for state variable a \\large{\\boldsymbol{k_{i_{a}}}} Integral gain for state variable a \\large{\\boldsymbol{p_{wo}}} Washout filter bandwidth \\large{\\boldsymbol{P}} Plant transfer function \\large{\\boldsymbol{s}} Laplace operator"},{"location":"developer-guide/rosplane/controller/controller-outline/#lateral-directional-autopilot","title":"Lateral-directional Autopilot","text":"The autopilot uses induced roll to control changes in course. The Lateral-directional Autopilot also uses a yaw damper to damp the dutch roll mode that can be induced by changes in roll.
"},{"location":"developer-guide/rosplane/controller/controller-outline/#course-loop","title":"Course Loop","text":"In figure 1, the entire control loop for the course is shown. This loop allows for tracking of ramp and step commands in course. Since the inner loop is tuned first and influences the outer loop tune, we will discuss it first.
Figure 1: Lateral-directional Autopilot Control Loop"},{"location":"developer-guide/rosplane/controller/controller-outline/#inner-loop","title":"Inner Loop","text":"The inner loop calculates the required percent deflection in the ailerons, \\boldsymbol{\\delta_a}, to acheive the commanded roll angle generated by the outer loop. This loop is a PD loop, meaning that it uses only a proportional and derivative control.
Note
That the derivative gain does not act on the rate of change of the error but of the direct roll rate, p.
The proportional gain acts on the error given by the estimated roll and the commanded roll. This loop does not use integral contol to ensure that it closes much faster than the outer loop. This bandwidth seperation helps the controller perform smoothly. See the specific page on the Course Loop for details on tuning and common pitfalls. For more details on how the roll rate and the roll angle are calculated, see the Estimator page. The output for the inner loop is routed into the outer loop.
"},{"location":"developer-guide/rosplane/controller/controller-outline/#outer-loop","title":"Outer Loop","text":"The outer loop calculates the commanded roll angle, \\boldsymbol{\\phi}, based on the error in the course, \\boldsymbol{\\chi}. This is a PI loop, meaning that it uses only proportional and integral control. The proportional gain acts on the error between the estimated course \\boldsymbol{\\chi} and the commanded course \\boldsymbol{\\chi}. The integral gain acts on the same error, ensuring that errors in course are driven to zero.
Note
The PI loop allows for only constant error in ramp inputs (orbits) and for no error to step inputs (path following commands).
See the specific page on the Course Loop for details on tuning and common pitfalls. For more details on how course is estimated and measured, see the Estimator page. These loops combine to give complete control of the course of the aircraft.
"},{"location":"developer-guide/rosplane/controller/controller-outline/#yaw-damper","title":"Yaw Damper","text":"The yaw damper allows for effective damping of undesirable yaw modes induced by rolling. This is done by using the rudder to control the yaw rate, r, to zero. Not all yaw rates should be controlled to zero since this would disallow turning. A washout filter is used to only damp high frequency yaw rates. In effect, this control only 'turns on' if the frequency of the yaw rate is high enough. For mor information see the Yaw Damper page.
Figure 2: Yaw Damper Control Loop"},{"location":"developer-guide/rosplane/controller/controller-outline/#longitudinal-autopilot","title":"Longitudinal Autopilot","text":"The longitudinal autopilot controls the longitudinal dynamics of the aircraft. This means that the loop controls altitude, pitch and airspeed.
"},{"location":"developer-guide/rosplane/controller/controller-outline/#altitude-loop","title":"Altitude Loop","text":"The altitude loop utilizes successive loop closure to control altitude. It uses the elevator to control the pitch of the aircraft, and then controls using commanded pitch the altitude. This loop can track step and ramp commands.
Figure 3: Altitude Control Loop"},{"location":"developer-guide/rosplane/controller/controller-outline/#inner-loop_1","title":"Inner Loop","text":"The inner loop controls the pitch, \\boldsymbol{\\theta}. It does so by calculating the necessary \\boldsymbol{\\delta_e} to acheive the commanded pitch. This is a PD loop, this means that there is often a small DC offset to the commanded pitch. This does not affect the performance of the overall altitude loop. Like the inner loop of the course control, the derivative gain acts on the measured pitch rate rather than the error derivative.
"},{"location":"developer-guide/rosplane/controller/controller-outline/#outer-loop_1","title":"Outer Loop","text":"The outer loop is a PI loop. It uses the error in the altitude, h, and integral of the error of altitude to drive the error to zero for steps and for ramps. The commanded altitude is capped using a scheme described in the Altitude Loop page. In practice, the altitude loop is often slower when the commanded altitude is descending and faster when ascending. This is because the airspeed is coupled to the altitude. While descending the controller will attempt to maintain airspeed. This can also result in more overshoot while descending.
"},{"location":"developer-guide/rosplane/controller/controller-outline/#airspeed-loop","title":"Airspeed Loop","text":"The Airspeed loop is a PI loop. It reacts to the straight forward error in commanded airspeed V_a^c given by the waypoint mission. It generates the required throttle, \\delta_t, to acheive the commanded airspeed. This is suffecient because of the natural damping of the drag on the aircraft. In practice, the loop performs well, but is prone to small fluctuations (on the order of \\pm 1 \\frac{m}{s}) due to the differential pressure sensor fluctuating because of wind and other disturbances.
Figure 4: Airspeed using throttle control loop"},{"location":"developer-guide/rosplane/controller/controller-outline/#controller-outputs","title":"Controller Outputs","text":"What the entire controller outputs is a set of 4 control efforts that correspond to the 4 major control surfaces on the aircraft. These are the elevator, ailerons, rudder and the throttle. The controller can easily be switched to outputing up to 8 outputs, using the aux channels of the Commands Message. These outputs are fed directly to rosflight_io and then passed along to the microcontroller and finally actuated on the physical or simulated aircraft. The controller is the exposed portion of ROSplane to ROSflight.
"},{"location":"developer-guide/rosplane/controller/controller-outline/#important-notes","title":"Important Notes","text":"The controller does not directly control the position. In the ROSplane overview page, it shows how the Path Follower feeds into the controller. The Path Follwer generates commands that result in the position control of the aircraft. For a better understanding of this realtionship visit the Path Follower page.
"},{"location":"developer-guide/rosplane/controller/controller-outline/#software-architecture","title":"Software Architecture","text":"The Successive Loop Closure Controller (SLCC) inherits from the state machine class, (see Software Architecture for more details) and implements the state function for each of the states. This state function is then populated with the desired control during each phase of flight (see State Machine for more details on control during each state). The state functions split control into longitudinal and lateral control, this allows for inheritance of this class an only override longitudinal or lateral control (see Total Energy Control for an example of how this is done).
Figure 5: An example of an implementation of a state function, in this case the altitude hold state. The lateral and longitudinal control functions activate particular control loops necessary.
Figure 6: An example of an implementation of a lateral and longitudinal control, in this case during the altitude hold state. Each control loop gets its own function and it follows a specific format. This format is pictured below, but a full outline is given in the .cpp file for the SLCC.
Note
All of the PID is implemented but the gains if not using a particular control (proportional/derivative/integral) are zero.
Figure 7: An example of an implementation of a control loop, in this case the roll loop (inner course loop)."},{"location":"developer-guide/rosplane/controller/controller-outline/#parameters","title":"Parameters","text":"These values are typically held in a .yaml file. For the default values, check the .cpp file.
Parameter Explanation Range max_takeoff_throttle Trottle saturation level during the takeoff zone. (0.0, 1.0) (double) c_kp The proportional gain on the outer course loop. \\geq 0.0 (double) c_kd The derivative gain on the outer course loop. \\leq 0.0 (double) c_ki The integral gain on the outer course loop. \\geq 0.0 (double) max_roll Commanded roll saturation limit. \\geq 0.0 (double)(degrees) cmd_takeoff_pitch Commanded pitch while in takeoff state. \\geq 0.0 (double)(degrees) r_kp The proportional gain on the inner course loop. \\geq 0.0 (double) r_kd The derivative gain on the inner course loop. \\geq 0.0 (double) r_ki The integral gain on the inner course loop. \\geq 0.0 (double) max_a Saturation limit for the ailerons \\geq 0.0 (double) trim_a Trim value for the ailerons. \\geq 0.0 (double) a_kp The proportional gain on the outer altitude loop. \\geq 0.0 (double) a_kd The derivative gain on the outer altitude loop. \\geq 0.0 (double) a_ki The integral gain on the outer altitude loop. \\geq 0.0 (double) max_pitch Commanded pitch saturation limit. \\geq 0.0 (double)(degrees) p_kp The proportional gain on the inner altitude loop. \\leq 0.0 (double) p_kd The derivative gain on the inner altitude loop. \\leq 0.0 (double) p_ki The integral gain on the inner altitude loop. \\leq 0.0 (double) max_e Saturation limit for the elevator \\geq 0.0 (double) trim_e Trim value for the elevator. \\geq 0.0 (double) y_pwo The yaw damper washout filter cutoff frequency. \\leq 0.0 (double)(radians/s) y_kr Control gain on yaw damper. \\leq 0.0 (double) a_t_kp The proportional gain on the airspeed loop. \\geq 0.0 (double) a_t_kd The derivative gain on the airspeed loop. \\geq 0.0 (double) a_t_ki The integral gain on the airspeed loop. \\geq 0.0 (double) max_t Saturation limit for the throttle. \\geq 0.0 (double) trim_t Trim value for the throttle. \\geq 0.0 (double) tau Dirty derivative low pass filter gain for airspeed. \\geq 0.0 (double)"},{"location":"developer-guide/rosplane/controller/controller-software-architecture/","title":"Controller Software Architecture","text":""},{"location":"developer-guide/rosplane/controller/controller-software-architecture/#overview","title":"Overview","text":"The controller makes use of inheritance to make the controller more modular. This creates a hierarchy of classes that each take on a responsibility. This means that a user that modifies the controller only has to inherit from a particular class make the modifications only to the portions of the code that matter to them, and then continue to use the other parts of the controller. An example of this is provided in the code. The total energy controller exemplifies this by inheriting and only changing just a few key functions. The aim of this architecture is to make the developer's job easier.
"},{"location":"developer-guide/rosplane/controller/controller-software-architecture/#inheritance-scheme","title":"Inheritance Scheme","text":"The controller starts off with the controller_base
class. This contains all of the interface with ROS. The next layer, controller_state_machine
, implements a basic state machine for the controller. These states control which commands are happening at what time. An example of how this may be used is, ensuring the aircraft is at altitude before attempting major maneuvers. Following the state machine is the actual control scheme. By default we use a successive loop closure scheme, controller_successive_loop
. This layer calculates the control errors and necessary actuator deflections to track commands.
Figure 1: Controller class inheritance structure.
This scheme was chosen to limit code duplication. A composition structure would have resulted in code duplication between controllers. Guides on how and where to modify each part of this structure can be found on the respective pages in the Developer Guide. This page does go over the basics of how to implement a controller changes in terms of overall architecture.
"},{"location":"developer-guide/rosplane/controller/controller-software-architecture/#implementing-a-new-controller","title":"Implementing A New Controller","text":"Figure 2: Options for implementing a new controller. The total energy controller in the rosplane
package, shows in a practical way how to implement a new controller. This section is meant to only give a high level overview of how this can be done. The first step is to identify where your changes should be made. This means determining which class the change belongs in. Consult the class pages for more information on where the best fit for your controller would be. The next step is to define a new class that inherits from class you are changing. Override the functions of interest. Next if the inherited class is not at the bottom of the inheritance chain, you will have to modify (duplicate but only change the inheritance, this is to not break default behavior) the controller classes further down the chain to inherit from your class rather than the original. This is to avoid a multiple inheritance problem (inheritance diamond).
To add your new controller as an option to be launched you will need to make a few edits. To be clear, you add your new final controller, (new_controller
or copy_of_controller
in the diagram) as an option. These edits are as follows:
- Add new controller to the CMakeLists.txt.
- The best examples are found in the CMakeLists.txt.
- Be sure to include the
.cpp
files.
Figure 3: Location in CMakeLists.txt
to add the new controller's .cpp
file(s).
- First import the new controller by adding its header file to
controller_base.cpp
.
Figure 4: Location in controller_base.cpp
to import new controller's header file.
- Next you need to add the new controller as an option to the
main
function. The argument to the main function is the name/activation string for the control. This is passed in on launch of ROSplane (see Launching ROSplane in the User Guide for more details).
Figure 5: Location in controller_base.cpp
to add option to select control type.
If this is done correctly, then you should be able to simply change between control schemes with only an argument to a launch file. This will allow for easier testing where you can use a more tested controller initially and but swap to a new controller when convenient.
"},{"location":"developer-guide/rosplane/controller/controller-state-machine/","title":"Controller State Machine","text":""},{"location":"developer-guide/rosplane/controller/controller-state-machine/#state-machine-overview","title":"State Machine Overview","text":"The controller state machine uses discrete states to turn on and off particular controls for a more stable flight. These regimes are designed so that particular mission objectives are only activated when particular conditions are met. In the default implementation this is controlled based on the aircraft's altitude. Though, in practice these states could be effected by any input from a ROS topic. The states are pictured below, and the differences in state are explored in the next section.
Figure 1: Controller state machine."},{"location":"developer-guide/rosplane/controller/controller-state-machine/#states","title":"States","text":"This section describes all of the states and what control is active during that phase of flight.
"},{"location":"developer-guide/rosplane/controller/controller-state-machine/#takeoff","title":"Takeoff","text":"In the takeoff state, the commanded airspeed is set to cruise, the commanded pitch is held constant and roll is controlled to zero. This results in a steady takeoff directly along the runway. The deactivation of course control means that the aircraft will not attempt to maneuver while too close to the ground. The takeoff regime is only below a certain cutoff altitude. After passing this threshold it moves into the climb state.
"},{"location":"developer-guide/rosplane/controller/controller-state-machine/#climb","title":"Climb","text":"The climb state commands altitude and airspeed as normal, but still controls roll to zero. This means that the aircraft will proceed directly ahead until it is withing a cutoff (see Params section) of commanded altitude. Deactivating course control allows for the aircraft to gain enough altitude to be clear of all obstacles before attempting to follow the waypoint mission. Once within a cutoff of the commanded altitude, the state transitions to altitude hold. If the aircraft dips beneath the takeoff threshold, it will enter the takeoff state again.
"},{"location":"developer-guide/rosplane/controller/controller-state-machine/#altitude-hold","title":"Altitude Hold","text":"In altitude hold all control loops are closed normally. The aircraft will fly the waypoint mission as normal. If the aircraft dips beneath the takeoff cutoff, the state transitions to takeoff again.
"},{"location":"developer-guide/rosplane/controller/controller-state-machine/#code-architecture","title":"Code Architecture","text":"The state machine's architecture allows for different aspects of the control to be modified. It simply defines a virtual method to be implemented by a child that will control during the particular state the aircraft is in. The state method is implemented in the child, only using the controls necessary for that phase of flight (see the Architecture section of the Successive Loop Closure).
Figure 2: Code snippet from the state machine."},{"location":"developer-guide/rosplane/controller/controller-state-machine/#parameters","title":"Parameters","text":"Parameter Explanation Range alt_toz The altitude of the takeoff zone cutoff. \\geq 0.0 (double) alt_hz The altitude command saturation limit, and difference required to transition into altitude hold. \\geq 0.0 (double)"},{"location":"developer-guide/rosplane/controller/controller-total-energy/","title":"Total Energy Controller","text":""},{"location":"developer-guide/rosplane/controller/controller-total-energy/#overview","title":"Overview","text":"The total energy control system approach (TECS) differs from the successive loop closure controller in its control of airspeed and altitude. It does this by calculating the total energy of the system, both potential and kinetic and controlling it to the desired energy. A more in depth treatment of of TECS see Section 6.2 in the UAV book.
The TECS controller has been included in ROSplane not only to provide control of the aircraft but to also demonstrate how to easily modify the controller (see Software Architecture and the following section for more details). The TECS controller calculates the desired kinetic and potential energy, using references from the commanded airspeed and altitude. It then calculates the current kinetic and potential energies and finds the kinetic and potential errors. It combines these errors, and the throttle control loop uses a PI loop to drive this total energy error to zero. The energy errors are also used to find a balance error. This is the error in the ratio of potential to kinetic energy. Pitch is then controlled by a PI loop to drive the balance error to zero. Essentially the throttle allows for the total energy to rise as it adds or allows drag to subtract energy from the system. The pitch loop controls how much of that input energy is in potential versus kinetic energy
This approach can have advantages because it deals with the coupling of airspeed and altitude. In the successive loop closure controller (SLCC), it assumes a decoupling of airspeed and altitude which can present tuning issues, though they are not insurmountable.
"},{"location":"developer-guide/rosplane/controller/controller-total-energy/#software-architecture","title":"Software Architecture","text":"The TECS controller provides an excellent template on implementing a new controller. Since the changes to the total energy controller are only in the longitudinal control and the rest are the same as the SLCC it inherits directly from controller_successive_loop
and only overrides the longitudinal functions for each state.
Figure 1: Total Energy Controller's overriden longitudinal control for the altitude hold state."},{"location":"developer-guide/rosplane/controller/controller-total-energy/#parameters","title":"Parameters","text":"Parameter Explanation Range e_kp Total energy error proportional gain, used in throttle control. \\geq 0.0 (double) e_ki Total energy error integral gain, used in throttle control. \\geq 0.0 (double) e_kd Total energy error derivative gain, used in throttle control. \\geq 0.0 (double) l_kp Balance energy error proportional gain, used in throttle control. \\geq 0.0 (double) l_ki Balance energy error integral gain, used in throttle control. \\geq 0.0 (double) l_kd Balance energy error derivative gain, used in throttle control. \\geq 0.0 (double) mass The mass of the aircraft, allowing for calculation of energies. \\geq 0.0 (double)(kg) gravity The gravity experienced by the aircraft, allowing for calculation of potential energy. \\geq 0.0 (double)(\\frac{m}{s}) max_alt_error This is the maximum error in altitude that the total energy loop will use to calculate energy error. \\geq 0.0 (double)(meters)"},{"location":"developer-guide/rosplane/navigation/navigation-overview/","title":"Navigation Overview","text":"The path planning methods used in ROSplane is modeled after the architecture presented in Small Unmanned Aircraft: Theory and Practice by Dr. Randal Beard and Dr. Tim McLain.
In their work, the path planning functionality of the aircraft is split into three main parts, as shown in Figure 1.
Note
This is not a full description of the architecture. For example, the state estimator is not shown, and not all of the inputs to each of the blocks is included. These elements were removed from the figure for simplicity.
Figure 1: Path planning architecture - based on Figure 1.1 in Small Unmanned Aircraft: Theory and Practice The high-level path planning is done by the path planner node. The path planner's job is to manage, create, and publish waypoints. Those waypoints are published to the path manager node. The path manager's job is to determine and calculate the appropriate line segments and orbits needed to complete the waypoints. The path manager then publishes these straight lines and waypoints to the path follower. The job of the path follower is to control the course, airspeed, and altitude of the aircraft to follow these lines and orbits.
For more information on each of these nodes, see the related documentation pages for the path planner, the path manager, and the path follower. See also chapters 10-13 of the Small Unmanned Aircraft: Theory and Practice book.
"},{"location":"developer-guide/rosplane/navigation/navigation-overview/#changing-the-navigation-stack","title":"Changing the Navigation Stack","text":"The path planner currently takes in a set of user-defined waypoints and follows those waypoints. This is not useful in all contexts, since in many applications the aircraft needs to take in sensor data and create its own waypoints and paths.
For example, we could replace the path planner block with a vision-based guidance block. The vision-based-guidance block would make decisions based on visual data to create waypoints. However, the interface between the path planner (now the visual-based guidance planner) and the path manager would remain the same.
Similarly, the path manager could be adjusted to follow b-splines instead of straight lines and orbits as currently implemented, without affecting the general waypoint management (path planner) or the underlying path following control loops (path follower).
The modularity of this framework allows users to \"plug in\" their own algorithms for each of the blocks defined in Figure 1, instead of rewriting the whole path planning stack.
Chapter 13 of the Small Unmanned Aircraft: Theory and Practice book contains more detail on implementing a vision-based path planner.
"},{"location":"developer-guide/rosplane/navigation/navigation-overview/#running-the-navigation-stack","title":"Running the Navigation Stack","text":"To launch the navigation stack, you will need to launch 3 ROS2 nodes, one for each part of the navigation stack (path planner, manager, and follower).
Remember to launch these nodes with the appropriate parameter launch file, as seen in the rosplane.launch.py
file.
"},{"location":"developer-guide/rosplane/navigation/path-follower/","title":"Path Follower","text":""},{"location":"developer-guide/rosplane/navigation/path-follower/#overview","title":"Overview","text":"The role of the path follower is to generate the correct airspeed, course, and altitude commands for the autopilot such that the aircraft follows the paths published by path_manager
.
More information on the path_follower
can be found in Small Unmanned Aircraft: Theory and Practice by Dr. Randal Beard and Dr. Tim McLain.
"},{"location":"developer-guide/rosplane/navigation/path-follower/#path-follower-base","title":"Path Follower Base","text":"The path follower base contains all the ROS2 interfaces required for the path follower. A list of these interfaces is below.
The path_follower_base::follow
method is a virtual method that should be implemented by a derived class. The path_follower_base
publishes the controller commands calculated by the implementation of path_follower_base::follow
.
"},{"location":"developer-guide/rosplane/navigation/path-follower/#list-of-ros2-interfaces","title":"List of ROS2 Interfaces","text":"ROS2 Interface Topic or Service Explanation Message or Service Type vehicle_state_sub_
/estimated_state
Subscribes to the estimated aircraft state rosplane_msgs::msg::State
current_path_sub_
/current_path
Subscribes to the current path messages published by path_manager
rosplane_msgs::msg::CurrentPath
controller_commands_pub_
/controller_commands
Publishes control commands to the autopilot rosplane_msgs::msg::ControllerCommand
update_timer_
-- ROS2 timer that controls how frequently controller_commands_pub_
publishes --"},{"location":"developer-guide/rosplane/navigation/path-follower/#interface-with-the-autopilot","title":"Interface with the Autopilot","text":"The path_follower
node interfaces with the MAV autopilot by publishing to the /controller_commands
topic. The /controller_commands
topic contains the following information calculated by the path_follower
:
Member Description Type / units Required header
Standard message header that contains a valid timestamp std_msgs::msg::Header
Yes va_c
Commanded airspeed double
, m/s Yes h_c
Commanded altitude double
, m Yes chi_c
Commanded course double
, rad Yes phi_ff
Feedforward command (for orbits) double
, rad No"},{"location":"developer-guide/rosplane/navigation/path-follower/#path-follower-example","title":"Path Follower Example","text":"The path_follower_example
class contains the implementation of the path_follower_base::follow
method. This method contains the control command computations for straight line and orbit-type paths as outlined in Small Unmanned Aircraft: Theory and Practice.
"},{"location":"developer-guide/rosplane/navigation/path-follower/#parameters","title":"Parameters","text":"See the Parameter Management page for more details on how parameter management works.
"},{"location":"developer-guide/rosplane/navigation/path-follower/#list-of-parameters","title":"List of Parameters","text":"Parameter Explanation Type / Units Range chi_infty
At infinity, the angle at which the aircraft will approach the desired line double (rad) \\frac{\\pi}{2} \\geq \\chi^{\\infty} > 0.0 k_path
Constant that determines how quickly commanded course transitions from \\chi^{\\infty} to 0 during line following double > 0.0 k_orbit
Constant that determines how quickly commanded course transitions from \\lambda \\frac{\\pi}{2} to 0 during an orbit double > 0.0 Since there are two different types of lines generated by the path_manager
(straight lines and orbits), the path_follower
uses different parameters to calculate the control output for each path type.
For line following, path_follower
uses
chi_infty
and k_path
to compute the control commands.
As described in Small Unmanned Aircraft: Theory and Practice, these two parameters define a vector field for the commanded course. The chi_infty
parameter describes the angle at which the aircratft will approach a target line if the aircraft is infinitely far from the target line. For example, if chi_infty
is set to \\frac{\\pi}{2}, then the aircraft will approach the target line at an angle perpindicular to the line when the aircraft is far away.
The k_path
parameter defines how quickly the vectors at chi_infty
\"smooth\" into the target line. When k_path
is large, the transition will be abrupt, and when k_path
is small, the transition will be smoother.
During orbit following, path_follower
uses
k_orbit
to compute the control commands.
If the aircraft is very far away from the orbit, it will align itself so it flies directly at the center of the orbit. The k_orbit
parameter is similar to the k_path
parameter in that it determines how quickly the commanded angle of the aircraft will change from directly toward the center to the orbit direction.
Note
When tuning, make sure you are changing the correct gains for the type of line (straight or orbit) the aircraft is tracking. chi_infty
and k_path
will not affect the orbit performance!
"},{"location":"developer-guide/rosplane/navigation/path-follower/#modifying-the-path-follower","title":"Modifying the Path Follower","text":"Changes to any of the ROS2 interface should be done in the path_follower_base
.
Changes to how path_follower
computes control commands to follow paths given by the path_manager
should be done in the path_manager_example
.
"},{"location":"developer-guide/rosplane/navigation/path-manager/","title":"Path Manager","text":""},{"location":"developer-guide/rosplane/navigation/path-manager/#overview","title":"Overview","text":"The path manager is responsible for calculating and publishing the current path to the path follower. It is split into a base class and an inherited class. The base class handles the ROS2 interfaces (publishing and subscribing) while the inherited class manages the path, i.e., calculates the parameters for the current path.
The path manager is designed this way so that the inherited class (how the paths are managed) can be replaced or rewritten without affecting the overlying ROS2 interface.
Both the path_manager_base
and the path_manager_example
are included in the same ROS2 node when compiled, called path_manager
. Parameters associated with the path_manager_base
or the path_manager_example
will therefore be visible under the path_manager
ROS2 node.
More details about the path manager can be found in Small Unmanned Aircraft: Theory and Practice by Dr. Randal Beard and Dr. Tim McLain.
"},{"location":"developer-guide/rosplane/navigation/path-manager/#path-manager-base","title":"Path Manager Base","text":"The path manager base contains all the ROS2 interfaces required for the path manager. A list of these interfaces is below.
"},{"location":"developer-guide/rosplane/navigation/path-manager/#list-of-ros2-interfaces","title":"List of ROS2 Interfaces","text":"ROS2 Interface Topic or Service Explanation Message or Service Type vehicle_state_sub_
/estimated_state
Subscribes to the estimated aircraft state rosplane_msgs::msg::State
new_waypoint_sub_
/waypoint_path
Subscribes to the waypoint messages published by path_planner
rosplane_msgs::msg::State
current_path_pub_
/current_path
Publishes the parameters of the current path rosplane_msgs::msg::CurrentPath
update_timer_
-- ROS2 timer that controls how frequently current_path_pub_
publishes --"},{"location":"developer-guide/rosplane/navigation/path-manager/#interface-with-the-path-follower","title":"Interface with the Path Follower","text":"The path_manager
node interfaces with the path follower by publishing to the /current_path
topic. These messages contain information about the current trajectory, which are either straight lines or circles.
Note that the only supported path types are straight lines and circles. Depending on how the path_manager
is set up to manage the waypoints, this may not be suitable for your application. See \"Modifying the Path Manager\" for more information. For more information on the path follower, see the Path Follwer documentation.
"},{"location":"developer-guide/rosplane/navigation/path-manager/#path-manager-example","title":"Path Manager Example","text":"The path_manager_example
class inherits from the path_manager_base
class. Specifically, the path_manager_example
overrides the path_manager_base::manage
method to determine how the path is managed.
In the current implementation, path_manager_example
decides to manage a waypoint using straight lines and fillets, orbits, or Dubins paths based on the current state of the aircraft, the values of the current ROS2 parameters, and the waypoints given. For example, if the use_chi
field on a Waypoint object (see Path Planner for more information) is set to true
, then path_manager_example
will use a Dubins path to navigate to the next waypoint. If use_chi
is set to false
, then path_manager_example
will use straight lines when navigating in between waypoints and a fillet to manage the corners. See Figure 1 for an example of a real flight path flown using ROSplane with chi_d
set to false
.
Example flight path from an actual flight test showing the straight lines and fillets path type Note that using fillets to manage the corners often means that the aircraft does not actually achieve the waypoint. If this is undesireable in your application, use Dubins paths or another method for the path_manager
.
"},{"location":"developer-guide/rosplane/navigation/path-manager/#parameters","title":"Parameters","text":"See the Parameter Management page for more details on how parameter management works.
"},{"location":"developer-guide/rosplane/navigation/path-manager/#list-of-parameters","title":"List of Parameters","text":"Parameter Explanation Type Range R_min
Minimum radius for orbit, fillet, and Dubins paths double \\geq 0.0 orbit_last
Specifies whether or not to orbit the last waypoint. If false, param_manager
will fly a circuit bool true
or false
"},{"location":"developer-guide/rosplane/navigation/path-manager/#the-orbit_last-parameter","title":"The orbit_last
Parameter","text":"The path_manager
node has a parameter named orbit_last
. This parameter controls what happens as the aircraft is approaching the last waypoint in the set of waypoints published to the path_manager
. If orbit_last
is set to true
, then path_manager
will follow an orbit around the last waypoint.
The direction of this waypoint (clockwise or counterclockwise) will be chosen based on which direction requires the least amount of turning. In other words, if the aircraft is angled slightly left as it approaches the waypoint, path_manager
will choose to orbit the last waypoint counterclockwise (from a top-down perspective). If the aircraft is pointing slightly right as it approaches the waypoint, it will orbit the waypoint clockwise (from a top-down perspective).
"},{"location":"developer-guide/rosplane/navigation/path-manager/#modifying-the-path-manager","title":"Modifying the Path Manager","text":"Changes or additions to any ROS2 interfaces should be done in the path_manager_base
field.
Changes to how path_manager
\"manages\" the waypoints should be done by overriding the path_manager_base::manage
method. If you wish to change the way paths are defined, make sure that the /current_path
topic is rewritten to contain the required information, and then make sure the path_follower
knows how to handle the new definition.
"},{"location":"developer-guide/rosplane/navigation/path-planner/","title":"Path Planner","text":""},{"location":"developer-guide/rosplane/navigation/path-planner/#overview","title":"Overview","text":"The path planner is responsible for creating, managing, and publishing waypoints. In the current implementation, the path planner simply maintains a list of user-defined waypoints that the user can add to or clear. The path planner then controls when waypoints are published to the path manager.
Another implementation of the path planner (as described in the overview) could include a visual-based path planner. In this case, the path planner would receive sensor input and create and manage its own waypoints instead of a user-defined list of waypoints. However, this new path planner would still be responsible for creating and publishing waypoints. This ensures that the interface between the path planner and the path manager would stay the same, allowing for modularity in the path planner architecture.
"},{"location":"developer-guide/rosplane/navigation/path-planner/#interfaces","title":"Interfaces","text":"The path planner is implemented as a standalone ROS2 node, called path_planner
. This node subscribes to the topics it needs, provides services available to the user and other nodes, and publishes waypoints to the path manager, called path_manager
.
The interface between path_planner
and path_manager
is the /waypoint_path
topic, which publishes messages with the rosplane_msgs::msg::Waypoint
type. This message contains information about the waypoint's location in NED (from the origin) or GNSS (LLA) coordinates, the desired airspeed at the waypoint, and the desired heading of the aircraft at the waypoint.
"},{"location":"developer-guide/rosplane/navigation/path-planner/#about-waypoints","title":"About Waypoints","text":"The following table contains the data members of the rosplane_msgs::msg::Waypoint
objects and a brief description.
Member Description Type Required header
Standard message header that contains a valid timestamp std_msgs::msg::Header
Yes w
Waypoint coordinates in NED or GNSS (LLA) std::array<float32, 3>
Yes lla
Flag to determine if the coordinates are passed in as NED or GNSS bool
Yes chi_d
Desired course at the waypoint double
No use_chi
Flag to use the chi_d
value at the waypoint or not bool
No - defaults to false
va_d
Desired airspeed at the waypoint double
Yes clear_wp_list
Clears all waypoints from path_planner
and path_manager
bool
No"},{"location":"developer-guide/rosplane/navigation/path-planner/#notes-on-the-waypoint-object-fields","title":"Notes on the Waypoint object fields","text":"The w
field contains the coordinates of the waypoint in either NED coordinates (from the origin, defined as the place where ROSplane initialized) or GNSS coordinates given in LLA (latitude, longitude, and altitude). The GNSS coordinates are converted to NED coordinates by path_planner
before sending them to path_manager
.
The lla
field is a flag that tells path_planner
if the coordinates provided are in the NED or world (GNSS) frame. Set it to true
if the coordinates for the waypoint are given in GNSS coordinates. Note that GNSS and relative waypoints can be used together, meaning that one waypoint could be in the NED frame while the next one is in the global frame, since ROSplane converts global coordinates to the NED frame before publishing them to path_manager
.
Note
Make sure that the lla
field is set correctly if you decide to use GNSS coordinates, or your waypoints will be incorrect.
The chi_d
field controls the desired course at the waypoint. Note that this is only used if the use_chi
flag is set to true
.
The use_chi
field determines whether or not the path_manager
should pay attention to the desired course (chi_d
). If use_chi
is set to true
then path_manager
will use a Dubins path framework to manage the waypoint. If use_chi
is set to false
, then path_manager
will ignore the desired course and will intead use straight lines and fillets to manage the transitions between waypoints. See the Path Manager documentation for more information on this behavior.
The clear_wp_list
is used internally by path_planner
when the /clear_waypoints
service is called. It is recommended to use the service call instead of using this field manually.
Warning
The header
, w
, va_d
, and lla
fields must be valid for every waypoint message sent. Failure to add these fields might crash the path planner or your aircraft.
"},{"location":"developer-guide/rosplane/navigation/path-planner/#list-of-ros2-interfaces","title":"List of ROS2 Interfaces","text":"ROS2 Interface Topic or Service Explanation Message or Service Type waypoint_publisher_
/waypoint_path
Publishes the waypoints to the path_manager
rosplane_msgs::msg::Waypoint
state_subscription_
/estimated_state
Subscribes to the estimated state of the aircraft rosplane_msgs::msg::State
next_waypoint_service_
/publish_next_waypoint
Publishes the next stored waypoint std_msgs::srv::Trigger
add_waypoint_service_
/add_waypoint
Adds a new waypoint to list and optionally publishes it rosplane_msgs::srv::AddWaypoint
clear_waypoint_service_
/clear_waypoints
Clears the list of waypoints from the path planner and publishes a clear waypoint command to the path_manager
std_msgs::srv::Trigger
print_waypoints_service_
/print_waypoints
Prints the saved waypoints to the terminal. Can be useful when debugging std_msgs::srv::Trigger
load_mission_service_
/load_mission_from_file
Loads a mission from a YAML file rosflight_msgs::srv::ParamFile
"},{"location":"developer-guide/rosplane/navigation/path-planner/#parameters","title":"Parameters","text":"See the Parameter Management page for more details on how parameter management works.
"},{"location":"developer-guide/rosplane/navigation/path-planner/#list-of-parameters","title":"List of Parameters","text":"Parameter Explanation Type Range num_waypoints_to_publish_at_start
Number of waypoints to immediately publish at launch. If no waypoints are added, it will not publish any. int \\geq 0"},{"location":"developer-guide/rosplane/navigation/path-planner/#recommended-usage","title":"Recommended Usage","text":"We recommend using a YAML file and the /load_mission_from_file
service from the command line to load and fly waypoints. See the example mission YAML file located at /path/to/rosplane/rosplane/params/fixedwing_mission.yaml
.
To call the service, run
ros2 service call /load_mission_from_file rosflight_msgs::srv::ParamFile \"{filename: <FILENAME>}\"\n
where <FILENAME>
is the path to the mission YAML file."},{"location":"user-guide/autonomous-flight/","title":"Autonomous Flight","text":"To perform autonomous flight with ROSflight, we need to send control commands from our companion computer to the firmware. This can be done with ROSplane or ROScopter, which already have completed autonomy stacks developed specifically for ROSflight. We recommend starting with one of these autonomy stacks and building on them to suit your needs. If using a multirotor, follow the ROScopter setup guide to get started. If using a fixed-wing, follow the ROSplane setup guide.
However, ROSplane and ROScopter are optional and an entirely different autonomy stack can be used if desired. To use a different autonomy stack, follow this guide.
"},{"location":"user-guide/autonomous-flight/#provide-control-from-a-companion-computer","title":"Provide Control from a Companion Computer","text":"Control setpoints are sent to the flight controller by publishing to the /command
topic that is advertised by the rosflight_io
node. This topic accepts messages of type rosflight_msgs/Command
, which have the following structure:
std_msgs/Header header\nuint8 mode\nuint8 ignore\nfloat32 x\nfloat32 y\nfloat32 z\nfloat32 f\n
The header
field is a standard ROS2 message header. The x
, y
, z
, and f
fields are the control setpoint values, which are interpreted according to the mode
and ignore
fields.
The following table describes the different values the mode
field can take, as well as how the setpoint values are interpreted for each of these modes:
Value Enum x y z F 0 MODE_PASS_THROUGH
aileron deflection (-1 to 1) elevator deflection (-1 to 1) rudder deflection (-1 to 1) throttle (0 to 1) 1 MODE_ROLLRATE_PITCHRATE_YAWRATE_THROTTLE
roll rate (rad/s) pitch rate (rad/s) yaw rate (rad/s) throttle (0 to 1) 2 MODE_ROLL_PITCH_YAWRATE_THROTTLE
roll angle (rad) pitch angle (rad) yaw rate (rad/s) throttle (0 to 1) The MODE_PASS_THROUGH
mode is used for fixed-wing vehicles to directly specify the control surface deflections and throttle, while the MODE_ROLLRATE_PITCHRATE_YAWRATE_THROTTLE
and MODE_ROLL_PITCH_YAWRATE_THROTTLE
modes are used for multirotor vehicles to specify the attitude rates or angles, respectively.
The ignore
field is used if you want to specify control setpoints for some, but not all, of the axes. For example, I may want to specify throttle setpoints to perform altitude hold, while still letting the RC pilot specify the attitude setpoints. The ignore
field is a bitmask that can be populated by combining the following values:
Value Enum Result 0 IGNORE_NONE
Ignore none of the fields (default) 1 IGNORE_X
Ignore the x
field 2 IGNORE_Y
Ignore the y
field 4 IGNORE_Z
Ignore the z
field 8 IGNORE_F
Ignore the F
field For the previous example, I would set the ignore
field to a value of
ignore = IGNORE_X | IGNORE_Y | IGNORE_Z\n
The best practice is to use enum names rather than the actual numeric values for the mode
and ignore
fields. For example, to specify a multirotor attitude angle command in C++ I might have:
#include <rclcpp/rclcpp.hpp>\n#include <rosflight_msgs/msg/command.hpp>\n\nrosflight_msgs::msg::Command msg;\nmsg.header.stamp = node->get_clock()->now();\nmsg.mode = rosflight_msgs::msg::Command::MODE_ROLL_PITCH_YAWRATE_THROTTLE;\nmsg.ignore = rosflight_msgs::msg::Command::IGNORE_NONE;\nmsg.x = 0.0;\nmsg.y = 0.0;\nmsg.z = 0.0;\nmsg.f = 0.6;\n
In Python I might have:
import rclpy\nfrom rosflight_msgs.msg import Command\n\nmsg = Command()\nmsg.header.stamp = node.get_clock().now().to_msg()\nmsg.mode = Command.MODE_ROLL_PITCH_YAWRATE_THROTTLE\nmsg.ignore = Command.IGNORE_NONE\nmsg.x = 0.0\nmsg.y = 0.0\nmsg.z = 0.0\nmsg.f = 0.6\n
I would then publish this message to the /command
topic to forward it to the embedded flight controller. Note
If the flight controller does not receive a new command for a defined period of time, it will ignore the old commands and revert to RC control. The length of this timeout period is set by the OFFBOARD_TIMEOUT
parameter.
"},{"location":"user-guide/flight-controller-setup/","title":"Flight Controller Setup","text":"Note
This page contains instructions for flashing pre-built firmware binaries. For instructions on building and flashing from source, see Building and Flashing in the Developer Guide.
"},{"location":"user-guide/flight-controller-setup/#compatible-hardware","title":"Compatible Hardware","text":"Currently, the ROSflight firmware only supports an in-development board from AeroVironment, the Varmint. This board is not yet commercially available, but plans are for it to start being sold early 2024.
We also plan to add support for the CubePilot Orange, which uses the same H7 processor as the Varmint.
"},{"location":"user-guide/flight-controller-setup/#serial-port-configuration","title":"Serial Port Configuration","text":"Tip
You can see which groups you are a member of by running groups $USER
on the command line.
The following bullet point is necessary:
- Be sure your user is in the
dialout
and plugdev
groups so you have access to the serial ports. You will need to log out and back in for these changes to take effect. sudo usermod -aG dialout,plugdev $USER\n
If you experience issues, you may need one or both of the next two bullet points:
-
Temporarily stop the modem-manager (Sometimes, Linux thinks the device is a modem -- this command will be effective until next boot, or until you run the command again with start
in place of stop
)
sudo systemctl stop ModemManager.service\n
-
Add the custom udev rule so Linux handles the flight controller properly (copy the following as /etc/udev/rules.d/45-stm32dfu.rules
)
# DFU (Internal bootloader for STM32 MCUs)\nSUBSYSTEM==\"usb\", ATTRS{idVendor}==\"0483\", ATTRS{idProduct}==\"df11\", MODE=\"0664\", GROUP=\"plugdev\"\n
Tip
You can permanently disable the ModemManager if you do not need it, then you won't have to disable it every time you reboot:
sudo systemctl disable ModemManager.service\n
Replace disable
with enable
to revert (i.e. if you find some other program you use needs access to it). Or you can uninstall it entirely from your system: sudo apt purge modemmanager\n
"},{"location":"user-guide/flight-controller-setup/#flashing-firmware","title":"Flashing Firmware","text":"TODO
Update flashing instructions.
"},{"location":"user-guide/flight-controller-setup/#f4-boards","title":"F4 Boards","text":" - Install the dfu-util utility
sudo apt install dfu-util\n
- Download the latest rosflight-F4.bin file, found here
- Put the board in bootloader mode (short the boot pins while restarting the board by cycling power)
Tip
dfu-util auto-detects F4-based boards. Try dfu-util -l
to make sure your board is in bootloader mode
- Flash the firmware to the device
dfu-util -a 0 -s 0x08000000 -D rosflight-F4.bin\n
"},{"location":"user-guide/getting-started/","title":"Getting Started","text":"Reading through the pages in this user guide in order should provide you with the information you need to get a vehicle flying with ROSflight. The following is a summary of the steps you'll need to follow to get your vehicle set up, with links to the corresponding documentation pages:
- Set up your hardware (fixed-wing or multirotor platform, flight controller, and companion computer)
- Flash your flight controller with the latest ROSflight firmware
- Set up your RC transmitter
- Set up ROS2 on your companion computer
- Configure the flight controller for your setup: the configuration checklists below should help guide you through this process
- Run through your preflight checks
- Tune the firmware attitude controller gains (multirotors only)
- Set up autonomous flight via offboard control (optional)
"},{"location":"user-guide/getting-started/#configuration-checklist","title":"Configuration Checklist","text":"The following checklists should help you get a new vehicle set up for the first time. This checklist assumes that your hardware is already set up correctly.
"},{"location":"user-guide/getting-started/#general-setup","title":"General Setup","text":" - Set the
FIXED_WING
parameter (1
if a fixed-wing, 0
if a multirotor) - Set the
RC_TYPE
parameter (0
if PPM, 1
if SBUS) - Set the
MIXER
parameter to the appropriate value described in the Hardware Setup page - Set the
MOTOR_PWM_UPDATE
parameter (typically 490
for SimonK ESCs, 50
for standard servos) - Make sure your RC transmitter is set up correctly
- Set up your RC switches
- If you want to arm/disarm using a switch, set the
ARM_CHANNEL
parameter to the appropriate channel (0-indexed) - If you want to use a switch to enable RC override, set the
RC_ATT_OVRD_CHN
and RC_THR_OVRD_CHN
parameters to the appropriate channel(s) (0-indexed). If you want complete control (attitude and throttle) when you flip the switch, set both these parameters to the same channel.
- Calibrate your IMU: start
rosflight_io
, then run ros2 service call /calibrate_imu std_srvs/srv/Trigger
- Complete the multirotor-specific or fixed-wing-specific checklist below
- Save the parameters (
ros2 service call /param_write std_srvs/srv/Trigger
) - You'll probably want to save a backup of your parameters (call
ros2 service call /param_save_to_file rosflight_msgs/srv/ParamFile \"{filename: \"params.yml\"}\"
) - Make sure you run through the Preflight Checklist before flying
"},{"location":"user-guide/getting-started/#multirotor-specific-setup","title":"Multirotor-specific Setup","text":"Danger
IMPORTANT: Remove all props from the vehicle when calibrating ESCs!!!
-
Calibrate ESCs
- Make sure
MOTOR_MIN_PWM
and MOTOR_MAX_PWM
are correct (usually 1000
and 2000
) - Set
MIXER
param to 0
(ESC calibration mixer) - Set
ARM_SPIN_MOTORS
to 0
-
Perform ESC calibration. For standard ESCs:
- With power disconnected from the motors, arm the flight controller
- Set throttle to maximum
- Connect power to the motors
- Drop the throttle to minimum
-
Set the MIXER
parameter back to the appropriate value for your vehicle (see the Hardware Setup page)
- Set
ARM_SPIN_MOTORS
back to 1
-
The ARM_SPIN_MOTORS
parameter should be set to 1
so the motors spin slowly when armed. The idle throttle setting can be adjusted with the MOTOR_IDLE_THR
parameter.
- You'll most likely want to set the
CAL_GYRO_ARM
param to 1
to enable calibrating gyros before arming - Set the
RC_ATT_MODE
parameter to set RC control mode (0
for rate mode, 1
for angle mode [default]) - Set torque offsets as described in the RC trim calculation section of the Improving Firmware Performance page
- Set the
FAILSAFE_THR
parameter to specify the throttle level the MAV will hold if the transimtter disconnects. Set the parameter to 0
if you just want the MAV to drop, otherwise determine the amount of throttle required to hover the MAV and set the parameter comfortably below that. DO NOT set it above, as this will result in a runaway MAV. We recommended that you test the throttle level in an enclosed space by powering off the transmitter while hovering, if you set this parameter above 0. - Tune the controller gains as described in the Multirotor gain tuning section of the Improving Firmware Performance page
"},{"location":"user-guide/getting-started/#fixed-wing-specific-setup","title":"Fixed-Wing-Specific Setup","text":" - Reverse servo directions if necessary using the
AIL_REV
, ELEVATOR_REV
, and RUDDER_REV
parameters (1
to reverse, 0
to keep current direction) - You'll most likely want to set the
ARM_SPIN_MOTORS
parameter to 0
so that the prop doesn't spin at a minimum throttle setting when you arm, especially if you'll be doing hand launching
"},{"location":"user-guide/hardware-setup/","title":"Hardware Setup","text":""},{"location":"user-guide/hardware-setup/#parts-list","title":"Parts List","text":"To use ROSflight to its full potential, you will need the following system components. Some components are mounted on your MAV (Miniature Aerial Vehicle), while others are on the ground. ROSflight supports both multirotor and fixed-wing vehicles.
Mounted on the MAV
- Aircraft Frame, Motor(s), ESC(s), Battery and Propeller(s)
- Flight Controller (FC)
- Vibration Isolation for FC
- Any external sensors
- R/C Receiver
- Companion Computer
- Wi-Fi Antenna, or access of some kind to ground-station, wireless network (e.g. Ubiquiti Bullet)
Ground Station
- Ground-Station, Wireless Network (e.g. Wi-Fi Router, Ubiquiti Rocket)
- R/C transmitter
- Laptop or base station computer
- Joystick (Xbox controller)
"},{"location":"user-guide/hardware-setup/#frame-motors-escs-battery-and-propeller","title":"Frame, Motors, ESCs, Battery, and Propeller","text":"We do not officially support any specific multirotor or airplane frame, motor, ESC, Battery or Propeller combination. There are a lot of great resources for building your own MAV, and there are a lot of great kits out there that have all of these parts.
If you are designing your own multirotor or airplane, you may want to look at ecalc, an online tool which can help you design a proper ESC/Battery/Motor/Propeller system for your MAV.
Some things to keep in mind as you design or build your MAV.
- Most kits do not include space for a companion computer, cameras, laser scanners or other sensors. Be sure to think about where these components are going to go, and how their placement will affect the CG of the MAV.
- You will likely also need to customize the power circuitry of your MAV to provide power to your companion computer at some specific voltage. Many people like to separate the power electronics (the ESCs and motors), from the computer and companion sensors. This can really come in handy if you are trying to develop code on the MAV, because you can have the computer on and sensors powered, and not worry at all about propellers turning on and causing injury as you move the aircraft about by hand. We will talk about this more when we talk about wiring up your MAV.
- Cheap propellers can cause a huge amount of vibration. Consider buying high-quality propellers, doing a propeller balance, or both. RCGroups, DIY Drones and Youtube have some awesome guides on how to do propeller balancing.
- ESCs will need to be calibrated from 2000 to 1000 us
"},{"location":"user-guide/hardware-setup/#flight-controller","title":"Flight Controller","text":"TODO
Update recommended hardware once supported hardware has been finalized.
"},{"location":"user-guide/hardware-setup/#external-sensors","title":"External Sensors","text":"Additional Sensors you may want for your ROSflight setup include:
- Sonar
- GPS
- Digital Airspeed Sensor (Pitot Tube)
"},{"location":"user-guide/hardware-setup/#vibration-isolation","title":"Vibration Isolation","text":"It is really important to isolate your flight controller from vehicle vibrations, such as those caused by propellers and motors. We recommend using small amounts of Kyosho Zeal to mount a fiberglass plate holding the FC to the MAV. You may also want to try adding mass to the flight control board. We have accomplished this by gluing steel washers to the fiberglass mounting plate.
You may need to experiment with the amount of gel you use, how far apart the gel is spaced, and the amount of mass added to the FC mounting plate. The interaction of these factors is difficult to predict, therefore it takes a little bit of experimentation to get it right.
"},{"location":"user-guide/hardware-setup/#companion-computer","title":"Companion Computer","text":"The only requirement for the companion computer is that it runs Linux (usually an Ubuntu LTS version, but using Docker on other distributions is also an option), ROS2, has at least one USB port, and can be carried by the aircraft. We have had success with the following companion computers, but by no means is this a comprehensive list; it is more by way of suggestion.
- NVIDIA Jetson
- MSI CUBI
- Intel NUC
- Rasberry Pi 3
"},{"location":"user-guide/hardware-setup/#wi-fi","title":"Wi-Fi","text":"You will need Wi-Fi to communicate with your MAV when it is in the air. Because ROS2 communicates over UDP, it is very easy to use ROS2 to view what is going on in your MAV while it is flying by sending commands and reading sensor data. For most applications, a standard Wi-Fi router and dongle will suffice. For long-range applications, you may want to look into Ubiquiti point-to-point Wi-Fi. (We have seen ranges over a mile with these networks.)
"},{"location":"user-guide/hardware-setup/#rc-transmitter-and-receiver","title":"RC Transmitter and Receiver","text":"For RC Control, you will need a transmitter with between 6 and 8 channels. Any additional channels will be wasted. We require RC control for safe operation, and only support arming and disarming via RC control.
ROSflight only supports PPM (pulse position modulation) and SBUS receivers. Individual channel PWM outputs are not supported. Any configurations with PPM or SBUS and 6-8 channels will be sufficient.
"},{"location":"user-guide/hardware-setup/#laptop-or-base-station-computer","title":"Laptop or Base Station Computer","text":"You will need a laptop which can run ROS2 to communicate with the MAV over the ground station wireless network. To do this natively you'll want a recent Ubuntu LTS version, but this can also be done with Docker containers from pretty much any Linux distribution. Linux within a virtual machine can also work, but is not recommended.
"},{"location":"user-guide/hardware-setup/#joystick","title":"Joystick","text":"A joystick is used for software-in-the-loop (SIL) simulations. The joystick is not technically a required component because it is possible to control your MAV from the command line, but it makes things much easier. Our first recommendation is to use the same transmitter you use for hardware as a joystick by plugging it into the computer via USB. We support Taranis QX7 transmitters, Radiomaster TX16s transmitters, RealFlight controllers, and XBOX controllers. Other joysticks can be used, but you may need to create custom axis and button mappings within the ROSflight joystick utility.
"},{"location":"user-guide/hardware-setup/#battery-monitor","title":"Battery Monitor","text":"A battery monitor is an analog sensor that provides battery voltage and/or battery current information. This data can be used to prevent power loss in air or to measure system load. The sensor outputs an analog voltage proportional to the battery voltage and/or current through the battery. Most flight controllers come equipped with a built-in battery monitor, but if not, small PCB sensors are also available that can be connected to the flight controller.
For ROSflight to use a battery monitor, an appropriate multiplier must be set. ROSflight multiplies the analog signal from the monitor by the multiplier to get the final reading. The monitor datasheet should contain the information needed to get the multiplier. For example, the datasheet for the AttoPilot 50V/90A sensor states that it outputs 63.69 mV / V. To get the original battery voltage, the multiplier must be 1/.06369, or 15.7. The multipliers for the voltage and current are set separately, with the BATT_VOLT_MULT
and BATT_CURR_MULT
parameters, respectively.
ROSflight applies a simple low-pass filter to remove noise from the voltage and current measurements. These filters are configurable via the BATT_VOLT_ALPHA
and BATT_CURR_ALPHA
parameters. The alpha value for a given cutoff frequency \\(a\\), can be calulated with: \\( \\alpha = e ^ {-.01a} \\). As battery voltages do not typically change quickly, the default of 0.995 usually suffices.
More information on battery monitor hardware, including determinining appropriate multipliers and creating a simple DIY monitor, can be found on the OpenPilot Wiki.
"},{"location":"user-guide/hardware-setup/#wiring-diagram","title":"Wiring Diagram","text":"Below is an example wiring diagram for a multirotor using an MSI Cubi as a companion computer. This diagram also includes the motor power switch, which allows for the sensors, flight controller, and companion computer to be powered on while the motors are off. This is a safer way to test sensors, code, etc. as the motors are unable to spin while the switch is off.
Your needs will likely be slightly different than what is shown. This is meant as an example only and can be adapted to fit your needs.
"},{"location":"user-guide/hardware-setup/#motor-layouts","title":"Motor Layouts","text":"The desired mixer can be chosen by setting the MIXER
parameter to the following values:
# Mixer 0 ESC calibration 1 Quad + 2 Quad X 3 Hex + 4 Hex X 5 Octo + 6 Octo X 7 Y6 8 X8 9 Tricopter 10 Fixed-wing (traditional AETR) The associated motor layouts are shown below for each mixer. The ESC calibration mixer directly outputs the throttle command equally to each motor, and can be used for calibrating the ESCs.
"},{"location":"user-guide/hardware-setup/#connecting-to-the-flight-controller","title":"Connecting to the Flight Controller","text":"The flight controller communicates with the companion computer over a serial link. ROSflight only supports one serial connection at a time and by default should be the serial link connected to the USB connector on the board.
"},{"location":"user-guide/hardware-setup/#using-secondary-serial-links","title":"Using Secondary Serial Links","text":"In the case of an F4 flight controller, which has a USB peripheral, the highest bandwidth connection will be the USB connector. However, UART3 can also be used to communicate with the companion computer if you desire a more secure connection (micro USB connectors have been known to disconnect in high vibrations).
If a USB connection is detected on the USB peripheral, ROSflight will direct all communication through this port. However, if the PARAM_SERIAL_DEVICE
parameter is set to 3
and the PARAM_BAUD_RATE
parameter is set properly, then UART3 will be enabled when the USB connection is absent.
"},{"location":"user-guide/improving-firmware-performance/","title":"Improving Firmware Performance","text":"ROSflight supplies several methods to improve the performance of your aircraft. Tuning gains, adding feed-forward torques, and tuning the estimator are three ways to get your aircraft flying great!
"},{"location":"user-guide/improving-firmware-performance/#gain-tuning","title":"Gain Tuning","text":"Because there are a wide variety of multirotors out there, no one set of PID controller gains will be optimal for all vehicles. The default set of gains is relatively conservative for most platforms, and should be somewhat airworthy in most cases. However, depending on the inertia-to-torque ratio on your MAV, you may have to change these gains considerably. There are some great tutorials online on multirotor gain tuning; this is another tried-and-true method used to great effect at BYU.
If you are unfamiliar with PIDs, you should probably go read about them before trying to tune a multirotor. Getting an understanding for what is going on will definitely guide your decision making process as you try to find better gains.
While tuning controller gains, it is very likely that the multirotor will oscillate out of control. To handle this scenario, we generally add what we call \"training wheels\" to the multirotors we are tuning. These amount to thin carbon rods in the shape of an X zip-tied to the landing gear. This widens out the base of the multirotor so if you come down on a hard oscillation, chances are the vehicle will land upright, hopefully without a prop strike, or worse, battery damage with a thermal runaway event. If the battery is not tucked inside the main frame, it is wise to add some foam as protection to the battery.
Here is a video of a maiden flight of ROSflight with \"training wheels\" attached.
Now, for the procedure on tuning.
"},{"location":"user-guide/improving-firmware-performance/#tuning-roll-and-pitch-angles","title":"Tuning Roll and Pitch angles","text":"Here is a flowchart describing my PID tuning process for roll and pitch:
You may want to do another D-tuning iteration. Additionally, sometimes it is helpful to do a little tweaking on roll and pitch separately to eek out a little more performance from the differences in roll and pitch dynamics of your vehicle.
Notice that we did not include any I
tuning. As a general rule, try to keep the I
gain as low as possible. It will always slow your response rate to input, and it can induce low frequency oscillations.
You should only have I
gain on roll and pitch if one of the following is true:
- You expect your CG to change, and/or
- You expect your rotor geometry to change
Both of these are pretty rare. Instead, use your RC transmitter to trim the aircraft so it hovers with no stick input. In the RC trim calculation section, we will use the RC trim to calculate a feed-forward torque on the roll, pitch and yaw rates.
"},{"location":"user-guide/improving-firmware-performance/#tuning-yaw-rate","title":"Tuning Yaw rate","text":"Dynamically and algorithmically, using a D
gain in yaw-rate control has no significant advantage. Controlling with derivative requires differentiating gyro measurements, which tends to be pretty noisy. In our experience, putting D
in rate controllers on multirotors has always decreased performance.
Tuning yaw rate is generally pretty easy. Basically, keep cranking it up until you feel like it's \"locked in\". Sometimes, a little bit of I
(on the order of 0.1P) can help with this as well.
The problem with too much P
on yaw rate generally manifests itself in motor saturation. Some, especially larger, multirotors have problems getting enough control authority in yaw with the propellers being aligned flat. After you are done tuning, you might want to look at a plot of motor commands during a fairly aggressive flight. Underactuated yaw will be pretty obvious in these plots, because you will see the motor commands railing. To fix this, you can put shims between the arm mounts and the motors to tilt the motors just a little bit in the direction of yaw for that motor.
"},{"location":"user-guide/improving-firmware-performance/#rc-trim","title":"RC trim","text":"In the vast majority of cases, your multirotor will not be built perfectly. The CG could be slightly off, or your motors, speed controllers and propellers could be slightly different. One way to fix this is by adding an integrator. Integrators get rid of static offsets such as those just mentioned. However, as explained above, integrators also always slow vehicle response. In our case, since this offset is going to be constant, we can instead find a \"feed-forward\", or equilibrium offset, torque that you need to apply to hover without drift.
Use the RC transmitter to find the \"equilibrium torques\" about the x, y, and z axes to keep the multirotor level. This is done by trimming the aircraft with the RC trims. These are usually the little switches next to the sticks on your transmitter. Adjust these until you can hover the multirotor without touching the sticks.
Next, land the multirotor, disarm, center the sticks and perform a trim calibration with ros2 service call /calibrate_rc_trim std_srvs/srv/Trigger
. ROSflight then uses the trim settings on your transmitter to find these feed-forward, or equilibrium, torques that need to be applied post-controller to keep the multirotor level. These torques will be applied to all future commands (both from the companion computer and RC), so you will need to zero out your transmitter trims after calibration.
"},{"location":"user-guide/improving-firmware-performance/#estimator-tuning","title":"Estimator Tuning","text":"ROSflight uses a non-linear complementary filter, based on the quaternion implementation of \"Non-linear complementary filters on the special orthogonal group\" by Robert Mahony1, to estimate attitude and angular rates. The implementation has been improved with suggestions from \"Attitude Representation and Kinematic Propagation for Low-Cost UAVs\" by Robert Casey2. A write-up of the derivation and implementation details can be found in the LaTeX report in reports/estimator.tex
. (You'll need to be able to compile LaTeX sources to view the PDF).
In addition to the complementary filter, accelerometer and gyro measurements are filtered using a simple low-pass filter (LPF) to cut out noise from vibrations. A block diagram of the estimator is shown below for reference. y_{gyro} and y_{acc} are gyro and accelerometer measurements, respectively and \\beta_{gyro} is the estimated gyro biases.
"},{"location":"user-guide/improving-firmware-performance/#tuning-the-low-pass-filter-gains","title":"Tuning the Low-Pass Filter Gains","text":"The ACC_LPF_ALPHA
and GYRO_LPF_ALPHA
parameters are used in the following low-pass-filter implementation (see lines 98-106
of estimator.c
):
x_t = (1-\\alpha)y_t + \\alpha x_{t-1} where y_t is the measurement and x_t is the filtered value. Lowering \\alpha will reduce lag in response, so if you feel like your MAV is sluggish despite all attempts at controller gain tuning, consider reducing \\alpha. Reducing \\alpha too far, however will result in a lot of noise from the sensors making its way into the motors. This can cause motors to get really hot, so make sure you check motor temperature if you are changing the low-pass filter constants.
"},{"location":"user-guide/improving-firmware-performance/#tuning-the-complementary-filter","title":"Tuning the Complementary Filter","text":"The complementary filter has two gains, k_p and k_i. For a complete understanding of how these work, we recommend reading the Mahony Paper, or the technical report in the reports folder. In short, k_p can be thought of as the strength of accelerometer measurements in the filter, and the k_i gain is the integral constant on the gyro bias. These values should probably not be changed. Before you go changing these values, make sure you completely understand how they work in the filter.
If you do decide to change these values, you should stick to the following rule of thumb.
k_i \\approx \\tfrac{k_p}{10}."},{"location":"user-guide/improving-firmware-performance/#external-attitude-measurements","title":"External Attitude Measurements","text":"Because the onboard attitude estimator uses only inertial measurements, the estimates can deviate from truth. This is especially true during extended periods of accelerated flight, during which the gravity vector cannot be measured. Attitude measurements from an external source can be applied to the filter to help improve performance. These external attitude measurements might come from a higher-level estimator running on the companion computer that fuses additional information from GPS, vision, or a motion capture system.
To send these updates to the flight controller, publish a geometry_msgs/Quaternion
message to the external_attitude
topic to which rosflight_io
subscribes. The degree to which this update will be trusted is tuned with the FILTER_KP_EXT
parameter.
-
Mahony, R., Hamel, T. and Pflimlin, J. (2008). Nonlinear Complementary Filters on the Special Orthogonal Group. IEEE Transactions on Automatic Control, 53(5), pp.1203-1218.\u00a0\u21a9
-
Casey, R., Karpenko, M., Curry, R. and Elkaim, G. (2013). Attitude Representation and Kinematic Propagation for Low-Cost UAVs. AIAA Guidance, Navigation, and Control (GNC) Conference.\u00a0\u21a9
"},{"location":"user-guide/overview/","title":"Overview","text":""},{"location":"user-guide/overview/#main-components-of-rosflight","title":"Main Components of ROSflight","text":"ROSflight is intended to be used with both a typical flight controller and a companion Linux computer. Although it can be used with just a flight controller, this setup will not offer most of the advantages of ROSflight.
Note
To avoid confusion, we try to consistently use the following terminology:
- Flight controller: The embedded board that runs the ROSflight firmware and performs I/O with sensors and ESCs
- Companion computer: A Linux computer, running ROS2, that is mounted on the vehicle and has a physical, serial connection with the flight controller
- Offboard control (setpoints): The control setpoints passed from the companion computer to the flight controller. The control is \"offboard\" from the perspective of the flight controller, even though the computer providing those commands is mounted onboard the vehicle.
The following figure illustrates the interactions between the major components of the system:
"},{"location":"user-guide/overview/#firmware","title":"Firmware","text":"The ROSflight firmware is the low level microcontroller code that runs on the flight controller. This communicates directly with sensors and actuators and serves as the bridge between hardware and higher level software. The firmware itself is designed to do as little as possible, offloading most of the work to the companion computer.
Although higher level control is offloaded to the companion computer, enough control and functionality is included in the firmware to enable a safety pilot to fly the UAV through any portion of the flight with or without an operating companion computer.
"},{"location":"user-guide/overview/#rosflight-io","title":"ROSflight IO","text":"ROSflight IO is a ROS2 node that runs on the companion computer that communicates directly with the firmware over a serial connection. This serves as the bridge between the firmware and the rest of ROS2 network.
"},{"location":"user-guide/overview/#rosplane-and-roscopter","title":"ROSplane and ROScopter","text":"ROSplane and ROScopter are ROS2 based autonomy stacks that run on the companion computer and do most of the heavy computation of the autopilot. Each portion of their autonomy stacks are organized into highly modular ROS nodes that can be easily swapped out with custom nodes.
ROSplane and ROScopter are not required for using ROSflight and you could choose to use an entirely different autonomy stack if you so desired.
"},{"location":"user-guide/overview/#rc-safety-pilot","title":"RC Safety Pilot","text":"ROSflight is designed for use with offboard control from experimental and research code. As such, it provides several mechanisms for an RC safety pilot to intervene if something goes wrong with the control setpoints coming from the companion computer:
- RC override switch: The safety pilot can flip a switch on the transmitter to take back RC control. Attitude and throttle override can be mapped independently, meaning you can choose one or the other, put them on separate switches, or put them both on the same switch. Details on these switches are provided on the RC configuration page.
- Stick deviations: If a stick is deviated from its center position, then that channel is overridden by RC control. This allows the safety pilot to take control without flipping a switch. This may be useful to provide a momentary correction on a single axis. The fraction of stick travel needed to activate the RC override is controlled by the
RC_OVRD_DEV
parameter. The OVRD_LAG_TIME
parameter controls the amount of time that the override remains active after the sticks return to center. - Minimum throttle: By default, the flight controller takes the minimum of the two throttle commands from RC and offboard control setpoints. This allows the safety pilot to drop the throttle quickly if needed. This behavior can be turned on or off with the
MIN_THROTTLE
parameter.
"},{"location":"user-guide/overview/#arming-errors-failsafe","title":"Arming, Errors & Failsafe","text":"The flight controller can only be armed and disarmed via RC control. Two mechanisms are provided: sticks (left stick down and right to arm, down and left to disarm) and switch. Only one of these options can be active at a time. Details on configuration are given on the RC configuration page.
The firmware runs a number of error checks before allowing the flight controller to arm. Completing the configuration checklist on the Getting Started page should avoid these errors. In addition to a few internal health checks, the following conditions are checked:
- Mixer: Valid mixer must have been selected (see the Hardware Setup documentation page)
- IMU calibration: The IMU must have been calibrated since firmware was flashed (it is recommended that you recalibrate often)
- RC: There must be an active RC connection
In addition to the error checking before arming, the flight controller enters a failsafe mode if the RC connection is lost during flight while armed. While in failsafe mode the flight controller commands level flight with the throttle value defined by the FAILSAFE_THR
parameter.
The following is a simplified version of the finite state machine that defines logic used for the arming, error checks, and failsafe operations:
The state manager also includes functionality for recovering from hard faults if one were to occur, although this is unlikely with unmodified firmware. If a hard fault occurs while the flight controller is armed, the firmware has the ability to immediately rearm after rebooting to enable continued RC control of the vehicle for recovery.
"},{"location":"user-guide/overview/#leds","title":"LEDs","text":"The meaning of the various LEDs is summarized in the following table. The colors of the LEDs may change depending on your specific board:
LED On Off Slow Blink Fast Blink Power (Blue) Board powered - - - Info (Green) RC control Offboard control - - Warning (Red) Armed Disarmed Error (disarmed) Failsafe (armed)"},{"location":"user-guide/parameter-configuration/","title":"Parameters","text":"The ROSflight firmware has several dozen parameters which it uses to customize performance. Parameters are considered semi-static variables. That is, parameters do not change during flight, but they may change between vehicles. Examples of parameters you may wish to change are:
- Fixed-wing vehicle flag
- PID gains
- Mixer choice
- IMU low-pass filter constant
- RC receiver type (PPM or SBUS)
and so on. Access to all parameters is enabled via ROS2 services advertised by rosflight_io
while the flight controller is connected.
"},{"location":"user-guide/parameter-configuration/#parameter-interface","title":"Parameter Interface","text":""},{"location":"user-guide/parameter-configuration/#getting-parameter-values","title":"Getting Parameter Values","text":"Sometimes it is handy to ask the flight controller what the current value of a parameter is. This is accomplished using the param_get
service. As an example, let's retrieve the roll angle controller proportional (P) gain.
ros2 service call /param_get rosflight_msgs/srv/ParamGet \"{name: \"PID_ROLL_ANG_P\"}\"\n
You should get a response similar to the following (this happens to be the default value with floating-point error):
exists: True\nvalue: 0.15000000596\n
"},{"location":"user-guide/parameter-configuration/#changing-parameters","title":"Changing Parameters","text":"Parameters are changed via the param_set
service. As an example, let's change the roll angle controller P gain. (I will assume that the flight controller is connected and rosflight_io
is running in the root namespace.)
ros2 service call /param_set rosflight_msgs/srv/ParamSet \"{name: \"PID_ROLL_ANG_P\", value: 0.08}\"\n
You should get a prompt from rosflight_io
saying
[ INFO] [1491672408.585339558]: Parameter PID_ROLL_ANG_P has new value 0.08\n[ WARN] [1491672408.585508849]: There are unsaved changes to onboard parameters\n
Notice that the parameters have been set, but not saved. Parameter changes take effect immediately, however they will not persist over a reboot unless you write them to the non-volatile memory. This brings us to the next task.
"},{"location":"user-guide/parameter-configuration/#writing-parameters","title":"Writing Parameters","text":"To ensure that parameter values persist between reboots, you must write the parameters to the non-volatile memory. This is done by calling param_write
ros2 service call /param_write std_srvs/srv/Trigger\n
rosflight_io
should then respond with
[ INFO] [1491672597.123201952]: Param write succeeded\n[ INFO] [1491672597.123452908]: Onboard parameters have been saved\n
Warning
It is highly recommended that you write parameters before arming and flying the vehicle. Among other things, this will ensure that in the rare case that a hard fault is encountered and the flight controller must reboot during flight, the correct configuration will be loaded on reboot.
Error
Parameter writing can only happen if the flight controller is disarmed. If the param write failed for some reason, you may want to make sure your FC is disarmed and try again.
"},{"location":"user-guide/parameter-configuration/#backing-up-and-loading-parameters-from-file","title":"Backing Up and Loading Parameters from File","text":"It is good practice to back up your parameter configuration in case you have to re-flash your firmware or you want to share configurations between vehicles. We can do this via the param_save_to_file
and param_load_from_file
services.
First, let's back up our current parameter configuration:
ros2 service call /param_save_to_file rosflight_msgs/srv/ParamFile \"{filename: \"~/parameters.yaml\"}\"\n
Parameters are saved in YAML format. You must also specify the absolute file name of where you would like your parameters to be saved. The current active set of parameters will be saved, regardless of what is saved in non-volatile memory on the flight controller.
Now, let's say we want to re-load this parameter file
ros2 service call /param_load_from_file rosflight_msgs/srv/ParamFile \"{filename: \"~/parameters.yml\"}\"\n
Again, you must specify the absolute file name of the file to be loaded."},{"location":"user-guide/parameter-configuration/#fixed-wing-parameter-configuration","title":"Fixed-Wing Parameter Configuration","text":"Because ROSflight ships with default parameters for multirotors, you will probably want to change the following parameters if you want to fly a fixed-wing aircraft.
Parameter Description Type Fixed-Wing Value MOTOR_PWM_UPDATE Refresh rate of motor commands to motors and servos (Hz) - See motor documentation int 50 ARM_SPIN_MOTORS Enforce MOTOR_IDLE_PWM int false MOTOR_IDLE_THR min throttle command sent to motors when armed (Set above 0.1 to spin when armed) float 0.1 ARM_CHANNEL RC switch channel mapped to arming [0 indexed, -1 to disable] int 4 FIXED_WING switches on passthrough commands for fixed-wing operation int true MIXER Which mixer to choose - See Mixer documentation int 10 ELEVATOR_REV reverses elevator servo output int 0/1 AIL_REV reverses aileron servo output int 0/1 RUDDER_REV reverses rudder servo output int 0/1 CAL_GYRO_ARM Calibrate gyros when arming - generally only for multirotors int false"},{"location":"user-guide/parameter-configuration/#description-of-all-parameters","title":"Description of all Parameters","text":"This is a list of all ROSflight parameters, including their types, default values, and minimum and maximum recommended values:
Parameter Description Type Default Value Min Max BAUD_RATE Baud rate of MAVlink communication with companion computer int 921600 9600 921600 SERIAL_DEVICE Serial Port (for supported devices) int 0 0 3 SYS_ID Mavlink System ID int 1 1 255 STRM_HRTBT Rate of heartbeat stream (Hz) int 1 0 1000 STRM_STATUS Rate of status stream (Hz) int 10 0 1000 STRM_ATTITUDE Rate of attitude stream (Hz) int 200 0 1000 STRM_IMU Rate of IMU stream (Hz) int 250 0 1000 STRM_MAG Rate of magnetometer stream (Hz) int 50 0 75 STRM_BARO Rate of barometer stream (Hz) int 50 0 100 STRM_AIRSPEED Rate of airspeed stream (Hz) int 50 0 50 STRM_SONAR Rate of sonar stream (Hz) int 40 0 40 STRM_SERVO Rate of raw output stream int 50 0 490 STRM_RC Rate of raw RC input stream int 50 0 50 STRM_GNSS Maximum rate of GNSS data streaming. Higher values allow for lower latency int 1000 0 1000 STRM_GNSS_FULL Maximum rate of fully detailed GNSS data streaming int 0 0 10 STRM_BATTERY Rate of battery status stream int 0 0 50 PARAM_MAX_CMD saturation point for PID controller output float 1.0 0 1.0 PID_ROLL_RATE_P Roll Rate Proportional Gain float 0.070f 0.0 1000.0 PID_ROLL_RATE_I Roll Rate Integral Gain float 0.000f 0.0 1000.0 PID_ROLL_RATE_D Roll Rate Derivative Gain float 0.000f 0.0 1000.0 PID_PITCH_RATE_P Pitch Rate Proportional Gain float 0.070f 0.0 1000.0 PID_PITCH_RATE_I Pitch Rate Integral Gain float 0.0000f 0.0 1000.0 PID_PITCH_RATE_D Pitch Rate Derivative Gain float 0.0000f 0.0 1000.0 PID_YAW_RATE_P Yaw Rate Proportional Gain float 0.25f 0.0 1000.0 PID_YAW_RATE_I Yaw Rate Integral Gain float 0.0f 0.0 1000.0 PID_YAW_RATE_D Yaw Rate Derivative Gain float 0.0f 0.0 1000.0 PID_ROLL_ANG_P Roll Angle Proportional Gain float 0.15f 0.0 1000.0 PID_ROLL_ANG_I Roll Angle Integral Gain float 0.0f 0.0 1000.0 PID_ROLL_ANG_D Roll Angle Derivative Gain float 0.05f 0.0 1000.0 PID_PITCH_ANG_P Pitch Angle Proportional Gain float 0.15f 0.0 1000.0 PID_PITCH_ANG_I Pitch Angle Integral Gain float 0.0f 0.0 1000.0 PID_PITCH_ANG_D Pitch Angle Derivative Gain float 0.05f 0.0 1000.0 X_EQ_TORQUE Equilibrium torque added to output of controller on x axis float 0.0f -1.0 1.0 Y_EQ_TORQUE Equilibrium torque added to output of controller on y axis float 0.0f -1.0 1.0 Z_EQ_TORQUE Equilibrium torque added to output of controller on z axis float 0.0f -1.0 1.0 PID_TAU Dirty Derivative time constant - See controller documentation float 0.05f 0.0 1.0 MOTOR_PWM_UPDATE Overrides default PWM rate specified by mixer if non-zero - Requires reboot to take effect int 0 0 490 MOTOR_IDLE_THR min throttle command sent to motors when armed (Set above 0.1 to spin when armed) float 0.1 0.0 1.0 FAILSAFE_THR Throttle sent to motors in failsafe condition (set just below hover throttle) float 0.3 0.0 1.0 ARM_SPIN_MOTORS Enforce MOTOR_IDLE_THR int true 0 1 FILTER_INIT_T Time in ms to initialize estimator int 3000 0 100000 FILTER_KP estimator proportional gain - See estimator documentation float 0.5f 0 10.0 FILTER_KI estimator integral gain - See estimator documentation float 0.01f 0 1.0 FILTER_KP_COR estimator proportional gain on external attitude correction - See estimator documentation float 10.0f 0 1.0 FILTER_ACCMARGIN allowable accel norm margin around 1g to determine if accel is usable float 0.1f 0 1.0 FILTER_QUAD_INT Perform a quadratic averaging of LPF gyro data prior to integration (adds ~20 us to estimation loop on F1 processors) int 1 0 1 FILTER_MAT_EXP 1 - Use matrix exponential to improve gyro integration (adds ~90 us to estimation loop in F1 processors) 0 - use euler integration int 1 0 1 FILTER_USE_ACC Use accelerometer to correct gyro integration drift (adds ~70 us to estimation loop) int 1 0 1 CAL_GYRO_ARM True if desired to calibrate gyros on arm int false 0 1 GYROXY_LPF_ALPHA Low-pass filter constant on gyro X and Y axes - See estimator documentation float 0.3f 0 1.0 GYROZ_LPF_ALPHA Low-pass filter constant on gyro Z axis - See estimator documentation float 0.3f 0 1.0 ACC_LPF_ALPHA Low-pass filter constant on all accel axes - See estimator documentation float 0.5f 0 1.0 GYRO_X_BIAS Constant x-bias of gyroscope readings float 0.0f -1.0 1.0 GYRO_Y_BIAS Constant y-bias of gyroscope readings float 0.0f -1.0 1.0 GYRO_Z_BIAS Constant z-bias of gyroscope readings float 0.0f -1.0 1.0 ACC_X_BIAS Constant x-bias of accelerometer readings float 0.0f -2.0 2.0 ACC_Y_BIAS Constant y-bias of accelerometer readings float 0.0f -2.0 2.0 ACC_Z_BIAS Constant z-bias of accelerometer readings float 0.0f -2.0 2.0 ACC_X_TEMP_COMP Linear x-axis temperature compensation constant float 0.0f -2.0 2.0 ACC_Y_TEMP_COMP Linear y-axis temperature compensation constant float 0.0f -2.0 2.0 ACC_Z_TEMP_COMP Linear z-axis temperature compensation constant float 0.0f -2.0 2.0 MAG_A11_COMP Soft iron compensation constant float 1.0f -999.0 999.0 MAG_A12_COMP Soft iron compensation constant float 0.0f -999.0 999.0 MAG_A13_COMP Soft iron compensation constant float 0.0f -999.0 999.0 MAG_A21_COMP Soft iron compensation constant float 0.0f -999.0 999.0 MAG_A22_COMP Soft iron compensation constant float 1.0f -999.0 999.0 MAG_A23_COMP Soft iron compensation constant float 0.0f -999.0 999.0 MAG_A31_COMP Soft iron compensation constant float 0.0f -999.0 999.0 MAG_A32_COMP Soft iron compensation constant float 0.0f -999.0 999.0 MAG_A33_COMP Soft iron compensation constant float 1.0f -999.0 999.0 MAG_X_BIAS Hard iron compensation constant float 0.0f -999.0 999.0 MAG_Y_BIAS Hard iron compensation constant float 0.0f -999.0 999.0 MAG_Z_BIAS Hard iron compensation constant float 0.0f -999.0 999.0 BARO_BIAS Barometer measurement bias (Pa) float 0.0f 0 inf GROUND_LEVEL Altitude of ground level (m) float 1387.0f -1000 10000 DIFF_PRESS_BIAS Differential Pressure Bias (Pa) float 0.0f -10 10 RC_TYPE Type of RC input 0 - PPM, 1 - SBUS int 0 0 1 BATT_VOLT_MULT Battery monitor voltage multiplier float 0 0 inf BATT_CURR_MULT Battery monitor current multiplier float 0 0 inf BATT_VOLT_ALPHA Batter monitor voltage filter alpha. Values closer to 1 smooth the signal more. float 0.995 0 1 BATT_CURR_ALPHA Battery monitor current filter alpha. Values closer to 1 smooth the signal more. float 0.995 0 1 RC_X_CHN RC input channel mapped to x-axis commands [0 - indexed] int 0 0 3 RC_Y_CHN RC input channel mapped to y-axis commands [0 - indexed] int 1 0 3 RC_Z_CHN RC input channel mapped to z-axis commands [0 - indexed] int 3 0 3 RC_F_CHN RC input channel mapped to F-axis commands [0 - indexed] int 2 0 3 RC_ATT_OVRD_CHN RC switch mapped to attitude override [0 indexed, -1 to disable] int 4 4 7 RC_THR_OVRD_CHN RC switch channel mapped to throttle override [0 indexed, -1 to disable] int 4 4 7 RC_ATT_CTRL_CHN RC switch channel mapped to attitude control type [0 indexed, -1 to disable] int -1 4 7 ARM_CHANNEL RC switch channel mapped to arming (only if PARAM_ARM_STICKS is false) [0 indexed, -1 to disable] int -1 4 7 RC_NUM_CHN number of RC input channels int 6 1 8 SWITCH_5_DIR RC switch 5 toggle direction int 1 -1 1 SWITCH_6_DIR RC switch 6 toggle direction int 1 -1 1 SWITCH_7_DIR RC switch 7 toggle direction int 1 -1 1 SWITCH_8_DIR RC switch 8 toggle direction int 1 -1 1 RC_OVRD_DEV RC stick deviation from center for override float 0.1 0.0 1.0 OVRD_LAG_TIME RC stick deviation lag time before returning control (ms) int 1000 0 100000 MIN_THROTTLE Take minimum throttle between RC and computer at all times int true 0 1 RC_ATT_MODE Attitude mode for RC sticks (0: rate, 1: angle). Overridden if RC_ATT_CTRL_CHN is set. int 1 0 1 RC_MAX_ROLL Maximum roll angle command sent by full deflection of RC sticks float 0.786f 0.0 3.14159 RC_MAX_PITCH Maximum pitch angle command sent by full stick deflection of RC sticks float 0.786f 0.0 3.14159 RC_MAX_ROLLRATE Maximum roll rate command sent by full stick deflection of RC sticks float 3.14159f 0.0 9.42477796077 RC_MAX_PITCHRATE Maximum pitch command sent by full stick deflection of RC sticks float 3.14159f 0.0 3.14159 RC_MAX_YAWRATE Maximum pitch command sent by full stick deflection of RC sticks float 1.507f 0.0 3.14159 MIXER Which mixer to choose - See Mixer documentation int Mixer::INVALID_MIXER 0 10 FIXED_WING switches on pass-through commands for fixed-wing operation int false 0 1 ELEVATOR_REV reverses elevator servo output int 0 0 1 AIL_REV reverses aileron servo output int 0 0 1 RUDDER_REV reverses rudder servo output int 0 0 1 FC_ROLL roll angle (deg) of flight controller wrt aircraft body float 0.0f 0 360 FC_PITCH pitch angle (deg) of flight controller wrt aircraft body float 0.0f 0 360 FC_YAW yaw angle (deg) of flight controller wrt aircraft body float 0.0f 0 360 ARM_THRESHOLD RC deviation from max/min in yaw and throttle for arming and disarming check (us) float 0.15 0 500 OFFBOARD_TIMEOUT Timeout in milliseconds for offboard commands, after which RC override is activated int 100 0 100000"},{"location":"user-guide/preflight-checks/","title":"Pre-Flight Checklist","text":"This is an example of a ROSflight pre-flight checklist. You will likely need to augment this with checks specific to both (a) your hardware and (b) the code running on your companion computer.
"},{"location":"user-guide/preflight-checks/#before-powering-up-motors","title":"Before powering up motors","text":" - ROS2 is running on the companion computer, communicating with the base station
-
rosflight_io
reports no errors - Sensors are calibrated and publishing
- IMU (re-calibrate every flight):
ros2 service call /calibrate_imu std_srvs/srv/Trigger
- Barometer:
ros2 service call /calibrate_baro std_srvs/srv/Trigger
- Sonar (if attached)
- Airspeed (if attached)
- Estimated attitude is being published and looks accurate
- Published outputs look reasonable
- Parameter Check (if using a fixed-wing, there are about 8 parameters you will need to change from default)
- RC communication
- Failsafe behavior
- Arming and disarming
- RC override behavior
- RC range test
- Wire-wiggle test (wiggle all wires to look for bad connections)
- If desired, logging is turned on (e.g. recording a ros2 bag)
"},{"location":"user-guide/preflight-checks/#after-powering-up-motors","title":"After Powering Up Motors","text":"Danger
Be sure the flight controller is disarmed before powering up motors!!!
- Arm/Disarm test
- Propeller spin test (check directions and response to stick inputs)
- Control surface test (fixed-wing)
- Response to offboard controls
"},{"location":"user-guide/rc-configuration/","title":"RC Configuration","text":""},{"location":"user-guide/rc-configuration/#binding-your-transmitter-to-your-receiver","title":"Binding your Transmitter to your Receiver","text":"Follow the instructions in your user manual to bind your transmitter to your RC receiver. You may also be able to find a guide on YouTube with instructions; just search for your particular transmitter and receiver model.
"},{"location":"user-guide/rc-configuration/#rc-transmitter-calibration","title":"RC Transmitter Calibration","text":"To avoid confusion and to reduce code complexity in the firmware source code, ROSflight does not perform software calibration of RC transmitters. This means that RC calibration must be done on the transmitter itself, as opposed to in software. This is pretty straight-forward for most modern transmitters.
"},{"location":"user-guide/rc-configuration/#configure-the-full-stick-output-for-each-channel","title":"Configure the full stick output for each channel","text":"The easiest way to do this is to enter the \"Servo Setup\" Menu (for Spektrum transmitters) and change the servo travel variable. You can watch the raw RC readings from the flight controller by echoing the rc_raw topic from rosflight_io
ros2 topic echo /rc_raw\n
- Center both sticks on your transmitter
- Apply subtrim until the first four channels all read 1500 exactly (or as close as possible--some RC receivers are worse than others and cannot exactly output 1500 us)
- Set the channel endpoints so that maximum stick deflections result in readings of 1000 and 2000 us.
"},{"location":"user-guide/rc-configuration/#configure-stick-directions-for-roll-pitch-and-yaw-channels","title":"Configure stick directions for roll, pitch, and yaw channels.","text":"You now have to make sure your RC transmitter is sending commands consistent with the north-east-down (NED) frame assumed by ROSflight.
You may find this graphic helpful. It shows all the basic stick positions, and the associated output from the first four channels when looking at a raw AETR (aileron, elevator, throttle, rudder) RC signal from rosflight_io
. Make sure that the stick output is in the correct direction.
It should be noted that channel assignment can be modified via the RC_*_CHN
parameters. So, if you are using something other than AETR assignment, the channel index for each stick may be different, but the direction should be the same.
"},{"location":"user-guide/rc-configuration/#switch-configuration","title":"Switch Configuration","text":"Switches can be configured for the following functions. To disable a switch for a specific, default function, set the corresponding parameter to -1
. Be sure to check that the switch directions operate as you intend, and reverse them in your transmitter if necessary.
"},{"location":"user-guide/rc-configuration/#safety-pilot-configuration","title":"Safety Pilot Configuration","text":"The RC_ATT_OVRD_CHN
parameter maps a switch to override attitude commands with RC control. The RC_THR_OVRD_CHN
parameter maps a switch to override throttle commands with RC control. To override both with a single switch, set both parameters to the same value (this is the default behavior).
"},{"location":"user-guide/rc-configuration/#arming","title":"Arming","text":"By default, arming is done with the sticks (left stick down and right to arm, down and left to disarm). To use a switch instead, set the ARM_CHANNEL
parameter to the desired channel. Setting an arming switch disables arming with the sticks.
"},{"location":"user-guide/rc-configuration/#flight-mode","title":"Flight Mode","text":"If desired, you can map a switch to select between attitude control types (angle and rate) in flight by setting the RC_ATT_CTRL_CHN
parameter to the desired channel. This can be useful if, for example, you are learning rate mode but want to be able to switch back to attitude mode to help stabilize the vehicle. This feature is disabled by default.
"},{"location":"user-guide/ros2-setup/","title":"Installing/Setting up ROS2","text":"You will need to get ROS2 on both the companion computer and the base station laptop. This can be done with a native installation or with Docker. To install ROS2 natively, Check out the official ROS2 Installation page for details. Make sure to install both the ros-humble-desktop
and ros-dev-tools
packages, or the equivalent packages for your version of ROS2. ros-humble-ros-base
can be used instead of ros-humble-desktop
if you don't need GUI tools or the simulation.
We support all fixed-release ROS2 versions that are not EOL, which currently includes ROS2 Humble and ROS2 Iron. ROS2 Rolling is not fixed-release and is therefore not officially supported.
"},{"location":"user-guide/ros2-setup/#installing-rosflight","title":"Installing ROSflight","text":"You will need to install the ROSflight packages on both the companion computer and the base station computer. The companion computer will run the node that actually communicates with the flight controller over a serial connection, while the base station needs the message and service definitions to be able to call services or subscribe and publish to topics.
"},{"location":"user-guide/ros2-setup/#from-source","title":"From Source","text":"First, set up a ROS2 workspace:
mkdir -p ~/rosflight_ws/src\ncd ~/rosflight_ws/src\n
Next, download the source code into your workspace (include the --recursive
argument to download the necessary submodules):
git clone --recursive https://github.com/rosflight/rosflight_ros_pkgs.git\n
Install dependencies:
sudo rosdep init\nrosdep update\nrosdep install --from-path . -y --ignore-src\n
Note
Gazebo does not have an arm64 build target. If using a companion computer with arm64 architecture, append --skip-keys=\"gazebo_dev gazebo_plugins gazebo_ros gazebo\"
to the rosdep install
command above. This will skip installing Gazebo and the compilation of rosflight_sim, which currently requires Gazebo.
Build the packages:
cd ~/rosflight_ws\ncolcon build\n
Source the setup file and set it to be sourced automatically:
source ~/rosflight_ws/install/setup.bash\necho \"source ~/rosflight_ws/install/setup.bash\" >> ~/.bashrc\n
Note
You'll also need to source the file at /usr/share/gazebo/setup.sh
if you plan to use the Gazebo simulator.
"},{"location":"user-guide/ros2-setup/#running-rosflight_io","title":"Running rosflight_io","text":"The rosflight_io
node is the bridge between ROS2 and the MAVLink communication with the flight controller. This node must be run on the computer that has the physical serial connection to your flight controller. To run this node, use something like the following command:
ros2 run rosflight_io rosflight_io --ros-args -p port:=/dev/ttyUSB0\n
Replace /dev/ttyUSB0
with the port your flight controller is connected to."},{"location":"user-guide/ros2-setup/#using-a-docker-container-to-run-ros2","title":"Using a Docker Container to run ROS2","text":"Note
This guide was written for using Linux as the host machine, but theoretically you should be able to use Docker to do the same thing on Mac or Windows. However, the specifics of the commands may be different. Please refer to the Docker documentation for information on how to use Docker on a non-Linux system.
Tip
This guide was written using ROS2 Humble Docker images, but any distribution of ROS can be used. Just replace humble
with the name of the distribution you want to use.
If you aren't running a compatible version of Linux for ROS2, don't want to make changes to your system, want to be able to easily switch between ROS verions, or just want to containerize your applications, then you can use Docker containers. To get started, install Docker Engine, sometimes referred to as Docker server.
Docker works by running self-contained systems called containers, which act kind of like a separate computer system but without all the overhead of a full virtual machine. Docker containers are based on Docker images, which provide the initial operating system, files, and programs for the Docker container. Fortunately, the developers of ROS provide Docker images for nearly all versions of ROS, which makes it very easy to get any version of ROS up and running on your system very quickly.
- To start a Docker container with ROS run this command:
docker run -it ros:humble\n
Once completed, you should enter a bash terminal in a fresh installation of Ubuntu and ROS! However, the container does not have access to any USB devices, source files on your system, or your network to be able to communicate with different computers. To do these things we'll need to add more arguments to the docker run
command.
-
To give access to source file on your system, mount a folder on your system to the docker container with the -v
argument:
docker run -it -v /folder_to_mount_from_host:/location_to_mount_folder_in_container ros:humble\n
-
To give access to a USB device, you need to mount the location of the USB device and give the container sudo access to your host system with --privileged
:
docker run -it -v /dev/usb_to_mount:/dev/USB --privileged ros:humble\n
-
You can also mount the entire /dev
folder to the container if you want to simplify the process of giving access to USB devices by not needing to know the address of the USB device beforehand. However, the more resources you give to the container, the less secure it is:
docker run -it -v /dev:/dev --privileged ros:humble\n
-
To give access to your network, specify the network to use as the host's network with --network host
.
docker run -it --network host ros:humble\n
It is worth noting that every time you use the docker run
command, a new container with those specific arguments are created. So, if you want a container with access to all those things, you need to use all the arguments at once.
- As an example, if I wanted to make a ROS2 Humble container with access to a USB device at
/dev/ttyUSB0
, access to my host network, access to the source files at ~/rosflight_ws
, and give the container a convenient name of rosflight
with the --name
argument, I would use this command: docker run --name rosflight -it -v /dev/ttyUSB0:/dev/ttyUSB0 --privileged --network host -v ~/rosflight_ws:/root/rosflight_ws ros:humble\n
Something the previous commands don't include is the ability to render GUI tools (like rqt_graph and Gazebo). Being able to render GUI tools can be done a number of ways, but an easy way is to give the container access to your system's X11 windowing system. Note that this isn't the most secure method and doesn't include GPU acceleration. (For more information about including GPU acceleration, refer to the guide found here.)
-
To give access to the host's windowing system, use the following commands. Note that the base Docker image is osrf/ros:humble-desktop-full
, as ros:humble
doesn't include GUI tools in the image. Also, xhost +local:root
needs to be run once per login session and is not persistent.
xhost +local:root\ndocker run -it --env=\"DISPLAY\" --env=\"QT_X11_NO_MITSHM=1\" --volume=\"/tmp/.X11-unix:/tmp/.X11-unix:rw\" osrf/ros:humble-desktop-full\n
-
To create a GUI enabled ROS container named rosflight
with access to the host network, source files found at ~/rosflight_ws
, and a USB device, use this command:
xhost +local:root\ndocker run --name rosflight -it -v /dev/ttyUSB0:/dev/ttyUSB0 --privileged --network host -v ~/rosflight_ws:/rosflight_ws --env=\"DISPLAY\" --env=\"QT_X11_NO_MITSHM=1\" --volume=\"/tmp/.X11-unix:/tmp/.X11-unix:rw\" osrf/ros:humble-desktop-full\n
Warning
During testing, we found some strange behavior with ROS when running a GUI enabled container on a system with ROS already installed. If you need a GUI enabled system, try to do so on a system without ROS installed (or at the very least avoid sourcing/using ROS on your system). Also avoid having multiple GUI enabled containers running at once.
Some other useful Docker commands:
-
To see all containers that exist on your system and their names:
docker ps -a\n
-
To start a container named rosflight
that was previously created with the docker run
command:
docker start -i rosflight\n
-
To open another bash terminal in a container named rosflight
that is already running:
docker exec -it rosflight bash\n
-
To delete a container named rosflight
:
docker rm rosflight\n
You should now be able to create Docker containers with everything you need to run ROSflight! Docker is a very powerful tool and there is much more you can do with Docker to improve your development workflow. However, we're not interested in making an exhaustive Docker guide so please refer to the Docker documentation or other online guides to learn more.
"},{"location":"user-guide/roscopter-setup/","title":"ROScopter","text":"ROScopter is still under development. Check the github repo for the latest instructions.
"},{"location":"user-guide/rosplane-setup/","title":"ROSplane Setup","text":"ROSplane v2.0.0-beta is now available! Check the github repo for the latest instructions.
ROSplane is a basic fixed-wing autopilot build around ROS2 for use with the ROSflight autopilot. It is built according to the methods published in Small Unmanned Aircraft: Theory and Practice by Dr. Randy Beard and Dr. Tim McLain.
"},{"location":"user-guide/rosplane-setup/#requirements","title":"Requirements","text":"ROSplane requires a working ROS2 installation on a companion computer. ROSplane will most often be used in conjunction with the ROSflight firmware and the firmware interface (aka rosflight_ros_pkgs
).
Follow the instructions on ROS2 Setup to install and set up ROS2 and rosflight_ros_pkgs
.
"},{"location":"user-guide/rosplane-setup/#installation","title":"Installation","text":"You will need to install ROSplane on the companion computer.
First, navigate to the src directory of the ROS2 workspace and clone the git repository:
cd /path/to/rosflight_ws/src\ngit clone https://github.com/rosflight/rosplane.git\n
Note
Your rosflight_ws
file structure should now look like:
rosflight_ws\n \u2514\u2500\u2500 src \n \u251c\u2500\u2500 rosflight_ros_pkgs\n \u2514\u2500\u2500 rosplane \n
Then navigate to the top of the rosflight_ws
directory and build:
cd ..\ncolcon build\n
Next, source the rosflight_ws
install files. If you already added the source command to your .bashrc
from the ROS2 Setup page, then you can skip this step.
# source the install file\nsource install/setup.bash\n\n# add it to your .bashrc\necho \"source install/setup.bash >> $HOME/.bashrc\"\n
Note that sourcing the setup.bash
file in the rosflight_ws
directory will install all ROS2 packages in any subdirectories.
"},{"location":"user-guide/rosplane-setup/#running-rosplane-sil","title":"Running ROSplane SIL","text":"A controller or a simulated controller can be used to fly the aircraft in simulation. See the README.md
file for the rosflight_ros_pkgs
package for more information on RC controll in simulation.
"},{"location":"user-guide/rosplane-setup/#launching","title":"Launching","text":""},{"location":"user-guide/rosplane-setup/#recommended-method","title":"Recommended Method","text":"A convenience bash script has been included that uses tmux to launch Gazebo, an instance of the ROSflight firmware, and ROSplane. Note that this requires tmux, so you may need to install it with sudo apt install tmux
. Run
./src/rosplane/rosplane/scripts/rosplane_gcs_launch.sh\n
from the rosflight_ws
directory. Note that the script needs options specified, so it will fail. However,it will print out the required configuration options. See the script for more information."},{"location":"user-guide/rosplane-setup/#alternative-method","title":"Alternative Method","text":"Alternatively, you can run each of the commands in the bash script individually:
# Terminal 1 - Launches Gazebo and a simulated instance of the firmware\nros2 launch rosflight_sim fixedwing.launch.py\n\n# Terminal 2 - Runs rosflight_io configured for SIL to interface with the firmware\nros2 run rosflight_io rosflight_io --ros-args -p udp:=true\n\n# Terminal 3 - Launches rosplane with the Anaconda aerodynamic coefficients\nros2 launch rosplane_sim sim.launch.py aircraft:=anaconda\n
You can also replace the first two commands above with the convenience launch file that does both:
ros2 launch rosflight_sim fixedwing_sim_io_joy.launch.py aircraft:=anaconda\n
Remember to launch ROSplane if you use this method."},{"location":"user-guide/rosplane-setup/#additional-setup","title":"Additional Setup","text":""},{"location":"user-guide/rosplane-setup/#recommended-method_1","title":"Recommended Method","text":"If this is your first time launching ROSplane, make sure to run the convenience launch script to initialize the firmware parameters and calibrate the IMU.
ros2 launch rosflight_sim fixedwing_init_firmware.launch.py\n
"},{"location":"user-guide/rosplane-setup/#alternative-method_1","title":"Alternative Method","text":"Alternatively, you can run the following commands to initialize firmware parameters and calibrate the IMU. Firmware parameters should first be loaded using
ros2 service call /param_load_from_file rosflight_msgs/srv/ParamFile \"filename: /path/to/rosflight_ws/src/rosflight_ros_pkgs/rosflight_sim/params/fixedwing_firmware.yaml\"\n
The IMU should then be calibrated to remove the random biases generated at startup. Note that the random number generator used to create these biases is seeded with a constant value, so this calibration should only need to be performed once. See the code to change the way these biases are calculated.
ros2 service call /calibrate_imu std_srvs/srv/Trigger\n
After calibrating, write the parameters to a file using:
ros2 service call /param_write std_srvs/srv/Trigger\n
This command will create a directory named rosflight_memory
where the parameters are written. The ROSflight firmware will automatically check if the rosflight_memory
directory is present when launched and will use those parameters if available. Note
The ROSflight firmware will only look for the rosflight_memory
directory in the directory where the launch command is run. You must launch rosflight_sim
in the same directory to use the saved parameters; otherwise, reload and re-write the parameters.
"},{"location":"user-guide/rosplane-setup/#flying-in-sim","title":"Flying in Sim","text":"Once you have the simulation booted up, use channel 4 of a connected transmitter to arm. If you are using a simulated transmitter, use ros2 service call /toggle_arm std_srvs/srv/Trigger
to toggle arm/disarm.
After arming, the plane will operate under RC control. Verify that the commands are working and that the aircraft is responding as expected.
To fly autonomously, use channel 5 to disable RC override. If using a simulated transmitter, use ros2 service call /toggle_override std_srvs/srv/Trigger
to toggle RC override on/off.
The plane should then take off or fly autonomously in the Gazebo simulator!
"},{"location":"user-guide/rosplane-setup/#running-rosplane-on-hardware","title":"Running ROSplane on Hardware","text":"Ensure rosflight_io
is running on the companion computer, and that the flight controller is connects to the companion computer.
Launch ROSplane using
ros2 launch rosplane rosplane.launch.py\n
Arm the aircraft using channel 4 of the safety RC transmitter. When ready to let ROSplane take control, use channel 5 of the RC transmitter to disable RC override.
Warning
Disabling RC override on hardware will turn control over to ROSplane. A safety pilot should always be ready to take control, especially when running untested code.
"},{"location":"user-guide/rosplane-setup/#flying-waypoint-missions-in-sim-and-hardware","title":"Flying Waypoint Missions (in sim and hardware)","text":"Autonomous waypoint missions can easily be flown using ROSplane. The waypoints of a mission are controlled by the path_planner
node. These waypoints are sent to the path_manager
node. Low level path-following is done by the path_follower
node. See \"Small Unmanned Aircraft: Theory and Practice\" by Dr. Randy Beard and Dr. Tim McLain for more information on the architecture. See Path Planning for more information on how to use and tune the path planner, manager, and follower.
"},{"location":"user-guide/rosplane-setup/#adding-waypoints","title":"Adding waypoints","text":""},{"location":"user-guide/rosplane-setup/#recommended-method_2","title":"Recommended Method","text":"ROSplane initializes with no waypoints added to the path_planner
. We recommend using a mission .yaml file (an example mission can be found in rosplane/params/fixedwing_mission.yaml
). Loading the mission can be done using
ros2 service call /load_mission_from_file rosflight_msgs/srv/ParamFile \"{filename: <FILENAME>}\"\n
where FILENAME
is the absolute path to the mission .yaml file. Note that the origin (0,0,0) is placed at the GNSS location where ROSplane was initialized.
Note
All waypoints must include a valid [X, Y, Z]
, va_d
, and lla
values.
"},{"location":"user-guide/rosplane-setup/#alternative-method_2","title":"Alternative Method","text":"Alternatively, you can add a waypoint one at a time by calling the appropriate service
ros2 service call /add_waypoint rosplane_msgs/srv/AddWaypoint \"{w: [X, Y, Z], chi_d: CHI_D, lla: USE_LLA, use_chi: USE_CHI, va_d: VA_D}\"\n
where [X, Y, Z]
is the NED position of the waypoint from the origin (in meters) OR the GNSS location of the waypoint (LLA), CHI_D
is the desired heading at the waypoint, and VA_D
is the airspeed at the waypoint. Set the lla
field to true
if the waypoint [X, Y, Z]
field is given in GNSS coordinates and false
if given in NED coordinates. Corners in the path are controlled by USE_CHI
, where a value of True
will cause ROSplane to use a Dubins path planner and a value of False
will cause a fillet path planner to be used. Adding waypoints can be done at any time, even after loading from a file.
Clearing waypoints can be done using
ros2 service call /clear_waypoints std_msgs/srv/Trigger\n
"},{"location":"user-guide/rosplane-setup/#publishing-waypoints","title":"Publishing Waypoints","text":"The path_planner
node automatically publishes a small number of waypoints (default is 3) at the beginning of this mission. This number is controlled by the num_waypoints_to_publish_at_start
ROS2 parameter.
Additional waypoints can be published using
ros2 service call /publish_next_waypoint std_srvs/srv/Trigger\n
"},{"location":"user-guide/running-gazebo-simulation/","title":"Running Simulations in Gazebo","text":"ROSflight comes with a useful tool allowing it to perform software-in-the-loop (SIL) simulations of the ROSflight firmware in Gazebo.
"},{"location":"user-guide/running-gazebo-simulation/#architecture-of-the-sil-simulation","title":"Architecture of the SIL Simulation","text":"To best mimic the hardware experience of ROSflight, the SIL plugin for Gazebo actually implements the firmware source code as a library. We just implemented a different \"board layer\" which uses gazebo instead of hardware calls for things like imu_read()
and pwm_write()
. Instead of a serial link over USB to the flight controller, we use a UDP connection bouncing off of localhost to communicate between rosflight_io
and the firmware. This means the interface to the SIL plugin is identical to that of hardware. rosflight_io
is the main gateway to the firmware in simulation, just as it is in hardware.
The following table summarizes the correlation between connections in hardware and simulation:
Connection Type Hardware Simulation Serial communications to rosflight_io
USB / UART UDP RC PPM Receiver ROS2 RC
topic (rosflight_msgs/RCRaw
) Motors PWM Gazebo Plugin Sensors SPI/I2C Gazebo Plugin"},{"location":"user-guide/running-gazebo-simulation/#quick-start-guide-to-sil-simulation","title":"Quick-Start Guide to SIL Simulation","text":"Note
To simulate a fixed-wing mav, just change all instances of multirotor
in the steps below to fixedwing
.
-
Setup ROSflight with the ROS2 Setup guide, making sure to install the -desktop
package of ROS2, not the -ros-base
.
-
Source the Gazebo setup file if you haven't added it to ~/.bashrc
:
source /usr/share/gazebo/setup.sh\n
-
Launch Gazebo with the ROSflight SIL:
ros2 launch rosflight_sim multirotor.launch.py\n
-
Gazebo should now be running, and you should have the following rqt_graph
.
-
At this point, you can't actually do anything because there is no RC connection and no rosflight_io
to talk to the firmware. Let's start by running a rosflight_io
node. In a separate terminal, run:
ros2 run rosflight_io rosflight_io --ros-args -p udp:=true\n
- The
udp
parameter tells rosflight_io
to simulate a serial connection over UDP rather than using the USB connection to hardware
Your rqt_graph
should look something like the following image. This looks funny because ROS2 doesn't actually know that there is a UDP connection between rosflight_io
and gazebo. There is one, though, and you can test it by echoing any of the topics published by rosflight_io
.
- Start up a simulated RC connection. The easiest way to do this is with the ROSflight utility
rc_joy.py
. Connect a joystick to the computer (or transmitter) and run: ros2 run rosflight_sim rc_joy.py --ros-args --remap /RC:=/multirotor/RC\n
This simulates the RC connection in hardware. If everything is mapped correctly, you should now be able to arm, disarm and fly the aircraft in simulation!
Tip
To start the Gazebo sim, rosflight_io node, and rc_joy.py utility all at once, run this command instead of the three commands individually:
ros2 launch rosflight_sim multirotor_sim_io_joy.launch.py \n
Note
It is much easier to fly with a real transmitter than with an Xbox-type controller. FrSky Taranis QX7 transmitters, Radiomaster TX16s transmitters, and RealFlight controllers are also supported. Non-Xbox joysticks may have incorrect mappings. If your joystick does not work, and you write your own mapping, please contribute back your new joystick mapping!
Remember, the SIL tries its best to replicate hardware. That means you have to calibrate and set parameters in the same way you do in hardware. See the Hardware Setup and Parameter Configuration pages in this documentation for instructions on how to perform all preflight configuration before the aircraft will arm. You can also run
ros2 launch rosflight_sim multirotor_init_firmware.launch.py\n
to load all required parameters and perform initial calibrations for a quick simulation setup."}]}
\ No newline at end of file
diff --git a/git-main/sitemap.xml b/git-main/sitemap.xml
index 79ab79a..63accdf 100644
--- a/git-main/sitemap.xml
+++ b/git-main/sitemap.xml
@@ -2,157 +2,157 @@
http://rosflight.org/git-main/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/developer-guide/contribution-guidelines/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/developer-guide/style-guide/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/developer-guide/firmware/building-and-flashing/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/developer-guide/firmware/code-architecture/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/developer-guide/firmware/debugging/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/developer-guide/firmware/unit-tests/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/developer-guide/rosplane/parameter-management/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/developer-guide/rosplane/controller/controller-base/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/developer-guide/rosplane/controller/controller-general-overview/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/developer-guide/rosplane/controller/controller-outline/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/developer-guide/rosplane/controller/controller-software-architecture/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/developer-guide/rosplane/controller/controller-state-machine/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/developer-guide/rosplane/controller/controller-total-energy/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/developer-guide/rosplane/navigation/navigation-overview/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/developer-guide/rosplane/navigation/path-follower/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/developer-guide/rosplane/navigation/path-manager/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/developer-guide/rosplane/navigation/path-planner/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/user-guide/autonomous-flight/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/user-guide/flight-controller-setup/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/user-guide/getting-started/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/user-guide/hardware-setup/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/user-guide/improving-firmware-performance/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/user-guide/overview/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/user-guide/parameter-configuration/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/user-guide/preflight-checks/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/user-guide/rc-configuration/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/user-guide/ros2-setup/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/user-guide/roscopter-setup/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/user-guide/rosplane-setup/
- 2024-06-24
+ 2024-06-28
daily
http://rosflight.org/git-main/user-guide/running-gazebo-simulation/
- 2024-06-24
+ 2024-06-28
daily
\ No newline at end of file
diff --git a/git-main/sitemap.xml.gz b/git-main/sitemap.xml.gz
index 80d9d7f..867e582 100644
Binary files a/git-main/sitemap.xml.gz and b/git-main/sitemap.xml.gz differ