mirror of
https://github.com/iNavFlight/inav.git
synced 2025-07-12 19:10:27 +03:00
- Bugfixes
- Add magnetometer and rnagefinder - Add joystick interface - Configuator integration - Update docs
This commit is contained in:
parent
1af0e6116b
commit
154ea341f4
34 changed files with 706 additions and 256 deletions
30
.github/workflows/ci.yml
vendored
30
.github/workflows/ci.yml
vendored
|
@ -43,6 +43,36 @@ jobs:
|
|||
name: ${{ env.BUILD_NAME }}.zip
|
||||
path: ./build/*.hex
|
||||
|
||||
build-SITL:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get update && sudo apt-get -y install ninja-build
|
||||
- name: Setup environment
|
||||
env:
|
||||
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
|
||||
run: |
|
||||
# This is the hash of the commit for the PR
|
||||
# when the action is triggered by PR, empty otherwise
|
||||
COMMIT_ID=${{ github.event.pull_request.head.sha }}
|
||||
# This is the hash of the commit when triggered by push
|
||||
# but the hash of refs/pull/<n>/merge, which is different
|
||||
# from the hash of the latest commit in the PR, that's
|
||||
# why we try github.event.pull_request.head.sha first
|
||||
COMMIT_ID=${COMMIT_ID:-${{ github.sha }}}
|
||||
BUILD_SUFFIX=ci-$(date '+%Y%m%d')-$(git rev-parse --short ${COMMIT_ID})
|
||||
VERSION=$(grep project CMakeLists.txt|awk -F VERSION '{ gsub(/^[ \t]+|[ \t\)]+$/, "", $2); print $2 }')
|
||||
echo "BUILD_SUFFIX=${BUILD_SUFFIX}" >> $GITHUB_ENV
|
||||
echo "BUILD_NAME=inav-${VERSION}-${BUILD_SUFFIX}" >> $GITHUB_ENV
|
||||
- name: Build SITL
|
||||
run: mkdir -p build_SITL && cd build_SITL && cmake -DSITL=ON -DWARNINGS_AS_ERRORS=ON -G Ninja .. && ninja
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v2-preview
|
||||
with:
|
||||
name: ${{ env.BUILD_NAME }}_SITL.zip
|
||||
path: ./build_SITL/*_SITL
|
||||
|
||||
test:
|
||||
needs: [build]
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
@ -44,8 +44,8 @@ else()
|
|||
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/${TOOLCHAIN}.cmake")
|
||||
else()
|
||||
set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/${TOOLCHAIN}.cmake")
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/${TOOLCHAIN}-checks.cmake")
|
||||
endif()
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/${TOOLCHAIN}-checks.cmake")
|
||||
endif()
|
||||
|
||||
project(INAV VERSION 6.0.0)
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
set(gcc_host_req_ver 10)
|
||||
|
||||
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
OUTPUT_VARIABLE version)
|
||||
|
||||
message("-- found GCC ${version}")
|
||||
if (NOT gcc_host_req_ver STREQUAL version)
|
||||
message(FATAL_ERROR "-- expecting GCC version ${gcc_host_req_ver}, but got version ${version} instead")
|
||||
endif()
|
|
@ -2,10 +2,14 @@
|
|||
|
||||
Supported are RealFlight 9.5S and RealFlight Evolution, NOT RealFlight-X.
|
||||
|
||||
RealFlight is very well suited to simulate the model flight specific aspects. Autolaunch and the mixers can be set in INAV.
|
||||
RealFlight is very well suited to simulate the model flight specific aspects. Autolaunch and the mixers can be used.
|
||||
However, since the sceneries do not correspond to a real environment, the GPS data must be "faked". The position is always shown somewhere in southern Nevada ;).
|
||||
GPS data and flight modes work fine though, only for missions with waypoints it is of course not ideal.
|
||||
|
||||
## Joystick
|
||||
In the settings, calibrate the joystick, set it up and assign the axes in the same order as in INAV.
|
||||
Channel 1 (Aileron) in RealFlight is Cannel 1 (Aileron in INAV) and so on.
|
||||
|
||||
## General settings
|
||||
Under Settings / Physics / Quality Switch on "RealFlight Link enabled".
|
||||
As a command line option for SITL, the port does not need to be specified, the port is fixed.
|
||||
|
@ -17,4 +21,4 @@ In the model editor under "Electronis" all mixers should be deleted and the serv
|
|||
In the "Radio" tab also deactivate Expo and low rates: "Activadd when: Never".
|
||||
Configure the model in the same way as a real model would be set up in INAV including Mixer, Expo, etc. depending on the selected model in RealFlight.
|
||||
|
||||
Then adjust the channelmap (see command line option) accordingly.
|
||||
Then adjust the channelmap im the Configurator or via command line accordingly.
|
|
@ -3,7 +3,7 @@
|
|||

|
||||
|
||||
## ATTENTION!
|
||||
SITL is currently still under development, its use is still a bit cumbersome.
|
||||
SITL is currently still under development.
|
||||
|
||||
SITL (Software in the loop) allows to run INAV completely in software on the PC without using a flight controller and simulate complete FPV flights.
|
||||
For this, INAV is compiled with a normal PC compiler.
|
||||
|
@ -13,46 +13,23 @@ Currently supported are
|
|||
- RealFlight https://www.realflight.com/
|
||||
- X-Plane https://www.x-plane.com/
|
||||
|
||||
INAV SITL communicates for sensor data and control directly with the corresponding simulator, see the documentation of the individual simulators and the command line options.
|
||||
|
||||
## Command line
|
||||
The following SITL specific command line options are available:
|
||||
|
||||
If SITL is started without command line options, only the Configurator can be used.
|
||||
|
||||
```--help``` Displays help for the command line options.
|
||||
|
||||
```--sim=[sim]``` Select the simulator. xp = X-Plane, rf = RealFlight. Example: ```--sim=xp```
|
||||
|
||||
```--simip=[ip]``` IP address of the simulator, if you specify a simulator with "--sim" and omit this option localhost (127.0.0.1) will be used. Example: ```--simip=172.65.21.15```
|
||||
|
||||
```--simport=[port]``` Port number of the simulator, not necessary for all simulators. Example: ```--simport=4900```
|
||||
|
||||
```--useimu``` Use IMU sensor data from the simulator instead of using attitude data directly from the simulator. Not recommended, use only for debugging.
|
||||
|
||||
```--chanmap=[chanmap]``` The channelmap to map the motor and servo outputs from INAV to the virtual receiver channel or control surfaces around simulator.
|
||||
Syntax: (M(otor)|S(ervo)<INAV-OUT>-<RECEIVER_OUT>),..., all numbers must have two digits.
|
||||
|
||||
Example:
|
||||
To assign motor1 to virtual receiver channel 1, servo 1 to channel 2, and servo2 to channel 3:
|
||||
```--chanmap:M01-01,S01-02,S02-03```
|
||||
Please also read the documentation of the individual simulators.
|
||||
INAV SITL communicates for sensor data and control directly with the corresponding simulator, see the documentation of the individual simulators and the Configurator or the command line options.
|
||||
|
||||
## Sensors
|
||||
The following sensors are emulated:
|
||||
- IMU (Gyro, Accelerometer)
|
||||
- GPS
|
||||
- Pitot
|
||||
- barometer
|
||||
- Magnetometer (Compass)
|
||||
- Rangefinder
|
||||
- Barometer
|
||||
- Battery (current and voltage), depending on simulator
|
||||
|
||||

|
||||
|
||||
Magnetometer (compass) is not yet supported, therefore no support for copters.
|
||||
|
||||
Select "FAKE" as type for all mentioned, so that they receive the data from the simulator.
|
||||
|
||||
## Serial ports
|
||||
## Serial ports+
|
||||
UARTs are replaced by TCP starting with port 5760 ascending. UART 1 port 5760, UART2 6761, ...
|
||||
By default, UART1 and UART2 are available as MSP connections.
|
||||
To connect the Configurator to SITL: Select TCP and connect to ```127.0.0.1:5760``` (if SITL is running on the same machine).
|
||||
|
@ -64,8 +41,17 @@ The assignment and status of user UART/TCP connections is displayed on the conso
|
|||
All other interfaces (I2C, SPI, etc.) are not emulated.
|
||||
|
||||
## Remote control
|
||||
At the moment only direct input via UART/TCP is supported.
|
||||
Joystick (via simulator) or serial receiver via USB/Serial interface are supported.
|
||||
|
||||
### Joystick interface
|
||||
Only 8 channels are supported.
|
||||
Select "SIM (SITL)" as the receiver and set up a joystick in the simulator, details of which can be found in the documentation for the individual simulators.
|
||||
|
||||
### Serial Receiver via USB
|
||||
Connect a serial receiver (e.g. SBUS) to the PC via a UART/USB adapter. Configure the receiver in the Configurator as usual.
|
||||
|
||||
The Configurator offers a built-in option for forwarding the serial data to the SITL TCP port, if SITL is started manually the following option can be used:
|
||||
|
||||
The connection can then be established with a programme that forwards the serial data unaltered to TCP, e.g. with the Python script tcp_serial_redirect.py (https://github.com/Scavanger/TCP-Serial-Redirect)
|
||||
If necessary, please download the required runtime environment from https://www.python.org/.
|
||||
Please use the linked version, which has a smaller buffer, otherwise the control response is relatively slow.
|
||||
|
@ -78,7 +64,7 @@ For this you need a FT232 module. With FT-Prog (https://ftdichip.com/utilities/)
|
|||
For SBUS, the command line arguments of the python script are:
|
||||
```python tcp_serial_redirect.py --parity E --stopbits 2 -c 127.0.0.1:[INAV-UART-PORT] COMXX 100000```
|
||||
|
||||
Note: Telemetry via return channel through the receiver is not supported by SITL.
|
||||
Note: Telemetry via return channel through the receiver is not supported by SITL (yet).
|
||||
|
||||
## OSD
|
||||
For the OSD the program INAV-Sim-OSD is available: https://github.com/Scavanger/INAV-SIM-OSD.
|
||||
|
@ -86,6 +72,33 @@ For this, activate MSP-Displayport on a UART/TCP port and connect to the corresp
|
|||
|
||||
Note: INAV-Sim-OSD only works if the simulator is in window mode.
|
||||
|
||||
## Command line
|
||||
The command line options are only necessary if the SITL executable is started by hand, e.g. when debugging.
|
||||
For normal use, please use the SITL tab in the configurator.
|
||||
|
||||
The following SITL specific command line options are available:
|
||||
|
||||
If SITL is started without command line options, only the Configurator can be used.
|
||||
|
||||
```--path``` Full path and file name to config file, if not present, eeprom.bin in the current directory is used. Example: ```C:\INAV_SITL\flying-wing.bin```
|
||||
|
||||
```--sim=[sim]``` Select the simulator. xp = X-Plane, rf = RealFlight. Example: ```--sim=xp```
|
||||
|
||||
```--simip=[ip]``` IP address of the simulator, if you specify a simulator with "--sim" and omit this option localhost (127.0.0.1) will be used. Example: ```--simip=172.65.21.15```
|
||||
|
||||
```--simport=[port]``` Port number of the simulator, not necessary for all simulators. Example: ```--simport=4900```
|
||||
|
||||
```--useimu``` Use IMU sensor data from the simulator instead of using attitude data directly from the simulator. Not recommended, use only for debugging.
|
||||
|
||||
```--chanmap=[chanmap]``` The channelmap to map the motor and servo outputs from INAV to the virtual receiver channel or control surfaces around simulator.
|
||||
Syntax: (M(otor)|S(ervo)<INAV-OUT>-<RECEIVER_OUT>),..., all numbers must have two digits.
|
||||
Example:
|
||||
To assign motor1 to virtual receiver channel 1, servo 1 to channel 2, and servo2 to channel 3:
|
||||
```--chanmap:M01-01,S01-02,S02-03```
|
||||
Please also read the documentation of the individual simulators.
|
||||
|
||||
```--help``` Displays help for the command line options.
|
||||
|
||||
## Running SITL
|
||||
It is recommended to start the tools in the following order:
|
||||
1. Simulator, aircraft should be ready for take-off
|
||||
|
@ -94,7 +107,6 @@ It is recommended to start the tools in the following order:
|
|||
4. serial redirect for RC input
|
||||
|
||||
## Compile
|
||||
GCC 10 is required, GCC 11 gives an error message (bug in GCC?!?).
|
||||
|
||||
### Linux:
|
||||
Almost like normal, ruby, cmake and make are also required.
|
||||
|
|
|
@ -2,14 +2,32 @@
|
|||
|
||||
Tested on X-Plane 11, 12 should(!) work but not tested.
|
||||
|
||||
X-Plane is not a model flight simulator, but is based on real world data and is therefore suitable
|
||||
GPS missions with waypoints.
|
||||
X-Plane is not a model flight simulator, but is based on real world data and is therefore suitable for GPS missions with waypoints.
|
||||
|
||||
## Aircraft
|
||||
It is recommended to use the "AR Wing" of the INAV HITL project: https://github.com/RomanLut/INAV-X-Plane-HITL
|
||||
|
||||
## General settings
|
||||
In Settings / Network select "Accept incoming connections".
|
||||
The port can be found under "UDP PORTS", "Port we receive on". If no connection is established, the port can be changed.
|
||||
You may want to incease the "Flight model per frame" value under "General"
|
||||
|
||||
## Joystick
|
||||
In the settings, calibrate the joystick, set it up and assign the axes as follows:
|
||||
|
||||
| INAV | X-Plane |
|
||||
|------|---------|
|
||||
| Roll | Roll |
|
||||
| Pitch | Pitch |
|
||||
| Throttle | Throttle |
|
||||
| Yaw | Yaw |
|
||||
| Channel 5 | Prop |
|
||||
| Channel 6 | Mixture |
|
||||
| Channel 7 | Collective |
|
||||
| Channel 8 | Thrust vector |
|
||||
|
||||
Reverse axis in X-Plane if necessary.
|
||||
|
||||
## Channelmap:
|
||||
The assignment of the "virtual receiver" is fixed:
|
||||
1 - Throttle
|
||||
|
@ -17,6 +35,6 @@ The assignment of the "virtual receiver" is fixed:
|
|||
3 - Pitch
|
||||
4 - Yaw
|
||||
|
||||
The internal mixer (e.g. for wings only) cannot be deactivated without further ado, therefore always select "Aircraft with tail" in INAV.
|
||||
The internal mixer (e.g. for flying wings) cannot be deactivated without further ado, therefore always select "Aircraft with tail" in INAV.
|
||||
For the standard Aircraft preset the channelmap is:
|
||||
```--chanmap=M01-01,S01-03,S03-02,S04-04```
|
||||
|
|
|
@ -406,6 +406,9 @@ main_sources(COMMON_SRC
|
|||
rx/srxl2.h
|
||||
rx/sumd.c
|
||||
rx/sumd.h
|
||||
rx/sim.c
|
||||
rx/sim.h
|
||||
|
||||
|
||||
scheduler/scheduler.c
|
||||
scheduler/scheduler.h
|
||||
|
@ -467,6 +470,7 @@ main_sources(COMMON_SRC
|
|||
io/rangefinder.h
|
||||
io/rangefinder_msp.c
|
||||
io/rangefinder_benewake.c
|
||||
io/rangefinder_fake.c
|
||||
io/opflow.h
|
||||
io/opflow_cxof.c
|
||||
io/opflow_msp.c
|
||||
|
|
|
@ -35,6 +35,10 @@
|
|||
|
||||
#include "fc/settings.h"
|
||||
|
||||
#ifdef SITL_BUILD
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
// For the "modulo 4" arithmetic to work, we need a leap base year
|
||||
#define REFERENCE_YEAR 2000
|
||||
// Offset (seconds) from the UNIX epoch (1970-01-01) to 2000-01-01
|
||||
|
@ -310,11 +314,16 @@ bool rtcHasTime(void)
|
|||
|
||||
bool rtcGet(rtcTime_t *t)
|
||||
{
|
||||
#ifdef SITL_BUILD
|
||||
*t = (rtcTime_t)(time(NULL) * 1000);
|
||||
return true;
|
||||
#else
|
||||
if (!rtcHasTime()) {
|
||||
return false;
|
||||
}
|
||||
*t = started + millis();
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool rtcSet(rtcTime_t *t)
|
||||
|
@ -323,6 +332,7 @@ bool rtcSet(rtcTime_t *t)
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool rtcGetDateTime(dateTime_t *dt)
|
||||
{
|
||||
rtcTime_t t;
|
||||
|
|
|
@ -57,3 +57,7 @@ int config_streamer_flush(config_streamer_t *c);
|
|||
|
||||
int config_streamer_finish(config_streamer_t *c);
|
||||
int config_streamer_status(config_streamer_t *c);
|
||||
|
||||
#if defined(CONFIG_IN_FILE)
|
||||
bool configFileSetPath(char* path);
|
||||
#endif
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include "platform.h"
|
||||
#include "drivers/system.h"
|
||||
#include "config/config_streamer.h"
|
||||
|
@ -26,21 +27,32 @@
|
|||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#define FLASH_PAGE_SIZE (0x400)
|
||||
|
||||
static FILE *eepromFd = NULL;
|
||||
|
||||
static bool streamerLocked = true;
|
||||
static char eepromPath[260] = EEPROM_FILENAME;
|
||||
|
||||
bool configFileSetPath(char* path)
|
||||
{
|
||||
if(!path || strlen(path) > 260) {
|
||||
return false;
|
||||
}
|
||||
|
||||
strcpy(eepromPath, path);
|
||||
return true;
|
||||
}
|
||||
|
||||
void config_streamer_impl_unlock(void)
|
||||
{
|
||||
if (eepromFd != NULL) {
|
||||
fprintf(stderr, "[EEPROM] Unable to load %s\n", EEPROM_FILENAME);
|
||||
fprintf(stderr, "[EEPROM] Unable to load %s\n", eepromPath);
|
||||
return;
|
||||
}
|
||||
|
||||
// open or create
|
||||
eepromFd = fopen(EEPROM_FILENAME,"r+");
|
||||
eepromFd = fopen(eepromPath,"r+");
|
||||
if (eepromFd != NULL) {
|
||||
// obtain file size:
|
||||
fseek(eepromFd , 0 , SEEK_END);
|
||||
|
@ -49,16 +61,16 @@ void config_streamer_impl_unlock(void)
|
|||
|
||||
size_t n = fread(eepromData, 1, sizeof(eepromData), eepromFd);
|
||||
if (n == size) {
|
||||
printf("[EEPROM] Loaded '%s' (%ld of %ld bytes)\n", EEPROM_FILENAME, size, sizeof(eepromData));
|
||||
fprintf(stderr,"[EEPROM] Loaded '%s' (%ld of %ld bytes)\n", eepromPath, size, sizeof(eepromData));
|
||||
streamerLocked = false;
|
||||
} else {
|
||||
fprintf(stderr, "[EEPROM] Failed to load '%s'\n", EEPROM_FILENAME);
|
||||
fprintf(stderr, "[EEPROM] Failed to load '%s'\n", eepromPath);
|
||||
}
|
||||
} else {
|
||||
printf("[EEPROM] Created '%s', size = %ld\n", EEPROM_FILENAME, sizeof(eepromData));
|
||||
printf("[EEPROM] Created '%s', size = %ld\n", eepromPath, sizeof(eepromData));
|
||||
streamerLocked = false;
|
||||
if ((eepromFd = fopen(EEPROM_FILENAME, "w+")) == NULL) {
|
||||
fprintf(stderr, "[EEPROM] Failed to create '%s'\n", EEPROM_FILENAME);
|
||||
if ((eepromFd = fopen(eepromPath, "w+")) == NULL) {
|
||||
fprintf(stderr, "[EEPROM] Failed to create '%s'\n", eepromPath);
|
||||
streamerLocked = true;
|
||||
}
|
||||
if (fwrite(eepromData, sizeof(eepromData), 1, eepromFd) != 1) {
|
||||
|
@ -66,8 +78,6 @@ void config_streamer_impl_unlock(void)
|
|||
streamerLocked = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void config_streamer_impl_lock(void)
|
||||
|
@ -78,7 +88,7 @@ void config_streamer_impl_lock(void)
|
|||
fwrite(eepromData, 1, sizeof(eepromData), eepromFd);
|
||||
fclose(eepromFd);
|
||||
eepromFd = NULL;
|
||||
printf("[EEPROM] Saved '%s'\n", EEPROM_FILENAME);
|
||||
fprintf(stderr, "[EEPROM] Saved '%s'\n", eepromPath);
|
||||
streamerLocked = false;
|
||||
} else {
|
||||
fprintf(stderr, "[EEPROM] Unlock error\n");
|
||||
|
@ -93,9 +103,9 @@ int config_streamer_impl_write_word(config_streamer_t *c, config_streamer_buffer
|
|||
|
||||
if ((c->address >= (uintptr_t)eepromData) && (c->address < (uintptr_t)ARRAYEND(eepromData))) {
|
||||
*((uint32_t*)c->address) = *buffer;
|
||||
printf("[EEPROM] Program word %p = %08x\n", (void*)c->address, *((uint32_t*)c->address));
|
||||
fprintf(stderr, "[EEPROM] Program word %p = %08x\n", (void*)c->address, *((uint32_t*)c->address));
|
||||
} else {
|
||||
printf("[EEPROM] Program word %p out of range!\n", (void*)c->address);
|
||||
fprintf(stderr, "[EEPROM] Program word %p out of range!\n", (void*)c->address);
|
||||
}
|
||||
|
||||
c->address += CONFIG_STREAMER_BUFFER_SIZE;
|
||||
|
|
|
@ -32,59 +32,25 @@
|
|||
|
||||
#ifdef USE_IMU_FAKE
|
||||
|
||||
#if defined(SITL_BUILD)
|
||||
|
||||
#define VOLATILE volatile
|
||||
|
||||
static pthread_mutex_t gyroMutex;
|
||||
static pthread_mutex_t accMutex;
|
||||
|
||||
#define LOCK(mutex) (pthread_mutex_lock(mutex))
|
||||
#define UNLOCK(mutex) (pthread_mutex_unlock(mutex))
|
||||
|
||||
#define GYROLOCK (pthread_mutex_lock(&gyroMutex))
|
||||
#define GYROUNLOCK (pthread_mutex_unlock(&gyroMutex))
|
||||
#define ACCLOCK (pthread_mutex_lock(&accMutex))
|
||||
#define ACCUNLOCK (pthread_mutex_unlock(&accMutex))
|
||||
|
||||
#else
|
||||
#define VOLATILE
|
||||
#define GYROLOCK
|
||||
#define GYROUNLOCK
|
||||
#define ACCLOCK
|
||||
#define ACCUNLOCK
|
||||
|
||||
#endif
|
||||
|
||||
static VOLATILE int16_t fakeGyroADC[XYZ_AXIS_COUNT];
|
||||
static int16_t fakeGyroADC[XYZ_AXIS_COUNT];
|
||||
|
||||
static void fakeGyroInit(gyroDev_t *gyro)
|
||||
{
|
||||
UNUSED(gyro);
|
||||
|
||||
#if defined(SITL_BUILD)
|
||||
pthread_mutex_init(&gyroMutex, NULL);
|
||||
#endif
|
||||
|
||||
//ENABLE_STATE(ACCELEROMETER_CALIBRATED);
|
||||
}
|
||||
|
||||
void fakeGyroSet(int16_t x, int16_t y, int16_t z)
|
||||
{
|
||||
GYROLOCK;
|
||||
fakeGyroADC[X] = x;
|
||||
fakeGyroADC[Y] = y;
|
||||
fakeGyroADC[Z] = z;
|
||||
GYROUNLOCK;
|
||||
}
|
||||
|
||||
static bool fakeGyroRead(gyroDev_t *gyro)
|
||||
{
|
||||
GYROLOCK;
|
||||
gyro->gyroADCRaw[X] = fakeGyroADC[X];
|
||||
gyro->gyroADCRaw[Y] = fakeGyroADC[Y];
|
||||
gyro->gyroADCRaw[Z] = fakeGyroADC[Z];
|
||||
GYROUNLOCK;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -112,33 +78,25 @@ bool fakeGyroDetect(gyroDev_t *gyro)
|
|||
return true;
|
||||
}
|
||||
|
||||
static VOLATILE int16_t fakeAccData[XYZ_AXIS_COUNT];
|
||||
static int16_t fakeAccData[XYZ_AXIS_COUNT];
|
||||
|
||||
static void fakeAccInit(accDev_t *acc)
|
||||
{
|
||||
#if defined(SITL_BUILD)
|
||||
pthread_mutex_init(&accMutex, NULL);
|
||||
#endif
|
||||
|
||||
acc->acc_1G = 9806;
|
||||
}
|
||||
|
||||
void fakeAccSet(int16_t x, int16_t y, int16_t z)
|
||||
{
|
||||
ACCLOCK;
|
||||
fakeAccData[X] = x;
|
||||
fakeAccData[Y] = y;
|
||||
fakeAccData[Z] = z;
|
||||
ACCUNLOCK;
|
||||
}
|
||||
|
||||
static bool fakeAccRead(accDev_t *acc)
|
||||
{
|
||||
ACCLOCK;
|
||||
acc->ADCRaw[X] = fakeAccData[X];
|
||||
acc->ADCRaw[Y] = fakeAccData[Y];
|
||||
acc->ADCRaw[Z] = fakeAccData[Z];
|
||||
ACCUNLOCK;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,18 +58,15 @@ static int32_t virtualRangefinderGetDistance(rangefinderDev_t * dev)
|
|||
return highLevelDeviceVTable->read();
|
||||
}
|
||||
|
||||
#define VIRTUAL_MAX_RANGE_CM 250
|
||||
#define VIRTUAL_DETECTION_CONE_DECIDEGREES 900
|
||||
|
||||
bool virtualRangefinderDetect(rangefinderDev_t * dev, const virtualRangefinderVTable_t * vtable)
|
||||
{
|
||||
if (vtable && vtable->detect()) {
|
||||
highLevelDeviceVTable = vtable;
|
||||
|
||||
dev->delayMs = RANGEFINDER_VIRTUAL_TASK_PERIOD_MS;
|
||||
dev->maxRangeCm = VIRTUAL_MAX_RANGE_CM;
|
||||
dev->detectionConeDeciDegrees = VIRTUAL_DETECTION_CONE_DECIDEGREES;
|
||||
dev->detectionConeExtendedDeciDegrees = VIRTUAL_DETECTION_CONE_DECIDEGREES;
|
||||
dev->maxRangeCm = RANGEFINDER_VIRTUAL_MAX_RANGE_CM;
|
||||
dev->detectionConeDeciDegrees = RANGEFINDER_VIRTUAL_DETECTION_CONE_DECIDEGREES;
|
||||
dev->detectionConeExtendedDeciDegrees = RANGEFINDER_VIRTUAL_DETECTION_CONE_DECIDEGREES;
|
||||
|
||||
dev->init = &virtualRangefinderInit;
|
||||
dev->update = &virtualRangefinderUpdate;
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
|
||||
#include "drivers/rangefinder/rangefinder.h"
|
||||
|
||||
#define RANGEFINDER_VIRTUAL_MAX_RANGE_CM 250
|
||||
#define RANGEFINDER_VIRTUAL_DETECTION_CONE_DECIDEGREES 900
|
||||
#define RANGEFINDER_VIRTUAL_TASK_PERIOD_MS 30
|
||||
|
||||
typedef struct virtualRangefinderVTable_s {
|
||||
|
|
|
@ -3417,7 +3417,11 @@ static void cliStatus(char *cmdline)
|
|||
cliPrint("OSD: ");
|
||||
#if defined(USE_OSD)
|
||||
displayPort_t *osdDisplayPort = osdGetDisplayPort();
|
||||
cliPrintf("%s [%u x %u]", osdDisplayPort->displayPortType, osdDisplayPort->cols, osdDisplayPort->rows);
|
||||
if (osdDisplayPort) {
|
||||
cliPrintf("%s [%u x %u]", osdDisplayPort->displayPortType, osdDisplayPort->cols, osdDisplayPort->rows);
|
||||
} else {
|
||||
cliPrintf("no OSD detected");
|
||||
}
|
||||
#else
|
||||
cliPrint("not used");
|
||||
#endif
|
||||
|
|
|
@ -161,11 +161,22 @@ bool areSensorsCalibrating(void)
|
|||
|
||||
int16_t getAxisRcCommand(int16_t rawData, int16_t rate, int16_t deadband)
|
||||
{
|
||||
int16_t stickDeflection;
|
||||
int16_t stickDeflection = 0;
|
||||
|
||||
stickDeflection = constrain(rawData - PWM_RANGE_MIDDLE, -500, 500);
|
||||
#if defined(SITL_BUILD) // Workaround due to strange bug in GCC > 10.2 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108914
|
||||
const int16_t value = rawData - PWM_RANGE_MIDDLE;
|
||||
if (value < -500) {
|
||||
stickDeflection = -500;
|
||||
} else if (value > 500) {
|
||||
stickDeflection = 500;
|
||||
} else {
|
||||
stickDeflection = value;
|
||||
}
|
||||
#else
|
||||
stickDeflection = constrain(rawData - PWM_RANGE_MIDDLE, -500, 500);
|
||||
#endif
|
||||
|
||||
stickDeflection = applyDeadbandRescaled(stickDeflection, deadband, -500, 500);
|
||||
|
||||
return rcLookup(stickDeflection, rate);
|
||||
}
|
||||
|
||||
|
|
|
@ -46,11 +46,7 @@
|
|||
#include "drivers/compass/compass_msp.h"
|
||||
#include "drivers/barometer/barometer_msp.h"
|
||||
#include "drivers/pitotmeter/pitotmeter_msp.h"
|
||||
#include "drivers/accgyro/accgyro_fake.h"
|
||||
#include "drivers/barometer/barometer_fake.h"
|
||||
#include "drivers/compass/compass_fake.h"
|
||||
#include "sensors/battery_sensor_fake.h"
|
||||
#include "drivers/pitotmeter/pitotmeter_fake.h"
|
||||
#include "drivers/bus_i2c.h"
|
||||
#include "drivers/display.h"
|
||||
#include "drivers/flash.h"
|
||||
|
|
|
@ -7,7 +7,7 @@ tables:
|
|||
values: ["NONE", "AUTO", "MPU6000", "MPU6500", "MPU9250", "BMI160", "ICM20689", "BMI088", "ICM42605", "BMI270", "FAKE"]
|
||||
enum: accelerationSensor_e
|
||||
- name: rangefinder_hardware
|
||||
values: ["NONE", "SRF10", "VL53L0X", "MSP", "BENEWAKE", "VL53L1X", "US42", "TOF10120_I2C"]
|
||||
values: ["NONE", "SRF10", "VL53L0X", "MSP", "BENEWAKE", "VL53L1X", "US42", "TOF10120_I2C", "FAKE"]
|
||||
enum: rangefinderType_e
|
||||
- name: mag_hardware
|
||||
values: ["NONE", "AUTO", "HMC5883", "AK8975", "MAG3110", "AK8963", "IST8310", "QMC5883", "MPU9250", "IST8308", "LIS3MDL", "MSP", "RM3100", "VCM5883", "MLX90393", "FAKE"]
|
||||
|
@ -22,7 +22,7 @@ tables:
|
|||
values: ["NONE", "AUTO", "MS4525", "ADC", "VIRTUAL", "FAKE", "MSP"]
|
||||
enum: pitotSensor_e
|
||||
- name: receiver_type
|
||||
values: ["NONE", "SERIAL", "MSP"]
|
||||
values: ["NONE", "SERIAL", "MSP", "SIM (SITL)"]
|
||||
enum: rxReceiverType_e
|
||||
- name: serial_rx
|
||||
values: ["SPEK1024", "SPEK2048", "SBUS", "SUMD", "IBUS", "JETIEXBUS", "CRSF", "FPORT", "SBUS_FAST", "FPORT2", "SRXL2", "GHST", "MAVLINK"]
|
||||
|
|
|
@ -31,5 +31,7 @@
|
|||
|
||||
extern virtualRangefinderVTable_t rangefinderMSPVtable;
|
||||
extern virtualRangefinderVTable_t rangefinderBenewakeVtable;
|
||||
extern virtualRangefinderVTable_t rangefinderFakeVtable;
|
||||
|
||||
void mspRangefinderReceiveNewData(uint8_t * bufferPtr);
|
||||
void mspRangefinderReceiveNewData(uint8_t * bufferPtr);
|
||||
void fakeRangefindersSetData(int32_t data);
|
86
src/main/io/rangefinder_fake.c
Normal file
86
src/main/io/rangefinder_fake.c
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* This file is part of INAV Project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms
|
||||
* of the GNU General Public License Version 3, as described below:
|
||||
*
|
||||
* This file is free software: you may copy, redistribute and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#include "build/build_config.h"
|
||||
#include "build/debug.h"
|
||||
|
||||
#include "common/maths.h"
|
||||
|
||||
#include "io/serial.h"
|
||||
|
||||
#if defined(USE_RANGEFINDER_FAKE)
|
||||
#include "drivers/rangefinder/rangefinder_virtual.h"
|
||||
#include "drivers/time.h"
|
||||
#include "io/rangefinder.h"
|
||||
|
||||
static bool hasNewData = false;
|
||||
static int32_t sensorData = RANGEFINDER_NO_NEW_DATA;
|
||||
|
||||
static bool fakeRangefinderDetect(void)
|
||||
{
|
||||
// Always detectable
|
||||
return true;
|
||||
}
|
||||
|
||||
static void fakeRangefinderInit(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void fakeRangefinderUpdate(void)
|
||||
{
|
||||
}
|
||||
|
||||
static int32_t fakeRangefinderGetDistance(void)
|
||||
{
|
||||
if (hasNewData) {
|
||||
hasNewData = false;
|
||||
return (sensorData > 0) ? sensorData : RANGEFINDER_OUT_OF_RANGE;
|
||||
}
|
||||
else {
|
||||
return RANGEFINDER_NO_NEW_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
void fakeRangefindersSetData(int32_t data)
|
||||
{
|
||||
sensorData = data;
|
||||
hasNewData = true;
|
||||
}
|
||||
|
||||
virtualRangefinderVTable_t rangefinderFakeVtable = {
|
||||
.detect = fakeRangefinderDetect,
|
||||
.init = fakeRangefinderInit,
|
||||
.update = fakeRangefinderUpdate,
|
||||
.read = fakeRangefinderGetDistance
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -241,7 +241,7 @@ void onNewGPSData(void)
|
|||
|
||||
/* Use VELNED provided by GPS if available, calculate from coordinates otherwise */
|
||||
float gpsScaleLonDown = constrainf(cos_approx((ABS(gpsSol.llh.lat) / 10000000.0f) * 0.0174532925f), 0.01f, 1.0f);
|
||||
if (positionEstimationConfig()->use_gps_velned && gpsSol.flags.validVelNE) {
|
||||
if (!ARMING_FLAG(SIMULATOR_MODE_SITL) && positionEstimationConfig()->use_gps_velned && gpsSol.flags.validVelNE) {
|
||||
posEstimator.gps.vel.x = gpsSol.velNED[X];
|
||||
posEstimator.gps.vel.y = gpsSol.velNED[Y];
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
#include "rx/sumd.h"
|
||||
#include "rx/ghst.h"
|
||||
#include "rx/mavlink.h"
|
||||
#include "rx/sim.h"
|
||||
|
||||
const char rcChannelLetters[] = "AERT";
|
||||
|
||||
|
@ -310,6 +311,12 @@ void rxInit(void)
|
|||
break;
|
||||
#endif
|
||||
|
||||
#ifdef USE_RX_SIM
|
||||
case RX_TYPE_SIM:
|
||||
rxSimInit(rxConfig(), &rxRuntimeConfig);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
case RX_TYPE_NONE:
|
||||
rxConfigMutable()->receiverType = RX_TYPE_NONE;
|
||||
|
|
|
@ -62,7 +62,8 @@ typedef enum {
|
|||
typedef enum {
|
||||
RX_TYPE_NONE = 0,
|
||||
RX_TYPE_SERIAL,
|
||||
RX_TYPE_MSP
|
||||
RX_TYPE_MSP,
|
||||
RX_TYPE_SIM
|
||||
} rxReceiverType_e;
|
||||
|
||||
typedef enum {
|
||||
|
|
71
src/main/rx/sim.c
Normal file
71
src/main/rx/sim.c
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* This file is part of Cleanflight.
|
||||
*
|
||||
* Cleanflight is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cleanflight is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#ifdef USE_RX_SIM
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#include "common/utils.h"
|
||||
|
||||
#include "rx/rx.h"
|
||||
#include "rx/sim.h"
|
||||
|
||||
static uint16_t channels[MAX_SUPPORTED_RC_CHANNEL_COUNT];
|
||||
static bool hasNewData = false;
|
||||
|
||||
static uint16_t rxSimReadRawRC(const rxRuntimeConfig_t *rxRuntimeConfigPtr, uint8_t chan)
|
||||
{
|
||||
UNUSED(rxRuntimeConfigPtr);
|
||||
return channels[chan];
|
||||
}
|
||||
|
||||
void rxSimSetChannelValue(uint16_t* values, uint8_t count)
|
||||
{
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
channels[i] = values[i];
|
||||
}
|
||||
|
||||
hasNewData = true;
|
||||
}
|
||||
|
||||
static uint8_t rxSimFrameStatus(rxRuntimeConfig_t *rxRuntimeConfig)
|
||||
{
|
||||
UNUSED(rxRuntimeConfig);
|
||||
|
||||
if (!hasNewData) {
|
||||
return RX_FRAME_PENDING;
|
||||
}
|
||||
|
||||
hasNewData = false;
|
||||
return RX_FRAME_COMPLETE;
|
||||
}
|
||||
|
||||
void rxSimInit(const rxConfig_t *rxConfig, rxRuntimeConfig_t *rxRuntimeConfig)
|
||||
{
|
||||
UNUSED(rxConfig);
|
||||
|
||||
rxRuntimeConfig->channelCount = MAX_SUPPORTED_RC_CHANNEL_COUNT;
|
||||
rxRuntimeConfig->rxSignalTimeout = DELAY_5_HZ;
|
||||
rxRuntimeConfig->rcReadRawFn = rxSimReadRawRC;
|
||||
rxRuntimeConfig->rcFrameStatusFn = rxSimFrameStatus;
|
||||
}
|
||||
#endif
|
23
src/main/rx/sim.h
Normal file
23
src/main/rx/sim.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* This file is part of INAV.
|
||||
*
|
||||
* Cleanflight is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cleanflight is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "rx/rx.h"
|
||||
|
||||
void rxSimSetChannelValue(uint16_t* values, uint8_t count);
|
||||
void rxSimInit(const rxConfig_t *rxConfig, rxRuntimeConfig_t *rxRuntimeConfig);
|
|
@ -520,11 +520,6 @@ void accUpdate(void)
|
|||
|
||||
if (!ARMING_FLAG(SIMULATOR_MODE_SITL)) {
|
||||
performAcclerationCalibration();
|
||||
|
||||
applyAccelerationZero(&accelerometerConfig()->accZero, &accelerometerConfig()->accGain);
|
||||
applyAccelerationZero(&accelerometerConfig()->accZero, &accelerometerConfig()->accGain);
|
||||
applyAccelerationZero(&accelerometerConfig()->accZero, &accelerometerConfig()->accGain);
|
||||
applyAccelerationZero(&accelerometerConfig()->accZero, &accelerometerConfig()->accGain);
|
||||
applyAccelerationZero(&accelerometerConfig()->accZero, &accelerometerConfig()->accGain);
|
||||
}
|
||||
|
||||
|
|
|
@ -141,7 +141,14 @@ static bool rangefinderDetect(rangefinderDev_t * dev, uint8_t rangefinderHardwar
|
|||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case RANGEFINDER_FAKE:
|
||||
#if defined(USE_RANGEFINDER_FAKE)
|
||||
if(virtualRangefinderDetect(dev, &rangefinderFakeVtable)) {
|
||||
rangefinderHardware = RANGEFINDER_FAKE;
|
||||
rescheduleTask(TASK_RANGEFINDER, TASK_PERIOD_MS(RANGEFINDER_VIRTUAL_TASK_PERIOD_MS));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case RANGEFINDER_NONE:
|
||||
rangefinderHardware = RANGEFINDER_NONE;
|
||||
break;
|
||||
|
|
|
@ -30,6 +30,7 @@ typedef enum {
|
|||
RANGEFINDER_VL53L1X = 5,
|
||||
RANGEFINDER_US42 = 6,
|
||||
RANGEFINDER_TOF10102I2C = 7,
|
||||
RANGEFINDER_FAKE = 8,
|
||||
} rangefinderType_e;
|
||||
|
||||
typedef struct rangefinderConfig_s {
|
||||
|
|
|
@ -45,14 +45,19 @@
|
|||
#include "sensors/acceleration.h"
|
||||
#include "sensors/barometer.h"
|
||||
#include "drivers/pitotmeter/pitotmeter_fake.h"
|
||||
#include "drivers/compass/compass_fake.h"
|
||||
#include "drivers/rangefinder/rangefinder_virtual.h"
|
||||
#include "io/rangefinder.h"
|
||||
#include "common/utils.h"
|
||||
#include "common/maths.h"
|
||||
#include "flight/mixer.h"
|
||||
#include "flight/servos.h"
|
||||
#include "flight/imu.h"
|
||||
#include "io/gps.h"
|
||||
#include "rx/sim.h"
|
||||
|
||||
#define RF_PORT 18083
|
||||
#define RF_MAX_CHANNEL_COUNT 12
|
||||
// RealFlight scenerys doesn't represent real landscapes, so fake some nice coords: Area 51 ;)
|
||||
#define FAKE_LAT 37.277127f
|
||||
#define FAKE_LON -115.799669f
|
||||
|
@ -212,6 +217,33 @@ static char* getStringFromResponse(const char* response, const char* elementName
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool getChannelValues(const char* response, uint16_t* channelValues)
|
||||
{
|
||||
if (!response) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* channelValueTag = "<m-channelValues-0to1 xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:double[12]\">";
|
||||
char* pos = strstr(response, channelValueTag);
|
||||
if (!pos){
|
||||
return false;
|
||||
}
|
||||
|
||||
pos += strlen(channelValueTag);
|
||||
for (size_t i = 0; i < RF_MAX_CHANNEL_COUNT; i++) {
|
||||
char* end = strstr(pos, "</");
|
||||
if (!end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
channelValues[i] = FLOAT_0_1_TO_PWM((float)atof(pos + 6));
|
||||
pos = end + 7;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void fakeCoords(double posX, double posY, double distanceX, double distanceY, double *lat, double *lon)
|
||||
{
|
||||
double m = 1 / (2 * (double)M_PIf / 360 * EARTH_RADIUS) / 1000;
|
||||
|
@ -224,7 +256,6 @@ static double convertAzimuth(double azimuth)
|
|||
if (azimuth < 0) {
|
||||
azimuth += 360;
|
||||
}
|
||||
|
||||
return 360 - fmod(azimuth + 90, 360.0f);
|
||||
}
|
||||
|
||||
|
@ -246,8 +277,8 @@ static void exchangeData(void)
|
|||
//rfValues.m_currentPhysicsTime_SEC = getDoubleFromResponse(response, "m-currentPhysicsTime-SEC");
|
||||
//rfValues.m_currentPhysicsSpeedMultiplier = getDoubleFromResponse(response, "m-currentPhysicsSpeedMultiplier");
|
||||
rfValues.m_airspeed_MPS = getDoubleFromResponse(response, "m-airspeed-MPS");
|
||||
rfValues.m_altitudeASL_MTR = getDoubleFromResponse(response, "<m-altitudeASL-MTR");
|
||||
//rfValues.m_altitudeAGL_MTR = getDoubleFromResponse(response, "<m-altitudeAGL-MTR");
|
||||
rfValues.m_altitudeASL_MTR = getDoubleFromResponse(response, "m-altitudeASL-MTR");
|
||||
rfValues.m_altitudeAGL_MTR = getDoubleFromResponse(response, "m-altitudeAGL-MTR");
|
||||
rfValues.m_groundspeed_MPS = getDoubleFromResponse(response, "m-groundspeed-MPS");
|
||||
rfValues.m_pitchRate_DEGpSEC = getDoubleFromResponse(response, "m-pitchRate-DEGpSEC");
|
||||
rfValues.m_rollRate_DEGpSEC = getDoubleFromResponse(response, "m-rollRate-DEGpSEC");
|
||||
|
@ -289,6 +320,11 @@ static void exchangeData(void)
|
|||
//rfValues.m_flightAxisControllerIsActive= getBoolFromResponse(response, "m-flightAxisControllerIsActive");
|
||||
rfValues.m_currentAircraftStatus = getStringFromResponse(response, "m-currentAircraftStatus");
|
||||
|
||||
|
||||
uint16_t channelValues[RF_MAX_CHANNEL_COUNT];
|
||||
getChannelValues(response, channelValues);
|
||||
rxSimSetChannelValue(channelValues, RF_MAX_CHANNEL_COUNT);
|
||||
|
||||
double lat, lon;
|
||||
fakeCoords(FAKE_LAT, FAKE_LON, rfValues.m_aircraftPositionX_MTR, -rfValues.m_aircraftPositionY_MTR, &lat, &lon);
|
||||
|
||||
|
@ -308,12 +344,18 @@ static void exchangeData(void)
|
|||
0
|
||||
);
|
||||
|
||||
int32_t altitudeOverGround = (int32_t)round(rfValues.m_altitudeAGL_MTR * 100);
|
||||
if (altitudeOverGround > 0 && altitudeOverGround <= RANGEFINDER_VIRTUAL_MAX_RANGE_CM) {
|
||||
fakeRangefindersSetData(altitudeOverGround);
|
||||
} else {
|
||||
fakeRangefindersSetData(-1);
|
||||
}
|
||||
|
||||
const int16_t roll_inav = (int16_t)round(rfValues.m_roll_DEG * 10);
|
||||
const int16_t pitch_inav = (int16_t)round(-rfValues.m_inclination_DEG * 10);
|
||||
const int16_t yaw_inav = course;
|
||||
if (!useImu) {
|
||||
imuSetAttitudeRPY(
|
||||
(int16_t)round(rfValues.m_roll_DEG * 10),
|
||||
(int16_t)round(-rfValues.m_inclination_DEG * 10),
|
||||
course
|
||||
);
|
||||
imuSetAttitudeRPY(roll_inav, pitch_inav, yaw_inav);
|
||||
imuUpdateAttitude(micros());
|
||||
}
|
||||
|
||||
|
@ -326,26 +368,38 @@ static void exchangeData(void)
|
|||
accY = 0;
|
||||
accZ = (int16_t)(GRAVITY_MSS * 1000.0f);
|
||||
} else {
|
||||
accX = clampToInt16(rfValues.m_accelerationBodyAX_MPS2 * 1000);
|
||||
accY = clampToInt16(-rfValues.m_accelerationBodyAY_MPS2 * 1000);
|
||||
accZ = clampToInt16(-rfValues.m_accelerationBodyAZ_MPS2 * 1000);
|
||||
accX = constrainToInt16(rfValues.m_accelerationBodyAX_MPS2 * 1000);
|
||||
accY = constrainToInt16(-rfValues.m_accelerationBodyAY_MPS2 * 1000);
|
||||
accZ = constrainToInt16(-rfValues.m_accelerationBodyAZ_MPS2 * 1000);
|
||||
}
|
||||
|
||||
fakeAccSet(accX, accY, accZ);
|
||||
|
||||
fakeGyroSet(
|
||||
clampToInt16(rfValues.m_rollRate_DEGpSEC * (double)16.0),
|
||||
clampToInt16(-rfValues.m_pitchRate_DEGpSEC * (double)16.0),
|
||||
clampToInt16(rfValues.m_yawRate_DEGpSEC * (double)16.0)
|
||||
constrainToInt16(rfValues.m_rollRate_DEGpSEC * (double)16.0),
|
||||
constrainToInt16(-rfValues.m_pitchRate_DEGpSEC * (double)16.0),
|
||||
constrainToInt16(rfValues.m_yawRate_DEGpSEC * (double)16.0)
|
||||
);
|
||||
|
||||
fakeBaroSet(altitudeToPressure(altitude), DEGREES_TO_CENTIDEGREES(21));
|
||||
fakePitotSetAirspeed(rfValues.m_airspeed_MPS * 100);
|
||||
|
||||
// TODO fakeMag
|
||||
|
||||
fakeBattSensorSetVbat((uint16_t)round(rfValues.m_batteryVoltage_VOLTS * 100));
|
||||
fakeBattSensorSetAmperage((uint16_t)round(rfValues.m_batteryCurrentDraw_AMPS * 100));
|
||||
fakeBattSensorSetAmperage((uint16_t)round(rfValues.m_batteryCurrentDraw_AMPS * 100));
|
||||
|
||||
fpQuaternion_t quat;
|
||||
fpVector3_t north;
|
||||
north.x = 1.0f;
|
||||
north.y = 0;
|
||||
north.z = 0;
|
||||
computeQuaternionFromRPY(&quat, roll_inav, pitch_inav, yaw_inav);
|
||||
transformVectorEarthToBody(&north, &quat);
|
||||
fakeMagSet(
|
||||
constrainToInt16(north.x * 16000.0f),
|
||||
constrainToInt16(north.y * 16000.0f),
|
||||
constrainToInt16(north.z * 16000.0f)
|
||||
);
|
||||
ENABLE_STATE(COMPASS_CALIBRATED);
|
||||
}
|
||||
|
||||
static void* soapWorker(void* arg)
|
||||
|
@ -357,14 +411,14 @@ static void* soapWorker(void* arg)
|
|||
startRequest("RestoreOriginalControllerDevice", "<RestoreOriginalControllerDevice><a>1</a><b>2</b></RestoreOriginalControllerDevice>");
|
||||
endRequest();
|
||||
startRequest("InjectUAVControllerInterface", "<InjectUAVControllerInterface><a>1</a><b>2</b></InjectUAVControllerInterface>");
|
||||
endRequest();
|
||||
|
||||
endRequest();
|
||||
exchangeData();
|
||||
ENABLE_ARMING_FLAG(SIMULATOR_MODE_SITL);
|
||||
|
||||
isInitalised = true;
|
||||
}
|
||||
exchangeData();
|
||||
|
||||
exchangeData();
|
||||
unlockMainPID();
|
||||
}
|
||||
|
||||
|
@ -414,7 +468,7 @@ bool simRealFlightInit(char* ip, uint8_t* mapping, uint8_t mapCount, bool imu)
|
|||
// Wait until the connection is established, the interface has been initialised
|
||||
// and the first valid packet has been received to avoid problems with the startup calibration.
|
||||
while (!isInitalised) {
|
||||
// ...
|
||||
delay(250);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -26,22 +26,42 @@
|
|||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "common/quaternion.h"
|
||||
|
||||
#include "target/SITL/sim/simHelper.h"
|
||||
|
||||
inline double clampd(double value, double min, double max)
|
||||
inline int16_t constrainToInt16(double value)
|
||||
{
|
||||
if (value < min) {
|
||||
value = min;
|
||||
}
|
||||
|
||||
if (value > max) {
|
||||
value = max;
|
||||
}
|
||||
|
||||
return value;
|
||||
return (int16_t)round(constrain(value, INT16_MIN, INT16_MAX));
|
||||
}
|
||||
|
||||
inline int16_t clampToInt16(double value)
|
||||
// Move to quaternion.h ?
|
||||
void computeQuaternionFromRPY(fpQuaternion_t *quat, int16_t initialRoll, int16_t initialPitch, int16_t initialYaw)
|
||||
{
|
||||
return (int16_t)round(clampd(value, INT16_MIN, INT16_MAX));
|
||||
if (initialRoll > 1800) initialRoll -= 3600;
|
||||
if (initialPitch > 1800) initialPitch -= 3600;
|
||||
if (initialYaw > 1800) initialYaw -= 3600;
|
||||
|
||||
const float cosRoll = cos_approx(DECIDEGREES_TO_RADIANS(initialRoll) * 0.5f);
|
||||
const float sinRoll = sin_approx(DECIDEGREES_TO_RADIANS(initialRoll) * 0.5f);
|
||||
|
||||
const float cosPitch = cos_approx(DECIDEGREES_TO_RADIANS(initialPitch) * 0.5f);
|
||||
const float sinPitch = sin_approx(DECIDEGREES_TO_RADIANS(initialPitch) * 0.5f);
|
||||
|
||||
const float cosYaw = cos_approx(DECIDEGREES_TO_RADIANS(-initialYaw) * 0.5f);
|
||||
const float sinYaw = sin_approx(DECIDEGREES_TO_RADIANS(-initialYaw) * 0.5f);
|
||||
|
||||
quat->q0 = cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw;
|
||||
quat->q1 = sinRoll * cosPitch * cosYaw - cosRoll * sinPitch * sinYaw;
|
||||
quat->q2 = cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw;
|
||||
quat->q3 = cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw;
|
||||
}
|
||||
|
||||
void transformVectorEarthToBody(fpVector3_t *v, const fpQuaternion_t *quat)
|
||||
{
|
||||
// HACK: This is needed to correctly transform from NED (sensor frame) to NEU (navigation)
|
||||
v->y = -v->y;
|
||||
|
||||
// From earth frame to body frame
|
||||
quaternionRotateVector(v, v, quat);
|
||||
}
|
||||
|
|
|
@ -23,11 +23,15 @@
|
|||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "common/maths.h"
|
||||
#include "common/quaternion.h"
|
||||
|
||||
#define EARTH_RADIUS ((double)6378.137)
|
||||
#define DEG2RAD(deg) (deg * (double)M_PIf / (double)180.0)
|
||||
#define PWM_TO_FLOAT_0_1(x) (((int)x - 1000) / 1000.0f)
|
||||
#define PWM_TO_FLOAT_MINUS_1_1(x) (((int)x - 1500) / 500.0f)
|
||||
#define FLOAT_0_1_TO_PWM(x) ((uint16_t)(x * 1000.0f) + 1000.0f)
|
||||
#define FLOAT_MINUS_1_1_TO_PWM(x) ((uint16_t)((x + 1.0f) / 2.0f * 1000.0f) + 1000.0f)
|
||||
|
||||
double clampd(double value, double min, double max);
|
||||
int16_t clampToInt16(double value);
|
||||
int16_t constrainToInt16(double value);
|
||||
void transformVectorEarthToBody(fpVector3_t *v, const fpQuaternion_t *quat);
|
||||
void computeQuaternionFromRPY(fpQuaternion_t *quat, int16_t initialRoll, int16_t initialPitch, int16_t initialYaw);
|
|
@ -47,7 +47,7 @@ bool soapClientConnect(soap_client_t *client, const char *address, int port)
|
|||
}
|
||||
|
||||
int one = 1;
|
||||
if (setsockopt(client->sockedFd, SOL_SOCKET, SO_REUSEADDR, &one,sizeof(one)) < 0) {
|
||||
if (setsockopt(client->sockedFd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -69,6 +69,8 @@ void soapClientClose(soap_client_t *client)
|
|||
{
|
||||
close(client->sockedFd);
|
||||
memset(client, 0, sizeof(soap_client_t));
|
||||
client->isConnected = false;
|
||||
client->isInitalised = false;
|
||||
}
|
||||
|
||||
void soapClientSendRequestVa(soap_client_t *client, const char* action, const char *fmt, va_list va)
|
||||
|
@ -78,11 +80,15 @@ void soapClientSendRequestVa(soap_client_t *client, const char* action, const ch
|
|||
}
|
||||
|
||||
char* requestBody;
|
||||
vasprintf(&requestBody, fmt, va);
|
||||
|
||||
if (vasprintf(&requestBody, fmt, va) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
char* request;
|
||||
asprintf(&request, "POST / HTTP/1.1\r\nsoapaction: %s\r\ncontent-length: %u\r\ncontent-type: text/xml;charset='UTF-8'\r\nConnection: Keep-Alive\r\n\r\n<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body>%s</soap:Body></soap:Envelope>",
|
||||
action, (unsigned)strlen(requestBody), requestBody);
|
||||
if (asprintf(&request, "POST / HTTP/1.1\r\nsoapaction: %s\r\ncontent-length: %u\r\ncontent-type: text/xml;charset='UTF-8'\r\nConnection: Keep-Alive\r\n\r\n<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body>%s</soap:Body></soap:Envelope>",
|
||||
action, (unsigned)strlen(requestBody), requestBody) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
send(client->sockedFd, request, strlen(request), 0);
|
||||
}
|
||||
|
|
|
@ -45,14 +45,19 @@
|
|||
#include "sensors/battery_sensor_fake.h"
|
||||
#include "sensors/acceleration.h"
|
||||
#include "drivers/pitotmeter/pitotmeter_fake.h"
|
||||
#include "drivers/compass/compass_fake.h"
|
||||
#include "drivers/rangefinder/rangefinder_virtual.h"
|
||||
#include "io/rangefinder.h"
|
||||
#include "common/utils.h"
|
||||
#include "common/maths.h"
|
||||
#include "flight/mixer.h"
|
||||
#include "flight/servos.h"
|
||||
#include "flight/imu.h"
|
||||
#include "io/gps.h"
|
||||
#include "rx/sim.h"
|
||||
|
||||
#define XP_PORT 49000
|
||||
#define XPLANE_JOYSTICK_AXIS_COUNT 8
|
||||
|
||||
|
||||
static uint8_t pwmMapping[XP_MAX_PWM_OUTS];
|
||||
|
@ -67,6 +72,7 @@ static bool useImu = false;
|
|||
static float lattitude = 0;
|
||||
static float longitude = 0;
|
||||
static float elevation = 0;
|
||||
static float agl = 0;
|
||||
static float local_vx = 0;
|
||||
static float local_vy = 0;
|
||||
static float local_vz = 0;
|
||||
|
@ -83,13 +89,27 @@ static float gyro_x = 0;
|
|||
static float gyro_y = 0;
|
||||
static float gyro_z = 0;
|
||||
static float barometer = 0;
|
||||
static bool hasJoystick = false;
|
||||
static float joystickRaw[XPLANE_JOYSTICK_AXIS_COUNT];
|
||||
|
||||
enum
|
||||
{
|
||||
RF_ASSIGNMENT_PITCH,
|
||||
RF_ASSIGNMENT_ROLL,
|
||||
RF_ASSIGNMENT_YAW,
|
||||
RF_ASSIGNMENT_THROTLE,
|
||||
RF_ASSIGNMENT_PROP,
|
||||
RF_ASSIGNMENT_MIXTURE,
|
||||
RF_ASSIGNMENT_COLLECTIVE,
|
||||
RF_ASSIGNMENT_THRUST_VECTOR
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DREF_LATITUDE,
|
||||
DREF_LONGITUDE,
|
||||
DREF_ELEVATION,
|
||||
DREF_AGL,
|
||||
DREF_LOCAL_VX,
|
||||
DREF_LOCAL_VY,
|
||||
DREF_LOCAL_VZ,
|
||||
|
@ -106,7 +126,16 @@ typedef enum
|
|||
DREF_POS_Q,
|
||||
DREF_POS_R,
|
||||
DREF_POS_BARO_CURRENT_INHG,
|
||||
DREF_COUNT
|
||||
DREF_COUNT,
|
||||
DREF_HAS_JOYSTICK,
|
||||
DREF_JOYSTICK_VALUES_ROll,
|
||||
DREF_JOYSTICK_VALUES_PITCH,
|
||||
DREF_JOYSTICK_VALUES_THROTTLE,
|
||||
DREF_JOYSTICK_VALUES_YAW,
|
||||
DREF_JOYSTICK_VALUES_PROP,
|
||||
DREF_JOYSTICK_VALUES_MIXTURE,
|
||||
DREF_JOYSTICK_VALUES_COLLECTIVE,
|
||||
DREF_JOYSTICK_VALUES_THRUST_VECTOR,
|
||||
} dref_t;
|
||||
|
||||
uint32_t xint2uint32 (uint8_t * buf)
|
||||
|
@ -168,7 +197,7 @@ static void* listenWorker(void* arg)
|
|||
if (y > 2) {
|
||||
break;
|
||||
}
|
||||
if (pwmMapping[i] & 0x80) { // Motor)
|
||||
if (pwmMapping[i] & 0x80) { // Motor
|
||||
motorValue = PWM_TO_FLOAT_0_1(motor[pwmMapping[i] & 0x7f]);
|
||||
} else {
|
||||
yokeValues[y] = PWM_TO_FLOAT_MINUS_1_1(servo[pwmMapping[i]]);
|
||||
|
@ -184,11 +213,11 @@ static void* listenWorker(void* arg)
|
|||
|
||||
recvLen = recvfrom(sockFd, buf, sizeof(buf), 0, (struct sockaddr*)&remoteAddr, &slen);
|
||||
if (recvLen < 0 && errno != EWOULDBLOCK) {
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp((char*)buf, "RREF", 4) != 0) {
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 5; i < recvLen; i += 8) {
|
||||
|
@ -208,6 +237,10 @@ static void* listenWorker(void* arg)
|
|||
case DREF_ELEVATION:
|
||||
elevation = value;
|
||||
break;
|
||||
|
||||
case DREF_AGL:
|
||||
agl = value;
|
||||
break;
|
||||
|
||||
case DREF_LOCAL_VX:
|
||||
local_vx = value;
|
||||
|
@ -273,10 +306,45 @@ static void* listenWorker(void* arg)
|
|||
barometer = value;
|
||||
break;
|
||||
|
||||
case DREF_HAS_JOYSTICK:
|
||||
hasJoystick = value >= 1 ? true : false;
|
||||
break;
|
||||
|
||||
case DREF_JOYSTICK_VALUES_ROll:
|
||||
joystickRaw[0] = value;
|
||||
break;
|
||||
|
||||
case DREF_JOYSTICK_VALUES_PITCH:
|
||||
joystickRaw[1] = value;
|
||||
break;
|
||||
|
||||
case DREF_JOYSTICK_VALUES_THROTTLE:
|
||||
joystickRaw[2] = value;
|
||||
break;
|
||||
|
||||
case DREF_JOYSTICK_VALUES_YAW:
|
||||
joystickRaw[3] = value;
|
||||
break;
|
||||
|
||||
case DREF_JOYSTICK_VALUES_PROP:
|
||||
joystickRaw[4] = value;
|
||||
break;
|
||||
|
||||
case DREF_JOYSTICK_VALUES_MIXTURE:
|
||||
joystickRaw[5] = value;
|
||||
break;
|
||||
|
||||
case DREF_JOYSTICK_VALUES_COLLECTIVE:
|
||||
joystickRaw[6] = value;
|
||||
break;
|
||||
|
||||
case DREF_JOYSTICK_VALUES_THRUST_VECTOR:
|
||||
joystickRaw[7] = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (hpath < 0) {
|
||||
|
@ -287,6 +355,20 @@ static void* listenWorker(void* arg)
|
|||
yaw += 3600;
|
||||
}
|
||||
|
||||
if (hasJoystick) {
|
||||
uint16_t channelValues[XPLANE_JOYSTICK_AXIS_COUNT];
|
||||
channelValues[0] = FLOAT_MINUS_1_1_TO_PWM(joystickRaw[RF_ASSIGNMENT_ROLL]);
|
||||
channelValues[1] = FLOAT_MINUS_1_1_TO_PWM(joystickRaw[RF_ASSIGNMENT_PITCH]);
|
||||
channelValues[2] = FLOAT_0_1_TO_PWM(joystickRaw[RF_ASSIGNMENT_THROTLE]);
|
||||
channelValues[3] = FLOAT_MINUS_1_1_TO_PWM(joystickRaw[RF_ASSIGNMENT_YAW]);
|
||||
channelValues[4] = FLOAT_0_1_TO_PWM(joystickRaw[RF_ASSIGNMENT_PROP]);
|
||||
channelValues[5] = FLOAT_0_1_TO_PWM(joystickRaw[RF_ASSIGNMENT_MIXTURE]);
|
||||
channelValues[6] = FLOAT_0_1_TO_PWM(joystickRaw[RF_ASSIGNMENT_COLLECTIVE]);
|
||||
channelValues[7] = FLOAT_0_1_TO_PWM(joystickRaw[RF_ASSIGNMENT_THRUST_VECTOR]);
|
||||
|
||||
rxSimSetChannelValue(channelValues, XPLANE_JOYSTICK_AXIS_COUNT);
|
||||
}
|
||||
|
||||
gpsFakeSet(
|
||||
GPS_FIX_3D,
|
||||
16,
|
||||
|
@ -300,26 +382,33 @@ static void* listenWorker(void* arg)
|
|||
0, //(int16_t)round(-local_vy * 100),
|
||||
0
|
||||
);
|
||||
|
||||
const int32_t altitideOverGround = (int32_t)round(agl * 100);
|
||||
if (altitideOverGround > 0 && altitideOverGround <= RANGEFINDER_VIRTUAL_MAX_RANGE_CM) {
|
||||
fakeRangefindersSetData(altitideOverGround);
|
||||
} else {
|
||||
fakeRangefindersSetData(-1);
|
||||
}
|
||||
|
||||
const int16_t roll_inav = roll * 10;
|
||||
const int16_t pitch_inav = -pitch * 10;
|
||||
const int16_t yaw_inav = yaw * 10;
|
||||
|
||||
if (!useImu) {
|
||||
imuSetAttitudeRPY(
|
||||
(int16_t)round(roll * 10),
|
||||
(int16_t)round(-pitch * 10),
|
||||
(int16_t)round(yaw * 10)
|
||||
);
|
||||
imuSetAttitudeRPY(roll_inav, pitch_inav, yaw_inav);
|
||||
imuUpdateAttitude(micros());
|
||||
}
|
||||
|
||||
fakeAccSet(
|
||||
clampToInt16(-accel_x * GRAVITY_MSS * 1000),
|
||||
clampToInt16(accel_y * GRAVITY_MSS * 1000),
|
||||
clampToInt16(accel_z * GRAVITY_MSS * 1000)
|
||||
constrainToInt16(-accel_x * GRAVITY_MSS * 1000),
|
||||
constrainToInt16(accel_y * GRAVITY_MSS * 1000),
|
||||
constrainToInt16(accel_z * GRAVITY_MSS * 1000)
|
||||
);
|
||||
|
||||
fakeGyroSet(
|
||||
clampToInt16(gyro_x * 16.0f),
|
||||
clampToInt16(-gyro_y * 16.0f),
|
||||
clampToInt16(-gyro_z * 16.0f)
|
||||
constrainToInt16(gyro_x * 16.0f),
|
||||
constrainToInt16(-gyro_y * 16.0f),
|
||||
constrainToInt16(-gyro_z * 16.0f)
|
||||
);
|
||||
|
||||
fakeBaroSet((int32_t)round(barometer * 3386.39f), DEGREES_TO_CENTIDEGREES(21));
|
||||
|
@ -327,8 +416,24 @@ static void* listenWorker(void* arg)
|
|||
|
||||
fakeBattSensorSetVbat(16.8 * 100);
|
||||
|
||||
fpQuaternion_t quat;
|
||||
fpVector3_t north;
|
||||
north.x = 1.0f;
|
||||
north.y = 0;
|
||||
north.z = 0;
|
||||
computeQuaternionFromRPY(&quat, roll_inav, pitch_inav, yaw_inav);
|
||||
transformVectorEarthToBody(&north, &quat);
|
||||
fakeMagSet(
|
||||
constrainToInt16(north.x * 16000.0f),
|
||||
constrainToInt16(north.y * 16000.0f),
|
||||
constrainToInt16(north.z * 16000.0f)
|
||||
);
|
||||
ENABLE_STATE(COMPASS_CALIBRATED);
|
||||
|
||||
if (!initalized) {
|
||||
ENABLE_ARMING_FLAG(SIMULATOR_MODE_SITL);
|
||||
ENABLE_ARMING_FLAG(SIMULATOR_MODE_SITL);
|
||||
// Aircraft can wobble on the runway and prevents calibration of the accelerometer
|
||||
ENABLE_STATE(ACCELEROMETER_CALIBRATED);
|
||||
initalized = true;
|
||||
}
|
||||
|
||||
|
@ -362,42 +467,52 @@ bool simXPlaneInit(char* ip, int port, uint8_t* mapping, uint8_t mapCount, bool
|
|||
return false;
|
||||
}
|
||||
|
||||
if (bind(sockFd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
||||
if (setsockopt(sockFd, SOL_SOCKET, SO_SNDTIMEO, (struct timeval *) &tv,sizeof(struct timeval))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bind(sockFd, (struct sockaddr *) &addr, sizeof(addr));
|
||||
|
||||
serverAddr.sin_family = AF_INET;
|
||||
serverAddr.sin_addr.s_addr = inet_addr(ip);
|
||||
serverAddr.sin_port = htons(port);
|
||||
|
||||
registerDref(DREF_LATITUDE, "sim/flightmodel/position/latitude", 100);
|
||||
registerDref(DREF_LONGITUDE, "sim/flightmodel/position/longitude", 100);
|
||||
registerDref(DREF_ELEVATION, "sim/flightmodel/position/elevation", 100);
|
||||
registerDref(DREF_LOCAL_VX, "sim/flightmodel/position/local_vx", 100);
|
||||
registerDref(DREF_LOCAL_VY, "sim/flightmodel/position/local_vy", 100);
|
||||
registerDref(DREF_LOCAL_VZ, "sim/flightmodel/position/local_vz", 100);
|
||||
registerDref(DREF_GROUNDSPEED, "sim/flightmodel/position/groundspeed", 100);
|
||||
registerDref(DREF_TRUE_AIRSPEED, "sim/flightmodel/position/true_airspeed", 100);
|
||||
registerDref(DREF_POS_PHI, "sim/flightmodel/position/phi", 100);
|
||||
registerDref(DREF_POS_THETA, "sim/flightmodel/position/theta", 100);
|
||||
registerDref(DREF_POS_PSI, "sim/flightmodel/position/psi", 100);
|
||||
registerDref(DREF_POS_HPATH, "sim/flightmodel/position/hpath", 100);
|
||||
registerDref(DREF_FORCE_G_AXI1, "sim/flightmodel/forces/g_axil", 100);
|
||||
registerDref(DREF_FORCE_G_SIDE, "sim/flightmodel/forces/g_side", 100);
|
||||
registerDref(DREF_FORCE_G_NRML, "sim/flightmodel/forces/g_nrml", 100);
|
||||
registerDref(DREF_POS_P, "sim/flightmodel/position/P", 100);
|
||||
registerDref(DREF_POS_Q, "sim/flightmodel/position/Q", 100);
|
||||
registerDref(DREF_POS_R, "sim/flightmodel/position/R", 100);
|
||||
registerDref(DREF_POS_BARO_CURRENT_INHG, "sim/weather/barometer_current_inhg", 100);
|
||||
|
||||
|
||||
if (pthread_create(&listenThread, NULL, listenWorker, NULL) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while(!initalized) {
|
||||
//
|
||||
while (!initalized) {
|
||||
registerDref(DREF_LATITUDE, "sim/flightmodel/position/latitude", 100);
|
||||
registerDref(DREF_LONGITUDE, "sim/flightmodel/position/longitude", 100);
|
||||
registerDref(DREF_ELEVATION, "sim/flightmodel/position/elevation", 100);
|
||||
registerDref(DREF_AGL, "sim/flightmodel/position/y_agl", 100);
|
||||
registerDref(DREF_LOCAL_VX, "sim/flightmodel/position/local_vx", 100);
|
||||
registerDref(DREF_LOCAL_VY, "sim/flightmodel/position/local_vy", 100);
|
||||
registerDref(DREF_LOCAL_VZ, "sim/flightmodel/position/local_vz", 100);
|
||||
registerDref(DREF_GROUNDSPEED, "sim/flightmodel/position/groundspeed", 100);
|
||||
registerDref(DREF_TRUE_AIRSPEED, "sim/flightmodel/position/true_airspeed", 100);
|
||||
registerDref(DREF_POS_PHI, "sim/flightmodel/position/phi", 100);
|
||||
registerDref(DREF_POS_THETA, "sim/flightmodel/position/theta", 100);
|
||||
registerDref(DREF_POS_PSI, "sim/flightmodel/position/psi", 100);
|
||||
registerDref(DREF_POS_HPATH, "sim/flightmodel/position/hpath", 100);
|
||||
registerDref(DREF_FORCE_G_AXI1, "sim/flightmodel/forces/g_axil", 100);
|
||||
registerDref(DREF_FORCE_G_SIDE, "sim/flightmodel/forces/g_side", 100);
|
||||
registerDref(DREF_FORCE_G_NRML, "sim/flightmodel/forces/g_nrml", 100);
|
||||
registerDref(DREF_POS_P, "sim/flightmodel/position/P", 100);
|
||||
registerDref(DREF_POS_Q, "sim/flightmodel/position/Q", 100);
|
||||
registerDref(DREF_POS_R, "sim/flightmodel/position/R", 100);
|
||||
registerDref(DREF_POS_BARO_CURRENT_INHG, "sim/weather/barometer_current_inhg", 100);
|
||||
registerDref(DREF_HAS_JOYSTICK, "sim/joystick/has_joystick", 100);
|
||||
registerDref(DREF_JOYSTICK_VALUES_ROll, "sim/joystick/joy_mapped_axis_value[1]", 100);
|
||||
registerDref(DREF_JOYSTICK_VALUES_PITCH, "sim/joystick/joy_mapped_axis_value[2]", 100);
|
||||
registerDref(DREF_JOYSTICK_VALUES_THROTTLE, "sim/joystick/joy_mapped_axis_value[3]", 100);
|
||||
registerDref(DREF_JOYSTICK_VALUES_YAW, "sim/joystick/joy_mapped_axis_value[4]", 100);
|
||||
registerDref(DREF_JOYSTICK_VALUES_PROP, "sim/joystick/joy_mapped_axis_value[8]", 100);
|
||||
registerDref(DREF_JOYSTICK_VALUES_MIXTURE, "sim/joystick/joy_mapped_axis_value[9]", 100);
|
||||
registerDref(DREF_JOYSTICK_VALUES_COLLECTIVE, "sim/joystick/joy_mapped_axis_value[5]", 100);
|
||||
registerDref(DREF_JOYSTICK_VALUES_THRUST_VECTOR, "sim/joystick/joy_mapped_axis_value[12]", 100);
|
||||
delay(250);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
|
@ -33,6 +33,7 @@
|
|||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <platform.h>
|
||||
#include "target.h"
|
||||
|
@ -44,6 +45,7 @@
|
|||
#include "drivers/pwm_mapping.h"
|
||||
#include "drivers/timer.h"
|
||||
#include "drivers/serial.h"
|
||||
#include "config/config_streamer.h"
|
||||
|
||||
#include "target/SITL/sim/realFlight.h"
|
||||
#include "target/SITL/sim/xplane.h"
|
||||
|
@ -66,46 +68,55 @@ static int simPort = 0;
|
|||
|
||||
void systemInit(void) {
|
||||
|
||||
printf("INAV %d.%d.%d SITL\n", FC_VERSION_MAJOR, FC_VERSION_MINOR, FC_VERSION_PATCH_LEVEL);
|
||||
fprintf(stderr, "INAV %d.%d.%d SITL\n", FC_VERSION_MAJOR, FC_VERSION_MINOR, FC_VERSION_PATCH_LEVEL);
|
||||
clock_gettime(CLOCK_MONOTONIC, &start_time);
|
||||
printf("[SYSTEM] Init...\n");
|
||||
fprintf(stderr, "[SYSTEM] Init...\n");
|
||||
|
||||
pthread_attr_t thAttr;
|
||||
int policy = 0;
|
||||
|
||||
pthread_attr_init(&thAttr);
|
||||
pthread_attr_getschedpolicy(&thAttr, &policy);
|
||||
|
||||
pthread_setschedprio(pthread_self(), sched_get_priority_min(policy));
|
||||
pthread_attr_destroy(&thAttr);
|
||||
|
||||
if (pthread_mutex_init(&mainLoopLock, NULL) != 0) {
|
||||
printf("[SYSTEM] Unable to create mainLoop lock.\n");
|
||||
fprintf(stderr, "[SYSTEM] Unable to create mainLoop lock.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (sitlSim != SITL_SIM_NONE) {
|
||||
printf("[SIM] Waiting for connection...\n");
|
||||
fprintf(stderr, "[SIM] Waiting for connection...\n");
|
||||
}
|
||||
|
||||
switch (sitlSim) {
|
||||
case SITL_SIM_REALFLIGHT:
|
||||
if (mappingCount > RF_MAX_PWM_OUTS) {
|
||||
printf("[SIM] Mapping error. RealFligt supports a maximum of %i PWM outputs.", RF_MAX_PWM_OUTS);
|
||||
fprintf(stderr, "[SIM] Mapping error. RealFligt supports a maximum of %i PWM outputs.", RF_MAX_PWM_OUTS);
|
||||
sitlSim = SITL_SIM_NONE;
|
||||
break;
|
||||
}
|
||||
if (simRealFlightInit(simIp, pwmMapping, mappingCount, useImu)) {
|
||||
printf("[SIM] Connection with RealFlight (%s) successfully established. \n", simIp);
|
||||
fprintf(stderr, "[SIM] Connection with RealFlight successfully established.\n");
|
||||
} else {
|
||||
printf("[SIM] Connection with RealFlight (%s) NOT established. \n", simIp);
|
||||
fprintf(stderr, "[SIM] Connection with RealFlight NOT established.\n");
|
||||
}
|
||||
break;
|
||||
case SITL_SIM_XPLANE:
|
||||
if (mappingCount > XP_MAX_PWM_OUTS) {
|
||||
printf("[SIM] Mapping error. RealFligt supports a maximum of %i PWM outputs.", XP_MAX_PWM_OUTS);
|
||||
fprintf(stderr, "[SIM] Mapping error. RealFligt supports a maximum of %i PWM outputs.", XP_MAX_PWM_OUTS);
|
||||
sitlSim = SITL_SIM_NONE;
|
||||
break;
|
||||
}
|
||||
if (simXPlaneInit(simIp, simPort, pwmMapping, mappingCount, useImu)) {
|
||||
printf("[SIM] Connection with XPlane successfully established. \n");
|
||||
fprintf(stderr, "[SIM] Connection with X-Plane successfully established.\n");
|
||||
} else {
|
||||
printf("[SIM] Connection with XPLane NOT established. \n");
|
||||
fprintf(stderr, "[SIM] Connection with X-PLane NOT established.\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("[SIM] No interface specified. Configurator only.\n");
|
||||
fprintf(stderr, "[SIM] No interface specified. Configurator only.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -149,21 +160,22 @@ bool parseMapping(char* mapStr)
|
|||
|
||||
void printCmdLineOptions(void)
|
||||
{
|
||||
printf("Avaiable options:\n");
|
||||
printf("--sim=[rf|xp] Simulator interface: rf = RealFligt, xp = XPlane. Example: --sim=rf\n");
|
||||
printf("--simip=[ip] IP-Address oft the simulator host. If not specified localhost (127.0.0.1) is used.");
|
||||
printf("--simport=[port] Port oft the simulator host.");
|
||||
printf("--useimu Use IMU sensor data from the simulator instead of using attitude data from the simulator directly (experimental, not recommended).");
|
||||
printf("--chanmap=[mapstring] Channel mapping, Maps INAVs motor and servo PWM outputs to the virtual receiver output in the simulator.\n");
|
||||
printf(" The mapstring has the following format: M(otor)|S(servo)<INAV-OUT>-<RECEIVER_OUT>,)... All numbers must have two digits\n");
|
||||
printf(" For example map motor 1 to virtal receiver output 1, servo 1 to output 2 and servo 2 to output 3:\n");
|
||||
printf(" --chanmap=M01-01,S01-02,S02-03\n");
|
||||
fprintf(stderr, "Avaiable options:\n");
|
||||
fprintf(stderr, "--path=[path] Path and filename of eeprom.bin. If not specified 'eeprom.bin' in program directory is used.\n");
|
||||
fprintf(stderr, "--sim=[rf|xp] Simulator interface: rf = RealFligt, xp = XPlane. Example: --sim=rf\n");
|
||||
fprintf(stderr, "--simip=[ip] IP-Address oft the simulator host. If not specified localhost (127.0.0.1) is used.\n");
|
||||
fprintf(stderr, "--simport=[port] Port oft the simulator host.\n");
|
||||
fprintf(stderr, "--useimu Use IMU sensor data from the simulator instead of using attitude data from the simulator directly (experimental, not recommended).\n");
|
||||
fprintf(stderr, "--chanmap=[mapstring] Channel mapping. Maps INAVs motor and servo PWM outputs to the virtual receiver output in the simulator.\n");
|
||||
fprintf(stderr, " The mapstring has the following format: M(otor)|S(servo)<INAV-OUT>-<RECEIVER-OUT>,... All numbers must have two digits\n");
|
||||
fprintf(stderr, " For example: Map motor 1 to virtal receiver output 1, servo 1 to output 2 and servo 2 to output 3:\n");
|
||||
fprintf(stderr, " --chanmap=M01-01,S01-02,S02-03\n");
|
||||
}
|
||||
|
||||
void parseArguments(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
while(1) {
|
||||
while(true) {
|
||||
static struct option longOpt[] = {
|
||||
{"sim", optional_argument, 0, 's'},
|
||||
{"useimu", optional_argument, 0, 'u'},
|
||||
|
@ -171,6 +183,7 @@ void parseArguments(int argc, char *argv[])
|
|||
{"simip", optional_argument, 0, 'i'},
|
||||
{"simport", optional_argument, 0, 'p'},
|
||||
{"help", optional_argument, 0, 'h'},
|
||||
{"path", optional_argument, 0, 'e'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
|
@ -185,13 +198,13 @@ void parseArguments(int argc, char *argv[])
|
|||
} else if (strcmp(optarg, "xp") == 0){
|
||||
sitlSim = SITL_SIM_XPLANE;
|
||||
} else {
|
||||
printf("[SIM] Unsupported simulator %s.\n", optarg);
|
||||
fprintf(stderr, "[SIM] Unsupported simulator %s.\n", optarg);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
if (!parseMapping(optarg) && sitlSim != SITL_SIM_NONE) {
|
||||
printf("[SIM] Invalid channel mapping string.\n");
|
||||
fprintf(stderr, "[SIM] Invalid channel mapping string.\n");
|
||||
printCmdLineOptions();
|
||||
exit(0);
|
||||
}
|
||||
|
@ -205,7 +218,11 @@ void parseArguments(int argc, char *argv[])
|
|||
case 'i':
|
||||
simIp = optarg;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
if (!configFileSetPath(optarg)){
|
||||
fprintf(stderr, "[EEPROM] Invalid path, using eeprom file in program directory\n.");
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
printCmdLineOptions();
|
||||
exit(0);
|
||||
|
@ -230,17 +247,6 @@ void unlockMainPID(void)
|
|||
}
|
||||
|
||||
// Replacements for system functions
|
||||
void microsleep(uint32_t usec) {
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = usec*1000UL;
|
||||
while (nanosleep(&ts, &ts) == -1 && errno == EINTR) ;
|
||||
}
|
||||
|
||||
void delayMicroseconds_real(uint32_t us) {
|
||||
microsleep(us);
|
||||
}
|
||||
|
||||
timeUs_t micros(void) {
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
@ -259,31 +265,31 @@ uint32_t millis(void) {
|
|||
|
||||
void delayMicroseconds(timeUs_t us)
|
||||
{
|
||||
timeUs_t now = micros();
|
||||
while (micros() - now < us);
|
||||
usleep(us);
|
||||
}
|
||||
|
||||
void delay(timeMs_t ms)
|
||||
{
|
||||
while (ms--)
|
||||
delayMicroseconds(1000);
|
||||
delayMicroseconds(ms * 1000UL);
|
||||
}
|
||||
|
||||
void systemReset(void)
|
||||
{
|
||||
printf("[SYSTEM] Reset\n");
|
||||
fprintf(stderr, "[SYSTEM] Reset\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void systemResetToBootloader(void)
|
||||
{
|
||||
printf("[SYSTEM] Reset to bootloader\n");
|
||||
fprintf(stderr, "[SYSTEM] Reset to bootloader\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void failureMode(failureMode_e mode) {
|
||||
printf("[SYSTEM] Failure mode %d\n", mode);
|
||||
while (1);
|
||||
fprintf(stderr, "[SYSTEM] Failure mode %d\n", mode);
|
||||
while (true) {
|
||||
delay(1000);
|
||||
};
|
||||
}
|
||||
|
||||
// Even more dummys and stubs
|
||||
|
|
|
@ -65,6 +65,8 @@
|
|||
#define USE_FAKE_BARO
|
||||
#define USE_FAKE_MAG
|
||||
#define USE_GPS_FAKE
|
||||
#define USE_RANGEFINDER_FAKE
|
||||
#define USE_RX_SIM
|
||||
|
||||
#undef USE_DASHBOARD
|
||||
#undef USE_TELEMETRY_LTM
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue