Gas Kanal wird nicht an die Regler weitergegeben

Jörn

Erfahrener Benutzer
#1
Hallo Zusammen,

nach zwei Abenden Recherche muss ich jetzt doch mal einen Thread eröffnen. Ich habe mir aus alten Teilen einen Y6 gebaut und habe nun das Problem, dass der Gas Kanal nicht an die Regler weitergegeben wird. Folgende Konfig:

- Flip32/Naze32
- Cleanflight 2.0.5 (letzte Version die auf einem F3-Chip einen Y6 unterstützt, kann also nicht einfach auf aktuelle Software wechseln)

Folgendes Verhalten:
- FC lässt sich per Schalter Armen, Motoren gehen in Idle-Drehzahl (1070)
- Drehzahl bleibt auf Idle, egal welche Stickposition Throttle hat
- In der FC kann ich per Motortest (Schieberegler) die Motoren auf volle Drehzahl bringen

Was alles überprüft wurde:
- Kanalzuordnung ist richtig (fliege überall RETA1234)
- In der FC ist der volle Knüppelausschlag des Senders zu sehen (glaube 995 - 2015)
- Min/Max Werte passen, Kopter armt ja auch mit Idle Drehzahl
- Kalibrierung der Lagesensoren erfolgreich
- Default Konfig auf der FC geladen
- gleiches Verhalten ob er an USB hängt oder nicht

Es sieht für mich so aus, als ob es einen mir unbekannten Sicherheitsschalter gibt, der den GAS-Kanal nicht an die Regler weiterreicht. So ist zu mindestens das Verhalten. Das ist übrigens bestimmt der zwanzigste Kopter den ich bisher gebaut habe. Bin also kein Anfänger mehr :) Jetzt seit ihr dran. Ideen???

Gruß
Jörn
 

Jörn

Erfahrener Benutzer
#2
Das Problem konnte mittlerweile selber analysiert und behoben werden. Entgegen der Release Notes sind die Mixer für den Y6 NICHT mehr in der Version 2.0.5 enthalten. Eine selber kompilierte Firmware in der die Mixer aktiviert wurden funktioniert. Es ist ja unwahrscheinlich das jemand dieses Problem nochmal haben wird, aber bei Bedarf kann ich die Firmware gerne weitergeben.
 
Erhaltene "Gefällt mir": vantaro

kritzelkratzel

Erfahrener Benutzer
#3
Ich muss gestehen, es ist echt eine Ewigkeit her, dass ich hier etwas geschrieben habe. Aber aus dem aktuellen Anlass denke ich mir, dass es sich lohnt den Lösungsweg zu skizzieren, weil dieser Ablauf für jede Art von Firmware-Hacking, sei es nun für Cleanflight oder Betaflight oder auch die passenden Konfiguratoren, der Gleiche ist.

TL;DR
  1. Cleanflight Code holen,
  2. Passende Stellen finden und modifizieren,
  3. Neue Firmware übersetzen und fertig.

1. Cleanflight Code holen
Als erstes holt man sich den Code-Basis von Cleanflight. Ich arbeite hier auf einem Mac, daher sind die relevanten Shell-Befehle alle schon vorhanden, wie auch bei Linux. Unter Windows ist es etwas komplizierter, aber diese Details erspare ich mir hier für die Demonstration.
Bash:
michael@MacBookAir foo % git clone https://github.com/cleanflight/cleanflight.git
Cloning into 'cleanflight'...
remote: Enumerating objects: 158780, done.
remote: Counting objects: 100% (319/319), done.
remote: Compressing objects: 100% (212/212), done.
remote: Total 158780 (delta 140), reused 219 (delta 97), pack-reused 158461
Receiving objects: 100% (158780/158780), 354.01 MiB | 5.16 MiB/s, done.
Resolving deltas: 100% (110341/110341), done.
Updating files: 100% (4487/4487), done.
michael@MacBookAir foo %
Danach gehen wir in der Code-Basis auf die Version 2.0.5 zurück, das ist die Version, die Jörn haben wollte. Der Code bekommt alle Jubeljahre ein Tag, mit dem die passender Version definiert wurde. Man kann auf die Github-Seite von Cleanflight gehen, um herauszufinden, wie diese Tags heißen. Es gibt auch separate git-Befehle dazu. In diesem Fall heißt das Tag CLFL_v2.0.5. Also:
Bash:
michael@MacBookAir foo % cd cleanflight
michael@MacBookAir cleanflight % git checkout CLFL_v2.0.5       
Updating files: 100% (6158/6158), done.
Note: switching to 'CLFL_v2.0.5'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 060a9e4d5 CF/BF - SPRACINGF4NEO stabilise ADC readings.
michael@MacBookAir cleanflight %
Die Warnungen, dass wir uns im detached HEAD state befinden, können wir ignorieren. Es geht hier nur um einen schnellen Fix des Problems.

2. Passende Stellen finden
Jetzt wird es kniffelig. Wonach soll man suchen? Der Hinweis von Jörn war, dass er seine Y6-Konfiguration nicht zum Laufen bekommen hat. Also durchsuchen wir die gesamte Code-Basis nach diesem Suchbegriff.
Bash:
michael@MacBookAir cleanflight % cd src/main
michael@MacBookAir main % search.sh Y6   
Diese Dateien enthalten den Ausdruck:  Y6

./flight/mixer.h
./fc/cli.c
./flight/mixer.c
./flight/servos.c
./telemetry/mavlink.c

Ende der Liste.
michael@MacBookAir main %
Der Begriff Y6 taucht also an nur wenigen Stellen in der Code-Basis auf. Das ist gut. Zu dem verwendeten Befehl search.sh schreibe ich später separat. In flight/mixer.h finden wir unter anderem:
C:
typedef enum mixerMode
{
    MIXER_TRI = 1,
    MIXER_QUADP = 2,
    MIXER_QUADX = 3,
    MIXER_BICOPTER = 4,
    MIXER_GIMBAL = 5,
    MIXER_Y6 = 6,
    MIXER_HEX6 = 7,
Das ist nur ein Enumerator für die gesamte Liste an Mixern in der Firmware, also nicht wirklich etwas überraschendes. Ähnlich verhält es sich mit fc/cli.c:
C:
#ifndef USE_QUAD_MIXER_ONLY
// sync this with mixerMode_e
static const char * const mixerNames[] = {
    "TRI", "QUADP", "QUADX", "BI",
    "GIMBAL", "Y6", "HEX6",
    "FLYING_WING", "Y4", "HEX6X", "OCTOX8", "OCTOFLATP", "OCTOFLATX",
    "AIRPLANE", "HE
    LI_120_CCPM", "HELI_90_DEG", "VTAIL4",
    "HEX6H", "PPM_TO_SERVO", "DUALCOPTER", "SINGLECOPTER",
    "ATAIL4", "CUSTOM", "CUSTOMAIRPLANE", "CUSTOMTRI", "QUADX1234", NULL
};
#endif
Auch kein Treffer. Anders verhält es sich mit flight/mixer.c:
C:
#if defined(USE_UNCOMMON_MIXERS)
static const motorMixer_t mixerHex6H[] = {
    { 1.0f, -1.0f,  1.0f, -1.0f },     // REAR_R
    { 1.0f, -1.0f, -1.0f,  1.0f },     // FRONT_R
    { 1.0f,  1.0f,  1.0f,  1.0f },     // REAR_L
    { 1.0f,  1.0f, -1.0f, -1.0f },     // FRONT_L
    { 1.0f,  0.0f,  0.0f,  0.0f },     // RIGHT
    { 1.0f,  0.0f,  0.0f,  0.0f },     // LEFT
};

static const motorMixer_t mixerHex6P[] = {
    { 1.0f, -0.866025f,  0.5f,  1.0f },     // REAR_R
    { 1.0f, -0.866025f, -0.5f, -1.0f },     // FRONT_R
    { 1.0f,  0.866025f,  0.5f,  1.0f },     // REAR_L
    { 1.0f,  0.866025f, -0.5f, -1.0f },     // FRONT_L
    { 1.0f,  0.0f,      -1.0f,  1.0f },     // FRONT
    { 1.0f,  0.0f,       1.0f, -1.0f },     // REAR
};
static const motorMixer_t mixerY6[] = {
    { 1.0f,  0.0f,  1.333333f,  1.0f },     // REAR
    { 1.0f, -1.0f, -0.666667f, -1.0f },     // RIGHT
    { 1.0f,  1.0f, -0.666667f, -1.0f },     // LEFT
    { 1.0f,  0.0f,  1.333333f, -1.0f },     // UNDER_REAR
    { 1.0f, -1.0f, -0.666667f,  1.0f },     // UNDER_RIGHT
    { 1.0f,  1.0f, -0.666667f,  1.0f },     // UNDER_LEFT
};
#else
#define mixerHex6H NULL
#define mixerHex6P NULL
#define mixerY6 NULL
#endif // USE_UNCOMMON_MIXERS
Hier werden irgendwelche Mixer-Variablen gesetzt, die ich jetzt in der Tiefe auch nicht verstehen muss, aber der ganze Block ist in einer #if defined(USE_UNCOMMON_MIXERS)-Umgebung. Das bedeutet, wenn dieser Bezeichner nicht definiert/gesetzt ist, wird static const motorMixer_t mixerY6[ nicht gesetzt, beinhaltet Null und wird demzufolge in der Motor-Steuerung ignoriert. Jetzt muss man also prüfen, ob für das Target Flip32/NAZE der Bezeichner USE_UNCOMMON_MIXERS tatsächlich gesetzt ist. Diese Information finden wir in target/common_fc_pre.h, und zwar ganz am Ende der Datei:
C:
...
#define USE_SERIALRX_SUMH       // Graupner legacy protocol
#define USE_SERIALRX_XBUS       // JR

#if (FLASH_SIZE > 64)
#define MAX_PROFILE_COUNT 3
#else
#define MAX_PROFILE_COUNT 2
#endif

#if (FLASH_SIZE > 64)
#define BLACKBOX
#define LED_STRIP
#define TELEMETRY
#define TELEMETRY_FRSKY
#define TELEMETRY_HOTT
#define TELEMETRY_SMARTPORT
#define USE_RESOURCE_MGMT
#define USE_SERVOS
#endif

#if (FLASH_SIZE > 128)
#define GPS
#define CMS
#define TELEMETRY_LTM
#define TELEMETRY_CRSF
#define TELEMETRY_IBUS
#define TELEMETRY_JETIEXBUS
#define TELEMETRY_MAVLINK
#define TELEMETRY_SRXL
#define USE_DASHBOARD
#define USE_MSP_DISPLAYPORT
#define USE_RX_MSP
#define USE_SERIALRX_JETIEXBUS
#define USE_SENSOR_NAMES
#define USE_VIRTUAL_CURRENT_METER
#define VTX_COMMON
#define VTX_CONTROL
#define VTX_SMARTAUDIO
#define VTX_TRAMP
#endif

#if (FLASH_SIZE > 256)
#define USE_UNCOMMON_MIXERS
#endif
Also nur für Targets mit Flash-Größe von mehr als 256 werden die UNCOMMON_MIXERS überhaupt mit einkompiliert. An der Stelle wurde mir schlagartig klar, dass hier der Grund für das Problem von Jörn liegen könnte, weil für seinen kleinen Flip32 mit F3 CPU der Flash zu klein sein würde. Man muss also aus der Standard-Konfiguration für kleine F3 etwas hergeben, um die UNCOMMON_MIXERS haben zu können. Dazu habe ich die Datei target/common_fc_pre.h etwas umgebaut:
C:
...
#define USE_SERIALRX_XBUS       // JR
#define USE_UNCOMMON_MIXERS

#if (FLASH_SIZE > 64)
#define MAX_PROFILE_COUNT 3
#else
#define MAX_PROFILE_COUNT 2
#endif

#if (FLASH_SIZE > 64)
#define BLACKBOX
#define LED_STRIP
#define TELEMETRY
#define TELEMETRY_FRSKY
#define TELEMETRY_HOTT
#define TELEMETRY_SMARTPORT
#define USE_RESOURCE_MGMT
//#define USE_SERVOS
#endif
#define USE_UNCOMMON_MIXERS wurde nach oben kopiert, so dass es in jedem Fall gesetzt wird und für die Targets mit FLASH_SIZE > 64 (trifft für Flip32 zu) habe ich den Support für die Servos geopfert.

3. Neue Firmware übersetzen
Zum Übersetzen der Firmware dann einfach die folgenden Befehle:
Bash:
michael@MacBookAir main % cd ..
michael@MacBookAir src % cd ..
michael@MacBookAir cleanflight % make arm_sdk_install
michael@MacBookAir cleanflight % make TARGET=NAZE
Also zwei Verzeichnisebenen zurückgehen, dann den passenden Compiler automatisch und lokal in die Code-Basis installieren lassen und schließlich das gewünschte Target übersetzen. Wenn alles passt, bekommt man am Ende die folgende Meldung:
Bash:
...
%% stm32f10x_wwdg.c
Linking NAZE
./tools/gcc-arm-none-eabi-6-2017-q1-update/bin/arm-none-eabi-size ./obj/main/cleanflight_NAZE.elf
   text       data        bss        dec        hex    filename
 123004       1616      17232     141852      22a1c    ./obj/main/cleanflight_NAZE.elf
./tools/gcc-arm-none-eabi-6-2017-q1-update/bin/arm-none-eabi-objcopy -O ihex --set-start 0x8000000 obj/main/cleanflight_NAZE.elf obj/cleanflight_2.0.5_NAZE.hex
michael@MacBookAir cleanflight %
Der Linker schmeißt Fehlermeldungen, wenn man zu viele Features versucht einzukompilieren. Hier kann man experimentieren mit target/common_fc_pre.h, was man haben möchte und auf was man verzichten kann.

Das war es dann auch schon. Die neue Firmware liegt im Unterverzeichnis obj und heißt in unserem Fall cleanflight_2.0.5_NAZE.hex. Diese Firmware hat Jörn dann auf seinen FC geladen und BOOM - es hat sofort funktioniert.

Nachtrag zu search.sh
Ich muss gestehen, dieses kleine Shell-Skript ist für mich eines der wichtigsten Werkzeuge überhaupt, um mich in der Cleanflight/Betaflight Codebasis zurechtzufinden. Wie bei vielen OpenSource-Projekten ist die Dokumentation meist sehr dürftig und man muss sich leider selbst durch die vielen Zeilen wühlen. Dazu ist es enorm hilfreich ein Tool zu haben, welches selektiv nur gewisse Quelltext-Dateien nach einem Suchbegriff durchsucht und sagt, wo es Treffer gibt. In meinem Fall liegt dieses Shell-Skript in Verzeichnis $HOME/bin. Die Rechte des Skripts sind so gesetzt, dass es ausführbar ist:
Bash:
michael@MacBookAir obj % cd $HOME/bin
michael@MacBookAir bin % ll search.sh
-rwxr-xr-x  1 michael  staff  546  5 Aug 12:50 search.sh
michael@MacBookAir bin %
Damit kann man es von jedem Ort aus direkt aufrufen, vorausgesetzt dass $HOME/bin sich im Suchpfad befindet. Der Inhalt des Skripts ist der folgende:
Bash:
#! /bin/bash
 
#datafile
datafile=data.asc

if [ $# -ne 1 ]; then
    echo
    echo "Falscher Parameter!"
    echo
    exit 1
fi

# suche aller dateien mit *.inc oder *.f oder *.f90
find . -name "*.html" >  $datafile
find . -name "*.js" >>  $datafile
find . -name "*.h" >>  $datafile
find . -name "*.c"   >> $datafile
find . -name "*.cpp"   >> $datafile

echo "Diese Dateien enthalten den Ausdruck:  $1"
echo
cat $datafile | xargs grep -i --count "$1" | grep -iv ":0" | sed -e "s/:.*//"
echo
echo "Ende der Liste."

rm -f $datafile

exit 0
Es werden also vom aktuellen Verzeichnis-Startpunkt aus alle relevanten Quelltext-Dateien gesucht und deren relative Pfade in einer temporären Datei gespeichert. Der Inhalt dieser Datei wird dann mit einer Kette von Befehlen verarbeitet, so dass am Ende herauskommt, welche Datei den gewünschten Suchbegriff beinhaltet. Am Ende wird die temporäre Datei gelöscht.
 
Erhaltene "Gefällt mir": vantaro
FPV1

Banggood

Oben Unten