Dan's Orbiter page

Orbiter Francophone => Orbiter Francophone => Topic started by: Mars Bleu on 08 November 2016, 08:44:24

Title: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 08 November 2016, 08:44:24

L’idée de construire un simucockpit pour mieux profiter d’Orbiter est présente dans ma tête depuis déjà un bon moment. J’avais les connaissances en électricité, en électronique, en dépannage, et en programmation pour commencer à m’aventurer dans ces terrains là. Il fallait seulement se lancer, ce que j’ai fini par faire depuis la fin de 2013.

LA GENÈSE:

J’ai commencé par rechercher plein de doc sur le Net, tant sur les simpits FSX que sur ceux dédiés à Orbiter. Sans idée préconçue, j’ai même envisagé l’utilisation de cartes SIOC dédiées à Flight Simulator.

J’ai suivi les travaux d’Antoo et de son frère; ils m’ont fait part de leur expérience qui a alimenté ma réflexion. Mais je voulais aller plus loin que les raccourcis clavier, et utiliser d’autres fonctions permettant d’afficher des valeurs telles que le cap, l’altitude, les fréquences radio, les jauges de carburant, etc… Le problème de la synchronisation des commutateurs du cockpit avec le scénario chargé au démarrage d’Orbiter était aussi à résoudre.

            La lecture des blogs consacrés au sujet des simpits montre que la concrétisation d’un tel projet est rare.

PRINCIPES GÉNÉRAUX:

Je pense que pour réussir, il faut poser des jalons :
                                                    -étudier la faisabilité
                                                    -faire quelques essais sur des fonctions principales
                                                    -passer à la construction proprement dite
                                                    -rester modulaire

Pour garder le fil de mes idées, j'utilise deux cahiers; l'un pour la partie programmation, et l'autre pour la construction des cartes électroniques associées à la carte Arduino.


Avant d’entamer un petit historique de mes travaux, je tiens à dire que les solutions que j'ai choisies sont possibles parmi d’autres. Ce ne sont que des indications qui pourront peut-être donner des idées à d’autres orbinautes. Aux yeux de codeurs avertis, j'aurai peut-être produit du vilain code (mais qui en principe doit fonctionner). C'est parfois intentionnel, car ça a été la seule façon que j'ai trouvée pour pouvoir m'en sortir.
La maître mot est compacité du code: il y peu de place dans nos microcontrôleurs préférés et les fréquences d'horloge ne sont pas très rapides.

 Mes premières lignes de code remontent il y a déjà bien longtemps, au temps du BASIC spaghetti, avec des numéros de ligne et des GOTO partout.

J'aurais bien aimé construire un vrai poste de pilotage déménageable, mais faute de place disponible, je pense m'orienter comme Hysot vers la réalisation d'un tableau de commande plus compact et plus léger.

LES PRINCIPAUX CHALLENGES:

Afin de parvenir à mes fins, plusieurs challenges se présentaient(liste non exhaustive):
                                 * Lire de manière automatique un fichier scn
                                 * Envoyer à Orbiter une commande simple avec la UNO
                                 * Multiplier les entrées/sorties sur la UNO
                                 * Commander des leds branchées sur la UNO au moyen d'un script Lua
                                 * Construction des modules Parallel Input Serial Output (PISO)
                                 * Construction des modules Serial Input Parallel Output (SIPO)
                                 * Construction des cartes de servitudes (Alims électriques, support de la UNO)
                                 * Gestion des leds associées aux auxiliaires APU
                                 * Gestion des signalisations liées à l'équilibre de l'engin (gimbal, gravityshift)

                  Il y aura d'autres challenges, mais ceux cités ci-dessus ont été déjà réussis.

                                                 A bientôt pour le premier challenge.


Title: Re: Le tableau de commande de Mars Bleu
Post by: nerofox on 08 November 2016, 13:19:25
Génial je ne serai pas seul à me lancer dans cette aventure  :beer:
J'ai hate de voir les premières photos ou éventuel croquis, schéma ou autre de ce que tu compte mettre en place  :badfinger:

J'ai plus qu'envisager d'utiliser lua pour la programmation j'en avais même parlé sur mon topic de tableau de bord, en revanche pour ma part le programme peut être assez conséquent et donc il serait préférable d'utiliser un langage plus modulable et qui s'organise de meilleur façon (le C++ notamment) c'est juste plus complexe a mettre en œuvre  :badsmile:

N'hésite pas a échanger sur la partie logiciel si tu a des questions ou autre  :wonder:

Good luck !
Title: Re: Le tableau de commande de Mars Bleu
Post by: antoo on 08 November 2016, 15:12:51
Trop cool ! Bienvenue au club :beer: !

Hâte de voir l'avancement de ton projet.

A+
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 08 November 2016, 17:38:27
Merci, les gars. C'est en échangeant les idées qu'on avance le mieux.

Pour les photos et schémas, ne vous inquiétez pas, ça viendra. Faudra que je les uploade.
Title: Re: Le tableau de commande de Mars Bleu
Post by: nulentout on 10 November 2016, 11:46:22
Coucou les copains,
Si je devais me refaire un tableau de bord, je pense que j'opterais pour plusieurs cartes Arduino. Vu le coût de quelques Euros d'une carte Nano qui a autant, sinon plus de possibilités que la Uno, en introduire plusieurs augmente le nombre d'entrées/Sorties, d'entrées analogiques etc. De plus, le logiciel réparti en plusieurs modules sera plus facile à dominer. Il ne faut pas oublier que certaines commandes sont prioritaires et doivent être prises en compte immédiatement. Par exemple une carte s'occupe en priorité des commandes de pilotage. Avec six entrées analogiques on peut déjà gérer les poussées principales. Mais pour les RCS une deuxième sera certainement la bienvenue. Une troisième carte prendrait en charge les requêtes moins urgentes, par exemple les inverseurs, les boutons poussoir etc. En multiplexant on peut facilement gérer 8 x 8 boutons, ce qui ouvre pas mal de possibilités. Sans compter que les deux premières cartes qui assurent les commandes de vol peuvent aussi s'occuper des afficheurs, de diverses LEDs etc.
Bref, avant de foncer, il me semble salutaire de réfléchir assez loin à l'architecture électronique future, et ne pas oublier de diviser les difficultés pour vaincre !
Quoi qu'il en soit, cogitez, percez, soudez ... il en restera forcément ... un superbe vaisseau !
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 12 November 2016, 12:51:37
Tout à fait d'accord avec toi, ô Nulentout. Dans l'avancement de mon projet,
je tiens à rester modulaire.
Pour l'instant, mon sketch Arduino tient dans moins de 10 Ko, alors qu'il gère pour l'instant
20 switches ou BP, et 100 lumineux. Ce qui fait qu'une UNO ou Léonardo convient encore.  Je ne sais pas combien de temps quelle taille de simpit ça pourra gérer.
Mais la DUE me semble indiquée pour amplifier un projet déjà devenu imposant.

Tu soulèves un point intéressant en parlant de priorité de certaine commandes par rapport à d'autres.
Je me demande pour l'instant comment on peut programmer des priorités. Je sais que le soft du LEM
avait été basé sur cette gestion des priorités, ce qui leur avait permis de se poser en sécurité
malgré l'avalanche de "stack overflow".
Title: Re: Le tableau de commande de Mars Bleu
Post by: nulentout on 15 November 2016, 11:13:44
Coucou les copains,
Ben ... pour gérer des priorités deux approches sont envisageables :
Confier les plus hautes priorités à un microcontrôleur qui s’en occupe en temps réel et « ne fait que ça ».
Charger un processeur de tout, mais les actions prioritaires sont traitées par interruptions.
L’ATmega328 se prête bien aux interruptions, mais il faut te « cogner » la théorie pour pouvoir mettre en pratique.  :wall:
 
Title: Re: Le tableau de commande de Mars Bleu
Post by: Bibi Uncle on 15 November 2016, 17:57:45
Pour une gestion des priorités efficaces, le mieux est de quitter le nid douillet de l'environnement Arduino, et de faire du "bare-metal" programming avec un RTOS. Ceci va te permettre d'avoir plusieurs tâches qui s'exécutent en même temps, d'avoir des tâches qui se réveillent par interruption et, si programmé correctement, d'avoir un environnement déterministe. C'est beaucoup plus complexe à programmer, mais ça peut être vraiment plus efficace à l'exécution.

Je te suggère de regarder FreeRTOS et TI-RTOS. Il y a aussi quelques projets de librairies pour simplifier la programmation bare-metal, notamment xpcc qui est une jolie librairie écrite en C++11.
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 15 November 2016, 18:31:07
Hou là!! Dans mon cours déjà lointain sur les microprocesseurs, ce que j'avais trouvé
le plus difficile était bien les interruptions.
Quant au "bare metal", alors là, je n'en suis pas là. Ça se programme en C++, ce truc là?

Disons que, pour l'instant, là où j'en suis, les réactions de mon système se font sans délai.
Mais je jetterai un œil là dessus, car c'était quelque chose dont j'ignorais l'existence...
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 20 November 2016, 20:43:07
Allez, on attaque:
                                      PREMIER CHALLENGE: Lire un fichier SCN


Dans un premier temps, je voulais savoir s'il était possible pour moi de récupérer des données d'un fichier SCN, de façon à pouvoir les charger dans le simpit. Le moyen d'y arriver est bien entendu d'utiliser la console Lua d'Orbiter.

Elle s’obtient avec F4, puis bouton « Custom ». On sélectionne « Lua console window », et la console va s’ouvrir. A partir de là, on peut entrer des lignes de commande. Par exemple, pour l’altitude :
         
Code: [Select]
Term.out(oapi.get_altitude()) va donner l’altitude du vaisseau
Pour d’autres valeurs, il faut d’abord avoir le handle du vaisseau. Il faut faire en premier :
         
Code: [Select]
v=vessel.get_focusinterface()Puis, si on veut connaître par exemple l’état des RCS :
         
Code: [Select]
term.out(v :get_rcsmode()) va renvoyer 0, 1 ou 2 selon la position du commutateur RCS.
Dans ce domaine, j’ai bidouillé pour connaître la valeur des jauges de carburant (Main Fuel, RCS, SCRAM Fuel). En regardant la doc, j’ai pu trouver tout ce que je cherchais.

Après cette première prise de contact avec la console LUA, j’ai éprouvé le besoin de lancer un script Lua depuis un scénario. Comme je ne savais pas trop comment faire, j’ai regardé le scénario "Atlantis/launch".



Au début du scénario, on a:
Code: [Select]
BEGIN ENVIRONMENT
System Sol
Date MJD
Script Demos/Atmautopilot
END ENVIRONMENT

Donc, on peut appeler un script Lua, en l'occurrence "Atmautopilot" à exécuter au lancement du scénario. C'est parfait pour lire l'état  du vaisseau, à condition de pouvoir ouvrir et lire ce dont on a besoin dans le fichier SCN. Mais comment faire?

Dr Spock m'a donné un début de solution en écrivant un script Lua pour des HiScores dans le cadre de Orbiter Challenge.

Code: [Select]
Data.path='Script/Challenges/Challenge1.dat'
max_score=10

slist=hscore_read(data_path, max_score)

function hscore_read(file, n)
local slist={}         
local f=io.open(file, "r")
if f~=nil then
for i=1, n do
local t=f:read()
if t==nil then break end
local name, fuel
_,_,name, fuel=string.find(t, "(._):(.+)")
slist[i]={name, to number(fuel)}
end
f:close()
end
return slist
     end

En cherchant à afficher en surimpression à l'écran les valeurs liées à mon vaisseau, je finis par avoir:
Code: [Select]
-- ******************************************
-- ********read number lines from scn file***
-- ******************************************
function line_read (file)
    number_lines=0
    local g = io.open(file,"r")
    if g ~= nil then
        repeat
            t = g:read()
            number_lines=number_lines+1
        until t == nil
    g:close()
    end
end
-- *****************************************
-- *********end function line_read *********
-- *****************************************
Cette première fonction a pour but de connaître le nombre de lignes à lire.

Ensuite,
Code: [Select]
-- *******************************************
-- ********load lines from scn file***********
-- *******************************************
function load_scnfile (file,n)
    slist={}
    local f = io.open(file,"r")
    if f ~= nil then
        for i=1,n do
            t = f:read()
            if t == nil then break end
            slist[i]=t
        end     
        f:close()
    end
    return slist
end
-- ******************************************
-- *********end function load_scnfile *******
-- ******************************************
Celle-ci va remplir le tableau slist[] ligne par ligne avec le contenu du fichier SCN.

Une fois le tableau chargé, on veut connaître les valeurs concernant les auxiliaires du vaisseau. Chacun aura compris qu'on parle ici du Xr2 Ravenstar.
Code: [Select]
-- *******************************************
-- ***********load ship status****************
-- *******************************************
function load_xr2_status (pattern)
    for i=1,number_lines-1 do
       s1 = slist[i]
       _,_,name,classname = string.find (s1, "(.-):(.+)")
       if (classname=='XR2Ravenstar') and (ship=='XR2Ravenstar') then
           name_ship=name
           for j=i, number_lines-1 do
               if string.match (slist[j], 'NOSECONE')~=nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
                   note:set_text('NOSECONE=>'..status..' '..level)
                   proc.wait_sysdt(0.41)
               elseif string.match (slist[j], 'GEAR')~=nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
                    note:set_text('GEAR=>'..status..' '..level)
                   proc.wait_sysdt(0.41)
               elseif string.match (slist[j], 'RADIATOR')~=nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
                   note:set_text('RADIATOR=>'..status..' '..level)
                   proc.wait_sysdt(0.41)
               elseif string.match (slist[j], 'HATCH')~=nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
                   note:set_text('HATCH=>'..status..' '..level)
    elseif slist[j]=='END' then
                   flag_out=1
                   break
               end                     
           end
       

Cette partie de script lit les lignes du fichier SCN et extrait les valeurs associées au nosecone, gear, radiator, hatch. Status contient une valeur comprise entre 0 et 3 (0 pour replié; 1 pour déployé; 2 pour en repli; 3 pour en déploiement), tandis que level contient une valeur à 4 chiffres après la virgule comprise entre 0 et 1. Les valeurs extrêmes de level sont 0 pour replié, 1 pour déployé. Ce sont ces valeurs qui devront ensuite être transmises à la Uno Arduino afin de synchroniser le cockpit sur l'état du Xr2 dans le SCN. Mais nous n'y sommes pas encore. Pour l'instant, le script ne fait qu'afficher ces valeurs à l'écran, une fois le scénario lancé.

J'ai aussi vérifié qu'il était possible d'afficher à l'écran les valeurs de réservoir et celles concernant d'éventuels conteneurs de cargaison chargés dans la soute.
Il fallait aussi envisager le cas où on aurait deux Xr2 dans le scénario, et ne se charger que du vaisseau à bord duquel on se trouve.

Ces trois fonctions(compter le nombre de lignes du scn, charger ces lignes dans un tableau, lire les valeurs qu'on y trouve) sont appelées par ce qui suit:
Code: [Select]
--****************************************************************************
-- ********** begin program ************************* begin program *********
--*****************************************************************************
note = oapi.create_annotation()
note:set_pos (0.35,0.1,0.8,0.95)
note:set_colour ({r=0.9,g=0.5,b=0.2})

data_path = 'Scenarios/(Current state).scn'
intro = 'Load scn data'

note:set_text(intro)
proc.wait_sysdt(0.5)

note:set_colour ({r=0.9,g=0.0,b=0.0})

v=vessel.get_focusinterface()
ship=v:get_classname()
name_ship_focused=v:get_name()


-- ******************************************************
-- ***********begin call functions for scn file**********
-- ******************************************************

sfirst = line_read (data_path)

slist = load_file (data_path,number_lines)


if  ship=='XR2Ravenstar' then
    lstatus = load_xr2_status (ship)
elseif ship=='Xr5Vanguard' then
    note:set_text('Toward function loop load of XR5Vanguard')
    proc.wait_sysdt(2.01)
elseif ship=='ShuttleA' then
    note:set_text('Toward function loop load of ShuttleA')
    proc.wait_sysdt(2.01)
else
    note:set_text('vessel not implemented, simpit not activated')
    proc.wait_sysdt(2.01)
end
-- ******************************************************
-- ************ end call functions for scn file**********
-- ******************************************************
note:set_text('End of program')
proc.wait_sysdt(1)
note:set_text('  ')
proc.wait_sysdt(1)

J'ai arrangé quelque chose de façon à ce qu'on puisse avoir autant de classe de vaisseau qu'on veut. Ca dépendra ensuite du simpit qu'on a construit.

Ces quelques lignes de script Lua ont validé mon idée qu'il est possible d'aller chercher des données dans le fichier SCN, de façon à pouvoir les envoyer dans le simpit. Ce dernier pourra donc être synchronisé avec le scénario chargé au préalable.

Le prochain challenge consistera en l'envoi d'une commande simple par la UNO à Orbiter.
Title: Re: Le tableau de commande de Mars Bleu
Post by: nerofox on 21 November 2016, 18:30:41
excellente infos
lua est un langage de script avant tout il existe des librairies pour tout  :badfinger:
cherche du coté luars232 pour la communication série avec une Arduino

bon courage pour ta recherche :)
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 23 November 2016, 18:06:21
Oui, Luars232 est bien utile. Il faut simplement mettre la dll au bon endroit.
J'avance bien dans mes travaux. Je sors d'une phase programmation et
débogage intensive pour attaquer une nouvelle phase de construction.
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 05 December 2016, 18:22:51
DEUXIÈME CHALLENGE: faire envoyer à la Arduino UNO une commande simple à ORBITER



La deuxième chose à valider est l'utilisation d'une carte Arduino Uno configurée en clavier afin d'envoyer des caractères en fonction d'un switch manœuvré. (Par exemple "G" pour manœuvrer le train d'atterrissage.)
Les posts de Hysot ont été très, très utiles pour me guider.
Pour cela, voir à:  http://orbiter.dansteph.com/forum/index.php?topic=12877.0 (http://orbiter.dansteph.com/forum/index.php?topic=12877.0)


J'ai effectué ma première commande de matériel, comprenant bien sûr une UNO. J'avais commandé un kit de base (quelques résistances, condensateurs, leds, etc…)
L'idée est que la manœuvre du switch va ouvrir ou fermer un circuit électrique. Selon que le circuit est ouvert ou fermé, on applique ou non Vcc aux bornes de la résistance de 10KΩ. Il suffit de connecter la borne où Vcc est appliquée à un pin  configuré en entrée de la UNO.

On commence simple...

(http://img4.hostingpics.net/pics/486296Intergear.jpg)

Dans la UNO, on charge un sketch qui enverra le caractère "g" à chaque changement d'état du switch:
Code: [Select]
#include <HIDKeyboard.h>                    // Inclut la librairie HIDKeyboard au programme

HIDKeyboard keyboard;                       // Initialise la librairie

int Buttonpin = 7;                          //Le bouton est branche sur la pin 7
int ButtonState = 0;                        //L'etat du bouton: ON (HIGH) ou OFF (HIGH). On lui donne pour le moment la valeur 0
int PreviousButtonState = 0;                //Le precedent etat du bouton

void setup()
{
  pinMode(Buttonpin, INPUT);                //On initialise la pin 7 comme une entree
 
  keyboard.begin();                         // Commence la communication
  delay(2000);                              // Attend que le peripherique soit reconnue comme un clavier
}

void loop()
{
  ButtonState = digitalRead(Buttonpin);     //On lit l'etat de la pin 7 et on le stocke dans la variable ButtonState
 
  if (ButtonState != PreviousButtonState)   //On compare les deux états. Si ils différents, la condition est validée et on écrit la lettre A
  {
    PreviousButtonState = ButtonState;      //On enregistre le nouvel état du bouton dans la variable PreviousButtonState pour
                                                             //la prochaine boucle.
    keyboard.pressKey('g');
    delay(100);
    keyboard.releaseKey();
    delay(50);
  }
}

Ensuite, il faut configurer la UNO en Keyboard selon la procédure indiquée par Hysot.

Il n'y a plus qu'à lancer Orbiter avec un DG en orbite, et manœuvrer le switch. Le train va suivre les mouvements du switch.

Ce petit montage a validé la possibilité de commander un auxiliaire d'un vaisseau d'Orbiter avec un raccourci clavier envoyé par une UNO. Ce n'était pas une première scientifique, mais j'étais bien content d'y être arrivé.


MAIS en avançant dans le projet, je me suis aperçu que la UNO une fois configurée en clavier ne peut pas
recevoir des données. Normal: un clavier n'est pas un périphérique qui reçoit des données, il en envoie.
Pour contourner la difficulté, il faut un Arduino capable d'être tant un périphérique capable de recevoir
des données, qu'un clavier (ou vu comme tel). c'est pour ça que je suis passé à la Leonardo. Du coup, plus
de librairie Keyboard à charger, ni de flashouillage de la UNO.

Le prochain challenge sera de multiplier les entrées/sorties connectées à la Arduino.

Title: Re: Le tableau de commande de Mars Bleu
Post by: nerofox on 05 December 2016, 19:24:32
Ta progression est intéressante et apporte de l'aide futur à d'autres personnes qui souhaiteraient se lancer dans l'aventure  :wor:

A noter que tu peux paramétrer ton switch non pas en mode INPUT mais en INPUT_PULLUP, cela évite d'ajouter une résistance au montage et donc simplifie l'électronique  :badfinger:

ce qui nous donne:
Code: [Select]
void setup()
{
  pinMode(Buttonpin, INPUT_PULLUP);                //On initialise la pin 7 comme une entree
 
  keyboard.begin();                         // Commence la communication
  delay(2000);                              // Attend que le peripherique soit reconnue comme un clavier
}
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 05 December 2016, 19:47:11
 :friend: Merci, Nerofox :friend:

Je ne connaissais pas cette commande INPUT_PULLUP; ce qui fait que
j'ai assemblé mes cartes d'élaboration de signal en incluant à chaque canal
une résistance de 10kOhms. 144 entrées en tout! Comme ça fonctionne,
je ne change rien :badsmile:
Title: Re: Le tableau de commande de Mars Bleu
Post by: nulentout on 17 December 2016, 07:19:54
Coucou les copains,
Je ne suis pas certain d'avoir tout compris dans le détail, mais il me semble que tu comptes affecter une entrée binaire par inverseur. Si il s'agit de boutons poussoir, tu peux en placer 5 ou 6 par entrée analogique, mais je suppose que tu sais faire ...
Bonne continuation : Nulentout
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 18 December 2016, 10:11:33
Effectivement, je vais faire ça. Mais la voie analogique a été une impasse pour moi. Je suis passé
par la voie numérique, avec succès.
Je voulais poursuivre les descriptions de mes travaux, mais hostingpics a l'air surchargé, ce matin.
Pas moyen d'uploader les photos destinées à illustrer mon propos. A suivre...


Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 18 December 2016, 12:23:00
Eeeet voici le....
              TROISIÈME CHALLENGE: multiplier les entrées/sorties connectées à la UNO

En suivant le chemin ouvert par Hysot, j'ai cherché à connecter plusieurs switches sur une même entrée analogique de la UNO, en faisant varier la tension d'entrée par des ponts diviseurs. Avec deux ou trois switches et des résistances associées, j'arrivais à peu près à mes fins, mais avec une dizaine de switches, je ne m'en sortais plus. J'ai noirci des pages et des pages, fait des tas d'essais de sketches Arduino pour arriver à la conclusion que j'étais dans une impasse technique. Il fallait faire autrement.

En remettant le nez dans la doc du web, j'ai trouvé: il faut faire du numérique. Le composant qui va me permettre d'avancer est le 74HC165, shift register PISO (Parallel Input Serial Output). Ce registre est cascadable, on peut donc avoir une multitude de switches dont on peut observer l'état. Ca tombe bien, car les raccourcis claviers du Xr2 sont nombreux (une bonne centaine).
D'un autre côté, les lumineux dont je vais avoir besoin vont être nombreux. Il y a déjà 12 auxiliaires APU sans compter les jauges de carburant, les afficheurs 7 segments, et tout un tas de signalisations.

Le site Arduino parle bien des 74HC165, et aussi des 74HC595 (registres SIPO). Avec ce qu'on y trouve, on peut apprendre facilement à s'en servir.


Nota:
A contrario, je commence par les registres de sortie 74HC595 afin de pouvoir matérialiser ce qu'on détecte des registres d'entrée 74HC165.



Les registres SIPO (Serial Input Parallel Output, 74HC595) vont permettre de gérer de multiples sorties, parce que cascadables tout comme le 74HC165.
Afin de tester, j'ai fait un montage provisoire sur breadboard, afin de matérialiser l'état des registres par l'allumage de leds.

(http://img4.hostingpics.net/pics/942690BrouillonSIPO1.jpg)

La photo ci-dessus montre le montage à deux 74HC595 chaînés. Dans un premier temps, j'avais utilisé seulement un seul registre SIPO et les leds rouges.

Pour commander l'allumage de 8 leds:

Code: [Select]
const int dataPin_out=2;   
const int latchPin_out=3;   
const int clockPin_out=4;
int byte1=0;
void setup()
{
pinMode(dataPin_out, OUTPUT);
pinMode(latchPin_out, OUTPUT);
pinMode(clockPin_out, OUTPUT);
Serial.begin(9600);
}

void loop()
{
byte1=byte1+1;
shiftOut(dataPin_out,clockPin_out,LSBFIRST,byte1);
delay(1000);
if byte1=255
{
Byte1=0;
}
}

Ca fait un compteur binaire dont l'état est matérialisé par l'allumage des leds.

Huit lumineux, c'est bien, mais il me fallait plus. L'étape suivante a été de chaîner un deuxième 74HC595, et d'y connecter huit leds supplémentaires, comme sur la photo.

Attention au bilan électrique du 74HC595: le circuit supporte une intensité totale de 70mA. Donc, pour au maximum 8 leds allumées, il faut au plus 8.75 mA par led. Pour cela, il faut une résistance d'atténuation de 300Ω pour chaque led. Dans la pratique, j'ai mis des résistances de 330 Ω, et je n'ai pas encore détruit de 74HC595.

Pour le remplissage des registres, j'ai voulu me passer de la commande shiftOut(), et utiliser des commandes plus élémentaires.

J'ai fini par arriver à cette fonction, où le tableau SIPOreg[ ] contient les valeurs commandant l'allumage ou l'extinction de leds. NumberSIPOreg est le nombre de registres à remplir divisé par deux. Cette division par deux est rendue nécessaire car j'utilise des mots de 16 bits (unsigned int) avec des registres de 8 bits.

Le principe est qu'on va pousser chaque bit dans la chaîne de registres, autant de fois qu'il le faut pour caler l'ensemble dedans. Si on a deux registres chaînés, on pousse 16 fois à chaque fois qu'on accède à cette fonction.

Code: [Select]
  // Fonction de remplissage des registres
  void updateRegister(unsigned int SIPOled[])
  {
      digitalWrite(latchPin_out, LOW); //déverrouillage des registres
      unsigned int value; //déclaration mémoire tampon pour scrutation SIPOreg[]
      for (byte Ii=0;Ii<NumberSIPOreg;Ii++)// traitement du nombre de registres divisé par 2:
      {                            // on marche en 16 bits sur des registres à 8 bits
        value=SIPOled[Ii];
        for (byte j=0;j<16;j++)          // scrutation des 16 bits de chaque élément de SIPOled[]
        {   
          digitalWrite(clockPin_out, HIGH); un coup d'horloge
          digitalWrite(dataPin_out, ((value&32768)==32768)); //détermination et écriture de DATA à 0 ou 1 sur pin 2 de la UNO
          digitalWrite(clockPin_out, LOW); fin du coup d'horloge
          value=value<<1;// décalage des bits
        }// fin de la boucle for j
      }//fin de la boucle for Ii
      digitalWrite(clockPin_out, HIGH); //ce coup d'horloge a été rajouté pour arriver à caler les bits
      digitalWrite(clockPin_out, LOW);// dans les registres. Je ne sais pas pourquoi c'est indispensable
                                      // mais ça marche comme ça
      digitalWrite(latchPin_out, HIGH);// verrouillage des registres
  }//fin remplissage des registres

Attention, ce code ne marche pas tout seul, il faut les déclarations, le setup, et le loop. C'est juste une fonction.


Si je rajoute un paquet de registres, il me suffit de changer la valeur de NumberSIPOreg dans la déclaration des variables, pour maintenir le calage.

Voilà, plus besoin de la fonction shiftOut(), et je peux multiplier les lumineux commandés par la UNO.

L'état des registres de sortie pouvant ainsi être très facilement matérialisé, on va pouvoir s'intéresser aux registres d'entrée en grand nombre
Title: Re: Le tableau de commande de Mars Bleu
Post by: Bibi Uncle on 20 December 2016, 05:57:03
Le coup d'horloge que tu ajoutes à la fin est dû au fait que SRCLK (ton clockPin_out) est activé sur un front montant (rising edge), ce qui décale tout ton encodage. Ainsi, ton premier bit est introduit dans le shift register lors du deuxième passage dans ta boucle, au front montant de SRCLK en prenant la valeur qui est toujours sur SER (ton dataPin_out).

J'ai refait un peu ton code:
Code: [Select]
// Fonction de remplissage des registres
void updateRegister(unsigned int SIPOled[], byte numSIPOreg)
{
    // Déverouillage des registres
    digitalWrite(latchPin_out, LOW);

    // On s'assure que l'horloge est dans un état connu
    digitalWrite(clockPin_out, LOW);

    // On parcourt chaque bloc de 16 bits
    for (byte i = 0; i < numSIPOreg; ++i)
    {
        unsigned int value = SIPOled[i];

        // On parcourt chaque bit
        for (byte j = 0; j < 16; ++j)
        {
            // Écriture de la valeur.
            unsigned int mask = 0x8000 >> j;
            digitalWrite(dataPin_out, value & mask)

            // Un coup d'horloge
            digitalWrite(clockPin_out, HIGH);
            digitalWrite(clockPin_out, LOW);
        }
    }

    // Verrouillage des registres
    digitalWrite(latchPin_out, HIGH);
}

Description des changements:

1. Ta variable NumberSIPOreg est maintenant passée en paramètre au lieu d'être une constante. Ça te permet de réutiliser ta fonction n'importe où.

2. Au début de la fonction, après avoir latché le shift register, c'est bien de réinitialiser l'horloge à LOW. Ainsi, si jamais ton code laisse par inadvertance l'horloge à HIGH, ta fonction est blindée.

3. La variable value est maintenant créée à l'intérieur de ta première boucle for. C'est une bonne pratique de limiter le scope de tes variables. Puisque celle-ci n'est utile qu'à l'intérieur de ta boucle, autant la déclarée à l'intérieur de celle-ci. Une nouvelle variable sera instanciée à chaque itération de ta boucle et elle ne sera jamais dans l'état non-initialisé (comme c'était le cas avant). N'est pas peur pour les performances, c'est une variable allouée sur la pile. Mon code est donc tout aussi performant que le tiens.

4. Au lieu de shifter la variable value, je préfère utiliser un masque. Comme ça, la variable value n'est jamais modifiée et représente toujours tes données. C'est seulement le masque (qui est en fait un 1 que je place à vis-à-vis le bit voulu, pour ensuite faire un AND avec la valeur pour l'extraire). Si tu n'es pas familier avec les masques, l'article Wikipédia en anglais donne de bonnes explications : https://en.wikipedia.org/wiki/Mask_(computing)

5. Mon masque utilise le 32768 que tu utilisais auparavant (pour mettre le 1 à la fin complétement). Quand tu as affaire à des valeurs comme celle-ci, je te suggère d'utiliser la notation hexadécimale, car c'est plus évident de retrouver l'utilité de ta valeur. 0x8000, pour quelqu'un avec un peu d'expérience est facilement décodable. Avec 32768, il faut sortir la calculatrice.... Aussi, à partir C++14, tu peux utiliser des binary literals comme 0b10000000 par exemple, qui est très facile à lire. Toutefois, je ne sais pas trop quel compilateur est utilisé sur la plateforme Arduino, donc je suis resté à du C++ classique.

6. Les coups d'horloge ont été déplacés comme je l'ai expliqué plus tôt. Ainsi, tu écris ta valeur sur ton SER, puis le front montant de l'horloge (créé quand tu la fais passer à HIGH) enregistre cette variable. Ensuite, on remet l'horloge à LOW pour se préparer à l'autre insertion.

7. J'ai aéré le code, ça fait du bien aux yeux. Particulièrement les paramètres des boucles qui sont gênants a lire lorsqu'ils sont tous collés. C'est toujours une question de préférence, mais certains standards rendent le code plus lisible.
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 20 December 2016, 14:20:30
Merci, Bibi Uncle de visiter mon humble cabane! :)

La clarté du code que tu as réaménagé est éclatante. Je suis bien content d'avoir le point de vue
de quelqu'un qui a été formé à coder. Pour ma part, j'ai appris à programmer sur le tas, et en
électronique, ma formation remonte aux années 80. :sage:
Au moins, je comprends maintenant le coup d'horloge supplémentaire qu'il fallait envoyer
pour avoir un bon calage de mes bits.

Tous tes points d'explications sont autant de nouveaux objectifs pour apprendre à coder plus
proprement. Afin de tenir compte de tes conseils, je vais avoir pas mal de réécriture à faire.

Dans mon code, je fais beaucoup de bitwise. J'utilise des masques assez souvent, donc, j'ai beaucoup
de valeurs à remettre en hexa ou en binary litteral. Le lien wiki est intéressant: en fait,
je faisais du common bitmask functions sans m'en rendre compte.

Je me demande si un code à base de bitwise est plus efficace en temps machine qu'un code
sans bitwise. Je serais enclin à penser que oui....
Title: Re: Le tableau de commande de Mars Bleu
Post by: Bibi Uncle on 20 December 2016, 19:48:21
Je me demande si un code à base de bitwise est plus efficace en temps machine qu'un code
sans bitwise. Je serais enclin à penser que oui....

Si tu écris du code qui sera exécuté sur une machine moderne, de manière générale, c'est mieux d'éviter les opérations bit à bit. En effet, les architectures modernes sont hautement optimisées pour faire des opérations sur leur "unité de base" (généralement des mots de 32 bits pour des machines modernes). Ainsi, il est souvent préférable d'utiliser un booléen enregistré dans un mot de 32 bits que de fusionner 32 booléens dans un seul mot. Il y a un gaspillage de mémoire, mais ça nécessite moins d'instructions.

Par contre, dans ton cas, tu programmes un système embarqué qui a peu de mémoire et un jeu d'instructions probablement réduit (je connaît pas beaucoup les microcontrôleurs d'Atmel, donc je suppose). Il est donc probablement préférable d'utiliser des opérations bit à bit dans ton cas.

Parfois on n'a pas le choix de les utiliser. Notamment, si tu implémentes un protocole de communication de couche un peu plus basse (couche transport et en dessous), tu n'auras pas le choix d'utiliser ce genre d'instructions pour extraire tes données des champs. Prends une paquet IP par exemple. Pour savoir la longueur de ton en-tête, il faut extraire les bits 4 à 7 à partir du premier mot que tu reçois. Dans ce cas, pas le choix de les extraire avec des opérations bit à bit.
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 04 January 2017, 17:11:28
J'ai un peu tardé, car pas trop le temps de me connecter pendant les fêtes.

Merci pour tes explications. Sur un Arduino, il vaut mieux donc être économe.
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 04 January 2017, 17:47:43
                                              Registres d'entrée
Dans l'élaboration de mon tableau de commande, il faut aussi des switches et boutons poussoirs.

Avec 8 switches connectés, le sketch de base pour collecter l'état de switches et le transférer sur un registre d'entrée devient:
Code: [Select]
const int dataPin_out=2;
const byte latchPin_out=3;
const byte clockPin_out=4;
const byte dataPin_in=5;
const byte latchPin_in=6;
const byte clockPin_in=7;
byte value;

void setup()
{
pinMode(dataPin_out, OUTPUT);
pinMode(latchPin_out, OUTPUT);
pinMode(clockPin_out, OUTPUT);
pinMode(dataPin_in, INPUT);
pinMode(latchPin_in, OUTPUT);
pinMode(clockPin_in, OUTPUT);
Serial.begin(9600);
}

void loop()
{
digitalWrite(latchPin, HIGH);
delayMicrosecond(10);
digitalWrite(latchPin, LOW);
value=shiftIn(dataPin,clockPin);
shiftOut(dataPin_out,clockPin_out,LSBFIRST,value);
delay(10);
}

La valeur value va contenir la valeur binaire de la position 0 ou 1 des switches scrutés. La valeur variera de 0 à 255 (8 bits).

L'état de mon montage provisoire avec un 74HC165 et deux 74HC595, plus deux afficheurs 7 segments.
(Question fouillis, je m'arrêterai là pour passer à des montages plus rangés.)
(http://img4.hostingpics.net/pics/294263BrouillonSIPO3.jpg) (http://www.hostingpics.net/viewer.php?id=294263BrouillonSIPO3.jpg)


En voulant chaîner un deuxième 74HC165, j'ai eu des problèmes de stabilité sur le MSB du deuxième registre.
J'ai à peu près tout essayé tant en soft que sur mon montage, rien n'y faisait.
J'ai alors choisi de me passer de la commande shiftIn(). Voici ce que j'ai codé.

@BibiUncle: j'ai soigné la présentation, mais n'hésites pas à me corriger.

Code: [Select]
   // Fonction de lecture des registres PISO (switches et boutons poussoir)

  void get_PISO_register()
  {
    //latch à LOW pour lire l'état des switches, et on attend 10 microsecondes
    digitalWrite(latchPin_in,LOW);
    delayMicroseconds(10);

    //latch à HIGH, verrouillage
    digitalWrite(latchPin_in,HIGH);

    for (unsigned int i=0;i<Data_width+1;++i){             //data_width est le nombre de bits à lire (multiple de 8)

//on "pousse" Data_width fois les valeurs lues dans la mémoire switchStatus; c'est le shiftIn
       unsigned int switchStatus=(switchStatus<<1)|(digitalRead(dataPin_in));

       //un coup d'horloge
       digitalWrite(clockPin_in,HIGH);
       delayMicroseconds(10);
       digitalWrite(clockPin_in,LOW);
       delayMicroseconds(10);

       //j est un modulo 16 de i, afin de cadencer le remplissage du tableau PISOreg[]
       byte j=i%16;
       if ((i>0)&&(j==15)){
        // envoi de la valeur dans le tableau PISOreg[]
        PISOreg[i/16]=switchStatus;
       }//Endif
      } //Next i
     
  }// fin lecture des registres PISO

Avec cette fonction, je peux scruter un grand nombre de switches ou boutons poussoirs et avoir une image de leur état dans le tableau PISOreg[ ].
Dans ma configuration actuelle (Janvier 2017), j'utilise 15 switches, 9 boutons-poussoir(s?), 4 joysticks à 2 ou
4 contacts, et le gros coup-de-poing du "undock". Mais j'ai de la réserve, ayant à ma disposition 144 entrées.

Mais avant d'aborder le montage de tout ça, il faut encore s'assurer de la possibilité de transmettre des
données, en vue de la synchronisation du tableau de commande avec le scénario chargé.
Title: Re: Le tableau de commande de Mars Bleu
Post by: Bibi Uncle on 04 January 2017, 19:18:49
Tes délais de 10 microsecondes sont-ils vraiment nécessaires ? L'Arduino a une horloge assez lente (j'ai trouvé 16 Mhz, mais ça reste à confirmer puisque Atmel spécifie une fréquence maximale de 20 Mhz pour le ATMega328p). Si on émet l'hypothèse très généreuse qu'un digitalWrite est atomique (un seul coup d'horloge du microcontrôleur pour l'exécuter), ce qui serait assez impressionnant, ton coup d'horloge sans délai sera à 16 Mhz. Selon la documentation de TI pour le SN74HC165, à température ambiante à 4.5V, la fréquence max est de 31 Mhz. Bref, je crois que le délai n'est pas nécessaire.

Sinon, j'ai regardé rapidement ton code et ça me semble très bien :top:
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 04 January 2017, 20:47:47
 Effectivement, en y réfléchissant, ça n'est pas nécessaire, étant donné la fréquence
d'horloge qui est de 16Mhz.
Merci pour le :top:  :)
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 14 January 2017, 10:17:55
      QUATRIÈME CHALLENGE: commander des leds à partir de Lua


Le premier challenge consistait à extraire des données d'Orbiter avec un script Lua. Ce challenge fait la deuxième partie du transfert de données vers la UNO elle-même programmée pour piloter les lumineux.

Le grand principe est qu'un script Lua doit fonctionner dans Orbiter, et échanger des données avec la UNO contenant le sketch qui les traite.

Il a fallu que je remette le nez dans le Web pour trouver quelque chose ("the nose buried in documentation" comme j'ai pu lire). C'est Widdernix dans le forum américain d'Orbiter qui m'a donné la solution dans le fil "talking with serial devices". Voir à: http://orbiter-forum.com/showthread.php?t=17847 (http://orbiter-forum.com/showthread.php?t=17847)

Pour échanger des données, on a besoin d'une librairie, luars232.dll. J'ai cherché six semaines durant comment y accéder, avant de trouver qu'il fallait simplement mettre cette dll dans le répertoire d'Orbiter. Une fois cette dll bien positionnée, la commande rs232=require("luars232") ne faisait  plus planter le script Lua.
Nota: en ce qui me concerne, le plantage d'un script Lua sur Orbiter est tout à fait discret. En fait, on s'en aperçoit lorsque le défilé des note:set_text()ne fige plus à l'endroit du plantage présumé.

Après quelques mises au point, j'ai essayé le sketch Arduino suivant sur ce montage:

(http://img4.hostingpics.net/pics/942690BrouillonSIPO1.jpg)

Code: [Select]
byte dataPin=2;
byte latchPin=3;
byte clockPin=4;
byte data=255;
byte byte1;


void setup()
  {
    pinMode (dataPin,OUTPUT);
    pinMode (latchPin,OUTPUT);
    pinMode (clockPin,OUTPUT);
    Serial.begin(9600);
  }
 
void loop()
{

    if (Serial.available()>0)
    {
    byte1=Serial.read();
    digitalWrite(latchPin,LOW);
    shiftOut(dataPin, clockPin, LSBFIRST, byte1);
    digitalWrite(latchPin, HIGH);

    }

   delay(150);
}

Le script Lua associé est le suivant:

Code: [Select]
note = oapi.create_annotation()
note:set_pos (0.35,0.1,0.8,0.95)
note:set_colour ({r=0.9,g=0.5,b=0.2})


rs232=require("luars232")
local port_name="COM4"
local e,p=rs232.open(port_name)
if e ~= rs232.RS232_ERR_NOERROR then
term.out('',string.format("can't open serial port '%s', error: '%s'\n", port_name, rs232.error_tostring(e)))
    return
end
-- set port settings
assert(p:set_baud_rate(rs232.RS232_BAUD_9600) == rs232.RS232_ERR_NOERROR)
assert(p:set_data_bits(rs232.RS232_DATA_8) == rs232.RS232_ERR_NOERROR)
assert(p:set_parity(rs232.RS232_PARITY_NONE) == rs232.RS232_ERR_NOERROR)
assert(p:set_stop_bits(rs232.RS232_STOP_1) == rs232.RS232_ERR_NOERROR)
assert(p:set_flow_control(rs232.RS232_FLOW_OFF)  == rs232.RS232_ERR_NOERROR)

byte1='U'
err, len_written = p:write(string.char(byte1))
  end

note:set_text('Longueur écrite='..len_written)
proc.wait_sysdt(1)

assert(p:close() == rs232.RS232_ERR_NOERROR)-- this closes the COM

note:set_text('End of program')
proc.wait_sysdt(1)
note:set_text('  ')
proc.wait_sysdt(1)

Et là, VICTOIRE, j'ai réussi à écrire dans le registre à décalage et à afficher un octet sur 8 leds. Le caractère 'U' correspondant à 85, c'est-à-dire 01010101 en binaire, soit une led sur deux. Changeons le contenu de la variable byte1, et les leds s'allumeront autrement.

Je vous laisse digérer tout ceci, avant de vous montrer un petit TP dont l'objet sera d'afficher le machmètre
d'un XR2.
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 27 January 2017, 14:48:02
Pour ceux qui suivent, et tous les autres qui dorment au fond de la classe  :rant: :badfinger:, voici le petit TP
que je vous annonçais il y a quelques jours:

Pour ce faire, j'ai étoffé mon montage provisoire en adjoignant une bredboard supplémentaire comprenant deux afficheurs 7 segments branchés sur un 4543 ( entrée 4 bits=>afficheur 7 segments). Avec ces deux afficheurs, je voulais donc avoir un machmètre, en allant chercher la valeur par:

                                                      m=v:get_machnumber()

Puis avec une mise en forme, l'envoyer  par le port USB à la UNO qui la renverrait aux registres de sortie.

Ci dessous, le script Lua:
Code: [Select]
function send_data(n1,n2)
  e,p=rs232.open(port_name)
  if e ~= rs232.RS232_ERR_NOERROR then
    term.out('',string.format("can't open serial port '%s', error: '%s'\n", port_name, rs232.error_tostring(e)))
      return
  end
  -- set port settings
  assert(p:set_baud_rate(rs232.RS232_BAUD_9600) == rs232.RS232_ERR_NOERROR)
  assert(p:set_data_bits(rs232.RS232_DATA_8) == rs232.RS232_ERR_NOERROR)
  assert(p:set_parity(rs232.RS232_PARITY_NONE) == rs232.RS232_ERR_NOERROR)
  assert(p:set_stop_bits(rs232.RS232_STOP_1) == rs232.RS232_ERR_NOERROR)
  assert(p:set_flow_control(rs232.RS232_FLOW_OFF)  == rs232.RS232_ERR_NOERROR)
  err, len_written = p:write(string.char(n2)..string.char(n1))
  assert(p:close() == rs232.RS232_ERR_NOERROR)-- this closes the COM
end

note = oapi.create_annotation()
note:set_pos (0.35,0.1,0.8,0.95)
note:set_colour ({r=0.9,g=0.5,b=0.2})


intro = "Machmètre sur 2 displays 7 segments"

note:set_text(intro)
proc.wait_sysdt(1.0)
v=vessel.get_interface('XR2-01')
rs232=require("luars232")
port_name="COM4"



repeat
  alt=oapi.get_altitude()
  mach = v:get_machnumber()
  mach_display=math.floor(10*mach)
  centaine=math.floor(mach_display/100)
  mach_display=mach_display-100*centaine
  dizaine=math.floor(mach_display/10)
  mach_display=mach_display-10*dizaine
  unite=mach_display
  char1=unite+16*dizaine
  char2=centaine
  note:set_text(char2.."  "..char1.."  "..centaine..dizaine..unite)
  if unite~=old_unite then
    send_data(char1, char2)
    old_unite=unite
  end
  proc.skip()
until alt>300000 -- sortie dès qu'on atteint 300 kms d'altitude

note:set_text('Longueur écrite='..len_written)
proc.wait_sysdt(1)


note:set_text('End of program')
proc.wait_sysdt(1)
note:set_text('  ')
proc.wait_sysdt(1)


Le sketch Arduino reçoit les données en boucle, envoyées par le script Lua, et les envoie dans les
registres à décalage pilotant les displays 7 segments par l'intermédiaire des 4553:
Code: [Select]
int dataPin=2;
int latchPin=3;
int clockPin=4;
int data=255;
byte octet1;
byte octet2;



void setup()
  {
    pinMode (dataPin,OUTPUT);
    pinMode (latchPin,OUTPUT);
    pinMode (clockPin,OUTPUT);
    Serial.begin(9600);
  }
 
void loop()
{

    if (Serial.available()>0)
    {
    octet1=Serial.read();
    octet2=Serial.read();
    digitalWrite(latchPin,LOW);
    shiftOut(dataPin, clockPin, LSBFIRST, octet1);
    shiftOut(dataPin, clockPin, LSBFIRST, octet2);
    digitalWrite(latchPin, HIGH);

    }

   delay(150);
}

On lance un SCN contenant l'ordre d'accès au script LUA, et on peut suivre la valeur des Machs
sur les deux afficheurs numériques 7 segments.

Envoyer des données d'Orbiter aux registres de sortie m'est désormais possible. Cela signifie aussi
que je peux synchroniser le simpit avec l'état du Xr2 au lancement du scénario.

Tout ceci est encore assez provisoire et expérimental. Dans mon prochain post, je vous exposerai comment j'ai optimisé ces bouts de code de façon simple.



 
Title: Re: Le tableau de commande de Mars Bleu
Post by: Bibi Uncle on 28 January 2017, 04:38:15
Continue Mars Bleu! Ton projet avance bien et j'adore lire les avancements au fur et à mesure!

Je suis plus ou moins sûr de comprendre la mise en forme que tu fais avant de l'envoyer à l'Arduino. Tu n'aurais pas pu faire un printf (ou la fonction équivalente en Lua, je n'ai jamais programmé avec ce langage) afin d'obtenir un string déjà formatée ? Ensuite, il suffirait d'envoyer les caractères les uns après les autres par UART et voilà. Dans ton code, tu sembles essayer de calculer manuellement les caractères nécessaires alors qu'une fonction standard aurait pu faire le travail à ta place.
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 28 January 2017, 19:44:38
 :salut: Merci, Bibi Uncle pour tes encouragements. :salut:
 J'ai encore plein d'avancements en réserve, tout en continuant à souder, découper, assembler, programmer.

Pour la mise en forme, j'ai fait en mode "artillerie lourde". Pour être plus subtil, j'ai demandé à un de mes fistons de me faire quelque chose, et il m'a pondu un bout de code que je n'ai pas encore eu le temps de
décortiquer. Je te le poste dès que je rentre à la maison (je ne l'ai pas pour l'instant).
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 28 January 2017, 19:58:37
Complément d'information:
Le principe que je mets en oeuvre pour la mise en forme est le suivant: on a besoin de quatre bits
pour piloter un 4553. Quatre bits, c'est un demi-octet, donc, avec un octet, je peux piloter deux
4553. C'est pour ça que je mets les dizaines avec un coeff de 16 (décalage des bits de quatre rangs).
Ainsi, je transmets dizaine et unités dans un seul registre à décalage 74HC595.

Je ne sais pas si je suis bien clair....
Title: Re: Le tableau de commande de Mars Bleu
Post by: Bibi Uncle on 30 January 2017, 19:22:25
Ah d'accord je comprends. Ça me semble légitime comme technique :top:
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 11 February 2017, 19:04:29
J'envoie un dernier chapitre sur la transmission des données entre l'ordinateur et la carte Arduino.
A mes yeux, c'est assez important, c'est pour ça que j'insiste un peu.

En fait, j'ai repris ce qui figure dans mes précédents posts, mais avec un peu de mises en forme,
et de séparation des éléments principaux.

En Lua, on doit en premier lieu ouvrir le port. J'ai appelé cette fonction: widdernixopen()
Code: [Select]
function widdernixopen()
     e,p=rs232.open(port_name)
      if e ~= rs232.RS232_ERR_NOERROR then
  note:set_text('Problème...')
  proc.wait_sysdt(1.41)
              return
      end
  -- set port settings
    assert(p:set_baud_rate(rs232.RS232_BAUD_9600) == rs232.RS232_ERR_NOERROR)
    assert(p:set_data_bits(rs232.RS232_DATA_8) == rs232.RS232_ERR_NOERROR)
    assert(p:set_parity(rs232.RS232_PARITY_NONE) == rs232.RS232_ERR_NOERROR)
    assert(p:set_stop_bits(rs232.RS232_STOP_1) == rs232.RS232_ERR_NOERROR)
    assert(p:set_flow_control(rs232.RS232_FLOW_OFF)  == rs232.RS232_ERR_NOERROR)
end

En deuxième lieu, la fermeture du port:
Code: [Select]
function widdernixclose()
    assert(p:close() == rs232.RS232_ERR_NOERROR)-- this closes the COM
end

Entre les deux (ouverture et fermeture) Lua doit envoyer les données vers Arduino. Elles soit sont contenues dans un tableau, ou bien en valeurs discrètes. Dans le cas d'un tableau, j'ai mis au point:

Code: [Select]
function init_data(data,start,width)
for i=start,width do
high_byte=math.floor(data[i]/256)
low_byte=data[i]-high_byte*256
err,len_written=p:write(string.char(high_byte)..string.char(low_byte))
end
end
J'ai mis dans ce tableau les valeurs donnant la position des auxiliaires dits APU (gear, airbrake,
baydoors, etc...). Cela permet de transmettre leur état, que ce soit en position déployée, rétractée ou intermédiaire, en vue de synchroniser les lumineux pilotés par l'Arduino et l'état logique de  l'engin chargé dans le fichier .scn.

Il y a bien sûr des données additionnelles (de plus en plus, à mesure que le cockpit s'amplifie). Pour les transmettre, j'ai écrit la fonction: init_status()
Pour l'instant, il y a trois valeurs int à transmettre, soit 6 octets supplémentaires:
Code: [Select]
function init_status()

        [color=grey]--envoi sur deux octets de la valeur SIPOstatus contenant l'état des 12 switches APU (dont l'APU lui même)[/color]
high_byte=math.floor(SIPOstatus/256)
low_byte=SIPOstatus-high_byte*256
err, len_written = p:write(string.char(high_byte)..string.char(low_byte))

        [color=grey]--envoi sur deux octets de la valeur SIPOtransit_status contenant l'état de position des 12 auxiliaires APU [/color]
high_byte=math.floor(SIPOtransit_status/256)
low_byte=SIPOtransit_status-high_byte*256
err, len_written = p:write(string.char(high_byte)..string.char(low_byte))

        [color=grey]--envoi sur deux octets de la valeur Miscstatus contenant l'état logique des RCS (OFF/ROT/LIN), ainsi que l'état
        Docké ou non du XR2. Il reste encore 13 bits dispos dans cette valeur[/color]
high_byte=math.floor(Miscstatus/256)
low_byte=Miscstatus-high_byte*256
err, len_written = p:write(string.char(high_byte)..string.char(low_byte))
end

Dans le script Lua, toutes ces fonctions sont appelées par:   
   widdernixopen()
   init_data(position,3,18)—transmission du tableau position[]
   init_status()
   widdernixclose()


Du côté de l'Arduino, , on doit recevoir ce qui est en provenance du sketch Lua. Un tableau de valeurs:

Code: [Select]
for (byte i=3;i<19;i++)
   {
//réception des données envoyées par Orbiter/Lua-----2*16=32 octets--------
      data=get_data(data);
      Pos[i]=data;
   }

Les données additionnelles:
Code: [Select]
//réception des données envoyées par Orbiter/Lua-----2 octets+les 32 déjà extraits---34 octets
    data=get_data(data);
    Switch_status=data;
 
//réception des données envoyées par Orbiter/Lua-----2 octets+les 34 déjà extraits---36 octets
    data=get_data(data);
    Transit_status=data;

//réception des données envoyées par Orbiter/Lua-----2 octets+les 36 déjà extraits---38 octets
    data=get_data(data);
    Miscstatus=data;

La fonction de réception et de transformation en int est:

Code: [Select]
  unsigned get_data(unsigned int value)
  {

    // réception des deux octets:
    byte high_byte=Serial.read();
    byte low_byte=Serial.read();

    //reconstitution de la valeur sur 2 octets
    value=256*high_byte+low_byte;
    return value;
  }//fin get_data()


J'ai dû me pencher sur la fonction réciproque: c'est-à-dire faire envoyer des données de l'Arduino vers Lua. En effet, le buffer d'entrée de la Leonardo ou de la Uno n'est que de 64 octets, ce qui n'est pas beaucoup. Si on a des paquets de données supérieurs à 64 octets, l'idée est de pouvoir envoyer un premier paquet, attendre une réponse, puis d'envoyer la suite.

Pour ce faire, dans le script Lua, j'initialise une variable: data_read="Z", et j'ai écrit une nouvelle fonction, la fonction copythat()
Code: [Select]
function copythat()
read_len=1
err, data_read, size=p:read(read_len)
end


Cette fonction va lire un octet en provenance de la carte Arduino. La valeur data_read ne va plus contenir "Z", mais la valeur envoyée par la carte Arduino, donnant un signal pour remplir de nouveau le petit buffer de l'Arduino avec de nouvelles données.

Voilà, voilà, j'espère que vous n'êtes pas trop :sick: :sick: :sick: :sick: J'ai essayé de faire léger!! :badsmile:

Dans un prochain post, je vous parlerai de l'assemblage de mes modules Parallel Input Serial Output. Il y aura plus d'illustrations!!
Title: Re: Le tableau de commande de Mars Bleu
Post by: jacquesmomo on 12 February 2017, 23:22:19
Voilà, voilà, j'espère que vous n'êtes pas trop :sick: :sick: :sick: :sick: J'ai essayé de faire léger!! :badsmile:

(http://img11.hostingpics.net/thumbs/mini_414692Tetemalade.gif)
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 12 February 2017, 23:49:13
 JacquesMomo:
Quote
(http://img11.hostingpics.net/thumbs/mini_414692Tetemalade.gif)

J'aime bien la Coccinelle, même quand elle est vaseuse! :)
Et aussi les smiley "hors forum" que tu nous déniches
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 28 February 2017, 09:09:55
CINQUIÈME CHALLENGE: construire les cartes PISO et les circuits d'élaboration de signal

Etant donné le nombre de raccourcis clavier du Xr2, et la nécessité d'être à l'aise, j'ai assemblé deux cartes, l'une supportant six circuits 74HC165, et l'autre douze circuits 74HC165. Cela me donne une capacité de traitement de 8x18=144 switches et boutons poussoirs.
Associées à ces deux cartes, les circuits d'élaboration de signal permettent d'envoyer 0 ou 5volts aux entrées des 74HC165:
                                (http://img11.hostingpics.net/pics/559925Elaborationsignal.jpg)Pas pu faire mieux pour le shéma...

Si l'interrupteur est ouvert, pas de tension, la sortie Signal PISO est à zéro volts.
Si l'interrupteur est fermé, on a 5 volts aux bornes de la résistance, parcourue par un courant de 0.5 mA. La sortie Signal PISO est à 5 volts.

Assembler de telles cartes est plus vite écrit que fait, car c'est un travail minutieux de soudage et, surtout, de vérifications (câblage correct, continuités électriques). Du boulot de neurochirurgien. Tout n'a pas été évident dès  le départ et il a fallu faire des changements d’organisation en cours de route.

Ensuite, une fois toutes les vérifications effectuées, j'ai fait les premières mises sous tension. Bien entendu, rien ne marchait comme prévu. De plus, en cas de disfonctionnement, il faut toujours se poser la question: est-ce mon montage, ou bien le programme qui l'anime?

Ci-dessous, la carte à douze 74HC165 et quatre groupes de 24 circuits d'élaboration de 5 volts. On relie l'ensemble avec des nappes à 26 pôles.

                (http://img15.hostingpics.net/pics/767800CartesPISOetsignal.jpg)

Une fois ce montage effectué, je me suis aperçu qu'il fallait installer les prises 26 pôles sur le fond du module, afin de pouvoir brancher/débrancher plus facilement. J'ai donc rajouté le petit panneau du fond, et les câblages qui vont bien (là, c'est mon montage à six 74HC165):

                (http://img11.hostingpics.net/pics/267558ModulePISO.jpg)

Une fois repliées, les deux platines forment un module que je peux installer dans un rack de hauteur 3U.
Si les modules dont on a besoin ne tiennent pas dans un seul rack, on peut en empiler autant qu'on veut pour faire une baie qu'il faudra ventiler.

Dans la mise au point de mes cartes PISO, j'ai eu pas mal de galères qui consistaient essentiellement en des soudures sèches (ne laissant pas passer le courant). J'ai eu aussi un tout petit morceau de métal qui s'était coincé entre une piste 5 volts et une autre piste LATCH. LATCH étant toujours à HIGH, plus moyen de lire les registres qui restaient verrouillés en permanence. J'ai passé un Dimanche après midi dans son entièreté à chercher avant de finir par trouver.
Ce n'est pas parce qu'une carte fonctionne correctement toute seule qu'elle marchera correctement associée à une autre carte du même type. Par exemple, si l'on inverse LATCH et CLK sur deux cartes, le fonctionnement des deux cartes va être parfaitement erratique.

Attention au sens de montage des circuits intégrés. A la mise sous tension, le fusible 5 volts a sauté immédiatement. Une mesure d'intensité avec un seul circuit 74HC165 a donné 2,4 Ampères! Après investigation, je me suis rendu compte que je les avais mis à l'envers sur leur support. Une fois tout remis comme il fallait, l'intensité absorbée était infiniment moins importante, tout à fait compatible avec le calibre du fusible.

Une fois mes 18 registres PISO correctement câblés, il a fallu mettre en place le sketch Arduino pour cadencer la scrutation des 144 entrées, et mettre les valeurs binaires associées dans un tableau[ ] afin de pouvoir les exploiter. (Cf #17)

Title: Re: Le tableau de commande de Mars Bleu
Post by: Kerguelen on 01 March 2017, 14:25:58
Jolie travaille ! Je soutiens ton projet, j'avais une idée un peu semblable pendant une certaine période mais, décidément, j'imagine que mon apprentissage en elec n'est pas assez poussé ahah...  :???:
Bon courage pour la suite!  :top:
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 01 March 2017, 19:17:00
 Merci, Kerguelen, et bienvenue sur le fofo! :beer:
J'alimente ce fil pour donner des idées aux "simpinautes".

Quote
Bon courage pour la suite!  :top:
Oui, des fois, ya besoin. En ce moment, je peine sur des circuits
comprenant des encodeurs rotatifs.
Title: Re: Le tableau de commande de Mars Bleu
Post by: nulentout on 14 March 2017, 11:57:52
Hé bé, tout ce PATAKÈSSSS me rappelle l'époque où je créais mon propre tableau de bord. Disposer de 255 entrées/sorties posait les mêmes problèmes de connectique et surtout d'encombrement. Je vois que notre copain avance de façon magistrale, et je m'en réjouis. Il démontre une fois de plus le plaisir qui émerge forcément d'un projet aussi ambitieux, quand on arrive à faire "tourner" des solutions qui après coup peuvent sembler à certains évidentes, mais qui imposent au concepteur des heures de recherche.  :wall:
Félicitations cher copain, tes élucubrations vont certainement inciter des internautes à te suivre sur cette voie passionnante de la création.  :wor: Chapeau bas ... je le pense vraiment : Môamôa.
Title: Re: Le tableau de commande de Mars Bleu
Post by: jacquesmomo on 14 March 2017, 14:36:09
200 ème karma pour Nulentout (donné par moi !)  :badsmile: Bien mérité !!!
Title: Re: Le tableau de commande de Mars Bleu
Post by: nulentout on 14 March 2017, 16:50:56
HHHYYYYYOOOOUUUUUPPPPPYYYYYY, ça fait un compte rond !
Plus que 32 de retard, je vais te rattraper à donf Môamôa !  :flower:
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 14 March 2017, 18:43:27
Merci à tôatôa, Nulentout pour ton élogieux #37.
Et aussi:
Quote
...quand on arrive à faire "tourner" des solutions qui après coup peuvent sembler à certains évidentes, mais qui imposent au concepteur des heures de recherche.  :wall:

Ah oui, alors; je viens de passer un mois de recherches pour une solution technique( :rant: :wall: :rant: :wall: :rant:) . Et, enfin
                                          :youpie: :youpie: j'ai pu aboutir! :youpie: :youpie:
                                                                Ça fait du bien!

Du coup, ça va me faire une réserve supplémentaire d'"élucubrations" que je vous garde bien au chaud
avant de servir...

Et puisqu'on parle de karmas, voici pour Nulentout (comme ça, plus de compte rond avant 300 :), eet aussi pour Jacquesmomo, un autre karma. Làààà...
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 17 March 2017, 20:01:47
Il est grand temps de continuer mes élucubrations: on s'accroche, les gars!

Avant de parler des modules SIPO, il faut que j'évoque l'ensemble des servitudes liées à la bonne marche de mon environnement. Il fallait bien sûr que ces servitudes soient mises en rack, tout comme les autres modules.


                PREMIÈRE SERVITUDE: L'ALIMENTATION ELECTRIQUE

Dès que j'ai eu plus d'un module à alimenter électriquement, j'ai vu qu'il fallait une alimentation électrique digne de ce nom. Il me fallait du 5 volts pour les modules PISO et SIPO, et du 8 volts pour la carte Arduino. J'ai trouvé que la meilleure alim était celle d'un PC, qui fournit du 5 volts et du 12 volts. Il a simplement fallu changer la petite prise fournissant le 12v et le 5v afin de pouvoir connecter cette alim de PC à mon répartiteur d'alimentation.

Le 12 volts passant par un L7808 est mis à 8 volts, ce qui est tout à fait convenable pour alimenter la carte Arduino.

J'ai utilisé une plaque 100x160 mm à bandes de cuivre pour pouvoir faire une bonne répartition du 5 volts pour chacun de mes modules. J'ai bien sûr installé des fusibles tant pour le 5 volts que pour le 12 volts. A juste raison, car il est arrivé souvent que je les transforme en chaleur et en lumière…

(http://img4.hostingpics.net/pics/288965DSC0565.jpg)

Leur emplacement est à revoir, car situés sur la carte, il faut tout débrancher et extraire la carte du rack pour pouvoir les remplacer. Je songe à des porte-fusibles en face avant.

Pour avoir une référence de clignotement de environ 1hz, et aussi me donner la possibilité de multiplexage, j'ai réalisé des petits circuits oscillants avec des 555. Le 1hz servira à piloter le clignotement de certaines leds, en fonctions des besoins. Le but étant de simplifier le sketch tournant dans l'Arduino. J'ai installé cette petite carte sur la carte d'alimentation pour gagner de la place dans mon rack.

Pour la face avant des modules, j'ai fait des projets que je voudrais faire réaliser en fablab, avec gravure laser, de façon à faire du rétroéclairé. Mais ça sera traité plus tard...

Dans un prochain post je vous expliquerai comment j'ai installé la petite carte Uno, (remplacée ensuite par une Leonardo) dans mon rack.
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 09 April 2017, 19:37:24
Scusez, j'ai pas eu le rythme, ayant dû m'éloigner  quelques jours....

Il est temps d'aborder la....

                   DEUXIÈME SERVITUDE: LE SUPPORT POUR LA carte Arduino.

On peut y installer indifféremment une UNO ou une Léonardo. L'avantage de la Léonardo est qu'elle permet
d'envoyer des caractères sans configuration particulière, contrairement à la UNO.


J'avais donc besoin d'un support facile à utiliser pour la Leonardo, qui est assez petite. J'ai trouvé une solution qui m'a a parue pratique, en soudant des broches sur une plaque 100x160 à pastilles de cuivre aux bons endroits pour pouvoir enficher la Leonardo dessus. Ça forme un module que je peux ensuite installer dans mon rack.

Les broches au-delà de la broche 13 m'on donné du fil à retordre, car l'espacement par rapport aux autres broches n'est pas du 2,54 mm.
Il restait à réaliser le câblage rampant et à souder les connecteurs pour relier la Leonardo à son alimentation électrique et aux modules supportant les registres à décalage.

Sur la face avant de ce module, j'ai mis, outre des leds matérialisant la présence du 5 et 8 volts, des groupes de leds pour LATCH, CLK et DATA SIPO/PISO, figurant la circulation des données et la pulsation commandant les registres. Pour ralentir tout cela afin de le rendre visible, j'ai ajouté six circuits décompteurs CD 4020 dans un coin de la carte supportant la Léonardo.

                           Ci dessous, la carte supportant le microcontrôleur Arduino:
(http://img4.hostingpics.net/pics/886776DSC0566.jpg) (http://www.hostingpics.net/viewer.php?id=886776DSC0566.jpg)

Les fils bleus sont DATA, jaunes=>LATCH, gris=>CLK. J'ai choisi ces couleurs au hasard, mais je m'y tiens.


Dans un prochain post, je reprendrai le cours de mes constructions en vous parlant de mes modules SIPO, utilisant des 74HC595, afin de multiplier les sorties. Bonne lecture!
Title: Re: Le tableau de commande de Mars Bleu
Post by: antoo on 09 April 2017, 20:39:07
Génial!
Title: Re: Le tableau de commande de Mars Bleu
Post by: jacquesmomo on 09 April 2017, 23:00:59
Captivant.... (chuis jaloux !)  :badsmile:
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 10 April 2017, 20:19:18
Merci, les gars. Ça fait plaisir d'avoir du retour. Je vois aussi le compteur des vues qui tourne,
donc il y a du monde qui vient voir, même s'il ne dit rien.

J'ai trouvé un site qui permet de dessiner des schémas en ligne. C'est : https://easyeda.com/ (https://easyeda.com/)
Je le trouve bien fait. Il faut juste ouvrir un compte si on veut sauvegarder ses créations.
Ça va me permettre de documenter tous mes circuits.

Allez, je retourne à la préparation de mes élucubrations.... :prof:
Title: Re: Le tableau de commande de Mars Bleu
Post by: jacquesmomo on 10 April 2017, 23:18:53
Merci, les gars. Ça fait plaisir d'avoir du retour. Je vois aussi le compteur des vues qui tourne,
donc il y a du monde qui vient voir, même s'il ne dit rien.
Voui, je suis tout ça...

C'est bien qu'il y ait encore des passionnés comme toi (et nous) car il me semble que ça devient plus rare....  :(
Title: Re: Le tableau de commande de Mars Bleu
Post by: antoo on 11 April 2017, 14:40:10
Ouép, je confirme. Ça s'endort un peu...
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 11 April 2017, 18:57:56
C'est un peu pour ça que je me suis décidé à partager l'ensemble de mes travaux:
pour donner envie, avec quelques solutions techniques qui peuvent être autant de
pistes de réflexion pour faire mieux.
Faisons vivre Orbiter avec de beaux add-on et/ou de belles réalisations!!
Title: Re: Le tableau de commande de Mars Bleu
Post by: jacquesmomo on 12 April 2017, 00:16:24
 :eek: C'est mon avis et je le partage !!!!
Title: Re: Le tableau de commande de Mars Bleu
Post by: antoo on 12 April 2017, 10:59:12
C'est top que tu partages tout ça! Avec notre simu Apollo, on avance tranquillement, on vous mettra des infos avant l'été :eek: .
A+
Title: Re: Le tableau de commande de Mars Bleu
Post by: nulentout on 12 April 2017, 16:36:09
Elles sont belles tes cartes électroniques, visiblement tu aimes le travail bien fait.  :top:
La réussite sera forcément la conclusion de ton entreprise avec la satisfaction qui va avec ...
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 12 April 2017, 22:37:45
@Antoo: simu Apollo? J'ai hâte de voir. Ça doit être bien pointu, ça.
Ce qui m'intéressera particulièrement de voir, ce sont les commandes qui n'ont pas
de raccourci clavier.
@ Nulentout: merci! Et, oui, j'essaie de faire de mon mieux, en utilisant
mon expérience professionnelle passée. Quelque chose de bien organisé
est clair et dépannable. Je devrais y arriver, même si, parfois, je galère un
peu. (En ce moment, je bute toujours sur mes roues codeuses...)
Title: Re: Le tableau de commande de Mars Bleu
Post by: antoo on 13 April 2017, 01:03:20
Quote
Ce qui m'intéressera particulièrement de voir, ce sont les commandes qui n'ont pas
de raccourci clavier.
C'est en effet le plus gro défi... et je me réjouis de vous dire que ça le fait :turning:. On vous partagera tout ça quand on aura trouvé de quoi imprimer un EMS en ABS. Il est question de faire un mod, qui prend cela en charge. N'hésite pas à demander si tu veux plus d'infos ;) .

A+
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 13 April 2017, 16:06:57
 :top: :top: :top:
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 29 April 2017, 12:37:17
Voici la suite de mes élucubrations, avec le.....
                                        SIXIÈME CHALLENGE: construire les cartes SIPO

Tout comme les modules PISO, il y a un gros travail de soudure, de vérification des continuités électriques, de vérification d'absence de court-circuit, du sens de montage des circuits intégrés, du bon fonctionnement en général. Pour l'instant j'ai monté trois modules SIPO, ce qui me donne la possibilité de piloter 8x12x3=288 sorties.
Pour le premier module, j'ai soudé les 96 résistances de 330Ω sur la plaque ne supportant pas les registres SIPO.

(https://img4.hostingpics.net/pics/363380DSC0564.jpg) (https://www.hostingpics.net/viewer.php?id=363380DSC0564.jpg)


L'expérience montre que ça multiplie les connecteurs, et donc complication et temps passés: à éviter. Je recommande donc de mettre les résistances en série avec les leds directement sur la carte où se trouvent les leds.
Voilà le module SIPO simplifié:

(https://img4.hostingpics.net/pics/824809DSC0528.jpg) (https://www.hostingpics.net/viewer.php?id=824809DSC0528.jpg)

Je mets la petite plaque ci-dessous au cul de la led, en faisant attention au sens de branchement. Pas brancher en direct les leds à la sortie des 74HC595 sinon, led fichue, mais ça vous le savez déjà.

(https://img4.hostingpics.net/pics/863179SupportLED.jpg) (https://www.hostingpics.net/viewer.php?id=863179SupportLED.jpg)

Pour la mise au point, j'ai bien sûr, commencé avec une seule série de 12 registres 74HC595, puis avec deux, et enfin avec les trois séries de 12 registres.
Avec deux séries de registres, j'ai commencé à avoir des problèmes de transmission de DATA à travers l'ensemble des 74HC595. J'ai équipé l'ensemble des 74HC595 de capas de découplage de 1μF entre Vcc et GND, mais je n'ai pas obtenu d'amélioration. En fait, la solution venait par l'agencement des câbles CLK et LATCH: je faisais passer de module en module les fils CLK et LATCH, alors qu'il fallait à chaque fois partir de la carte de support de la UNO. Cette modification de câblage effectuée, il n'y a plus eu de problème dans mes registres SIPO.

La fonction de remplissage des registres a été montrée plus haut. Si on doit rajouter des registres, parce que 288 sorties ne sont pas suffisantes, il faut juste changer la valeur de NumberSIPOreg à la déclaration des variables, afin de l'ajuster au nombre de 74HC595.

Je vous laisse profiter de tout ça. La suite, ça va être de voir comment on initialise tout ça en soft. Amateurs de C, préparez vous!!
Title: Re: Le tableau de commande de Mars Bleu
Post by: antoo on 29 April 2017, 12:56:12
Quel travail de pro! Bravo :top: !
Title: Re: Le tableau de commande de Mars Bleu
Post by: jacquesmomo on 30 April 2017, 00:07:56
Bravo pour le "rangement" des fils et connecteur ! comme le dis antoo : travail de pro...
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 30 April 2017, 15:50:55
Merci, les gars, ça fait toujours plaisir de lire de tels posts.
Maintenant, faut voir la table où je monte tout ça, c'est assez
fouillis (c'est le principe entropique!  :blbl:).
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 16 May 2017, 22:55:58
                          :hurle: Et voici la suite de mes élucubrations! :hurle:

J'ai donc obtenu un système à 144 entrées et 288 sorties. On va pouvoir aborder la programmation de l'initialisation du cockpit en ce qui concerne les auxiliaires fonctionnant avec l'APU. Sur le Xr2, c'est :

   -Gear                            -Airbrakes
   -Radiator                       -Hatch
   -Retrodoors                   -Hoverdoors
   -Scramdoors                  -Baydoors
   -Innerdoor                     -Chamber (ici, pas de raccourci clavier)
   -Outerdoor                    -Nosecone
             Et enfin, l'APU.



Au total 11 auxiliaires dont il faut connaître l'état, et la position. Chamber est un cas particulier, car on n'a pas de raccourci clavier pour la gestion de ce paramètre. APU aussi, car il commande tout le reste, et on ne tient pas compte du temps d'un éventuel démarrage ou arrêt à l'initialisation. (Constatation faite sur le terrain)

L'idée étant d'avoir un code aussi compact que possible, le mieux a été de stocker les états des auxiliaires dans des unsigned int codés sur deux octets, soit 16 bits. En donnant un poids à chaque marqueur d'auxiliaire, on part du MSB pour l'APU, et on descend en poids. Treize bits vont être nécessaires, et on va avoir trois bits disponibles (les trois LSB)

Plusieurs variables vont être nécessaires, car on doit savoir si chaque auxiliaire est à l'arrêt/fermé, en cours de démarrage/ouverture, démarré/ouvert, ou en cours d'arrêt/fermeture, soit quatre possibilités. Or dans les scn, on a:

                                   Valeur scn          Valeur scn en binaire       Transit_status      Switch_status

Arrêté/Fermé                        0                              00                          0                        0
Démarrage/Ouverture           3                              11                          1                         1
Démarré/Ouvert                   1                              01                          0                         1
Arrêt/Fermeture                   2                              10                          1                         0

On voit qu'on peut tirer de ce petit tableau deux valeurs: Transit_status qui va caractériser le mouvement et Switch_status qui va caractériser un ordre: ouvert/déployé ou fermé/replié. On élabore  Transit_status et Switch_status en fonction du poids donné à chaque auxiliaire. Par exemple, pour l'APU en marche, c'est le MSB de Switch_status qui sera positionné à 1.

Toujours pour la compacité du sketch Arduino, j'ai choisi de mesurer une durée avant fermeture complète. La position d'un auxiliaire va être comptée en millisecondes avant la fermeture complète, et c'est la valeur transmise par le script Lua à partir d'une règle de trois tenant compte de la valeur comprise entre 0 et 1 trouvée dans le scn, et de la durée de transit total refPosition[ ] en millisecondes de l'auxiliaire considéré (par exemple, 6.7 secondes, soit 6700 ms pour Gear => valeur fournie par la doc du Xr2).
La durée de transit la plus longue est celle du radiateur, qui est de 32 secondes, soit 32000 ms, ce qui est inférieur à la valeur max de 65535 (les 16 bits d'un unsigned int à 1)

La séquence d'initialisation doit attendre un flux d'octets en provenance du script Lua. Ce flux doit bien sûr être élaboré selon un protocole bien précis. Dans ce but, le script Lua envoie au port USB les éléments du tableau des positions d'auxiliaires, plus les deux derniers éléments contenant respectivement Transit_status et Switch_status. Du côté Arduino, les données arrivent dans le buffer d'entrée (24+2+2=28 octets), et sont chargées dans un tableau Position[3 à 14], plus les valeurs Transit_status, et Switch_status.

Les 28 (ou plus) octets sont envoyés par le script Lua (ce sont les fonctions "widdernix"=>voir le#31).

La carte Arduino réceptionne ces données, et connaît donc la position et l'état des auxiliaires.

C'est tout pour aujourd'hui: bonne digestion!!! Et pas de  :sick:, ni de  :arg: et encore moins de  :wall: dans le fond!

                          Si vous avez des questions, je suis là pour vous renseigner avec plaisir.

Dans un prochain post, j'expliquerai comment le sketch Arduino traite les données réceptionnées, afin de synchroniser le cockpit avec le scénario chargé.



Title: Re: Le tableau de commande de Mars Bleu
Post by: antoo on 17 May 2017, 06:49:02
Cool :top: !
Title: Re: Le tableau de commande de Mars Bleu
Post by: jacquesmomo on 18 May 2017, 19:16:43
(https://www.surlatoile.com/smileys/repository/Respect/respect-chapeau.gif) hébédisdonc....
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 18 May 2017, 22:23:39
Merci les gars pour votre présence. Ça me soutient et m'encourage pour
expliquer le déroulé de la conception de mes montages.
Title: Re: Le tableau de commande de Mars Bleu
Post by: antoo on 18 May 2017, 22:39:54
Avec plaisir l'ami. On attend la suite avec impatience :) !
Title: Re: Le tableau de commande de Mars Bleu
Post by: Gingin on 20 May 2017, 10:07:24
Wow, très solide aussi de ce coté là .  :beer:
Tes explications sont intéressantes, je n'y connais pas grand chose dans ce milieu, et ca me pousse à aller m'informer un peu plus sur tous ca.

Chapeau en tout cas. Est ce déjà opérationnel en partie?
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 20 May 2017, 16:12:49
@Gingin: Oui, oui. Tout ce que je décris est fonctionnel. Les auxiliaires fonctionnant avec la
marche de l'APU, le gimbal des moteurs, le COG (center of gravity) sont gérés. Le contrôle d'attitude
de l'engin également(RCS LIN et ROT, Undock); c'est bien pratique pour les appontages en orbite.
Pour l'instant, je travaille sur le contrôle des pilotes auto. Ça n'avance pas très vite, car je fais
des modifs en permanence, afin de m'adapter aux caprices de l'électronique. Mais ça avance...

J'ai aussi à faire les plans à partir du site  https://easyeda.com/
pour m'y retrouver plus tard pour dépannage ou modif.

Plus voir avec un fablab pour me faire des faces avant rétroéclairées qui soient un peu jolies.

Et pour montrer le fonctionnel, éditer quelques vidéos. Programme chargé!
Title: Re: Le tableau de commande de Mars Bleu
Post by: Gingin on 21 May 2017, 09:24:30
Super  :top: :top:

Tu as des photos des faces rétro éclairées?
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 02 June 2017, 17:48:38
Désolé de te décevoir, mais pour l'instant, je n'ai pas de faces rétroéclairés.  :sad:
C'est encore à l'état de projet, sous forme de dessin vectoriel.
Je suis en mode provisoire, avec des bouts de contreplaqué percés pour y installer 
les divers switches et autres boutons-poussoirs.

      :explique: De patience, preuve tu dois faire!  :explique:
Title: Re: Le tableau de commande de Mars Bleu
Post by: jacquesmomo on 02 June 2017, 23:59:13
:explique: de patience preuve nous ferons... :explique: :hot: impatient moi je suis de voir...
 :badsmile:
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 05 June 2017, 08:22:30
Pour les :hot: impatients :hot:
Ça fait quelque chose comme ça:

(https://img15.hostingpics.net/pics/614221APUfull.jpg) (https://www.hostingpics.net/viewer.php?id=614221APUfull.jpg)

Quelques explications:
Le rectangle situé sous "APU fuel" sera découpé, afin de laisser voir quatre afficheurs 7 segments
donnant la quantité d'APU fuel restante en pourcentage du plein.

Les cercles "mismatch" sont des leds rouges de discordance allumées en cas de différence entre l'état
logique de tel ou tel auxiliaire, et la position du switch correspondant. En cas de discordance, manœuvrer
le switch l'alignera sur l'état logique de l'auxiliaire considéré. Le but étant qu'à l'initialisation, on éteigne
toutes les discordances par la manœuvre des switches discordants.

La rangée de cercles située immédiatement en dessous est de couleur jaune, tandis que la suivante
sera verte, indiquant la position "rentrée atmosphérique": tout est vert, tout est clair.

Enfin, la rangée de cercles inférieure correspond au passage des switches de commande.

Je n'ai pas de calendrier précis pour la confection d'un tel synoptique... C'est qu'il y a énormément à faire par
ailleurs, surtout dans la confection du câblage des cartes.
Title: Re: Le tableau de commande de Mars Bleu
Post by: antoo on 05 June 2017, 13:35:37
Ulta stylé ! En gros tu nous fais un XR2 complet quoi :) !
T'as plus qu'à chercher une vieille carlingue de A-6E americain :badsmile: (chasseur 2 places un peu comme le xr2 ...) .

A+
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 05 June 2017, 14:26:09
Ouais, mais mon épouse y trouverait à redire :badsmile:
Déjà qu'elle rouspète gentiment quand elle s'approche
de ma table atelier...
Mais c'est vrai que ça serait bien. Il y aurait moyen de prendre un passager, et on aurait
des belles tenues de vol! ( Spacesuit-casque-gants pour les décollages et rentrées; combi bleu
NASA pour la croisière)
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 11 June 2017, 14:11:17
 :explique: Dans le #59, j'élucubrais que dans un prochain post, j'expliquerai comment le sketch Arduino traite les données réceptionnées, afin de synchroniser le cockpit avec le scénario chargé.
Cela consiste à la....

                                                        Gestion des leds des auxiliaires APU



Un auxiliaire APU en mouvement doit être caractérisé par le clignotement de sa led associée: verte pour repli/fermeture, jaune pour déploiement/ouverture. Afin d'éviter de coûteuses et compliquées lignes de commandes dans le sketch, j'ai choisi d'utiliser le 1hz dont j'ai déjà parlé. Ce 1hz élaboré à partir d'un 555 est connecté à une entrée de la UNO, et va être exploité dans le sketch par une fonction booléenne ET.

Dans Orbiter, les switches ne sont pas concrets. A l'initialisation du simpit, les vrais switches peuvent se retrouver en discordance par rapport à l'état logique (issu du scn) du vaisseau. J'ai choisi de monter des leds rouges clignotantes qui vont être activées en cas de XOR entre l'état des switches, et celui du vaisseau dans Orbiter. Ces leds sont aussi activées en cas de manœuvre switch alors que l'APU est arrêté.

Si une discordance apparaît, la manœuvre du switch associé fait disparaître cette discordance: on aligne le cockpit sur l'état du vaisseau issu du scn Orbiter.

En résumé, à chaque switch va être associé un groupe de trois leds: verte (replié/repli), jaune (déployé, déploiement), et rouge (discordance).
                  Les leds vertes sont associées à PISOreg[0]
                  Les leds jaunes sont associées à PISOreg[1]
                  Les leds rouges sont associées à PISOreg[2]


Plutôt que de traiter chaque switch séparément, j'ai préféré traiter l'ensemble des données unsigned int avec des bitwise. Cela permet d'éviter tout un tas de if...else if , et de faire un code compact. Après bien des essais et mises au point pour tenir compte de toutes les possibilités, j'ai obtenu:

    Mismatch_status=(PISOreg[0]^Switch_status);//élaboration des discordances entre l'état logique et physique du simpit
    APU_mismatch=(Transit_status&(65535*(Position_APU==0)));//élaboration des discordances liées à un mvt de switch alors que APU indisponible
    SIPOreg[0]=((~Switch_status&~Transit_status)|(Transit_status&Onehz))&(~Switch_status);// Gestion des leds vertes
    SIPOreg[1]=((Switch_status&~Transit_status)|(Transit_status&~Onehz))&(Switch_status);//   Gestion des leds jaunes
    SIPOreg[2]=Mismatch_status|APU_mismatch;// Gestion des leds rouges
    survey_Position();// envoi à la gestion des fin de course des auxiliaires APU     




Nota:   & correspond à l'opérateur booléen AND
           |  correspond à l'opérateur booléen OR
          ~ correspond à l'opérateur booléen NOT
          ^ correspond à l'opérateur booléen XOR


Pour produire ces petites équations logiques, il a fallu que je revoie mes notions sur les tableaux de Karnaugh, de lointains souvenirs…

Ces quelques lignes de codes placées dans un boucle d'initialisation permettent aux valeurs Switch_status et Transit_status envoyées par le script Lua et reçues par le sketch Arduino  de commander dans un premier temps l'allumage des 3x13=39 leds du panneau auxiliaires APU.


Nous verrons plus tard comment tenir compte de l’écoulement du temps afin faire rendre compte au panel de la variation de l'état des auxiliaires APU.
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 01 July 2017, 09:57:11
Il est grand temps de vous expliquer comment je m'y suis pris pour tenir compte de l'écoulement du temps dans le mouvement des auxiliaires animés par l'APU.

En effet, il se peut que le scénario comprenne des mouvements d'auxiliaires en cours. Il faut donc mettre à jour les états des leds pour tenir compte de l'évolution de la situation. C'est la raison d'être de la fonction survey_Position();

Cette fonction va, entre autres, comparer bit à bit l'état de Switch_status et Transit_status, afin de déterminer si l'auxiliaire associé est en fermeture/fermé ou en ouverture/ouvert. Selon le cas, on va incrémenter ou décrémenter la valeur Position[ ] jusqu'à ce qu'on arrive à une valeur de "fin de course", égale à zéro ou bien à refPosition[ ].


for (byte rank=3;rank<15;rank++)                   // Nota:la marche de l'APU devra aussi être liée au niveau de carburant APU
    {
      if ((bitRead(Switch_status,rank)==1)&(bitRead(Transit_status,rank)==1))
      {                //  si auxiliaire en ouverture
       Position[rank]=Position[rank]+((millis()-mem_time)*(APUrunning*(bitRead(interswitch_control, rank))));//incrémentation: on est en ouverture, à la condition que APU soit en fonction
        if (Position[rank]>(refPosition[rank]-50))//si dépassement position(à 50 ms près),...
        {
          Position[rank]=refPosition[rank];// ...recalage à la valeur max
          bitClear(Transit_status,rank);//marque la fin du mouvement. 
        }//endif
      }//endif
      if ((bitRead(Switch_status,rank)==0)&(bitRead(Transit_status,rank)==1))
      {                //si auxiliaire en fermeture
        Position[rank]=Position[rank]-((millis()-mem_time)*(APUrunning*(bitRead(interswitch_control, rank))));//décrémentation: on est en fermeture, à la condition que APU soit en fonction
        if (Position[rank]<50)// on est à 5/100° de seconde de la fermeture; c'est pour éviter de passer <0 car on est en "unsigned int"
        {
          Position[rank]=0;//si dépassement position, recalage à la valeur min, c a d zéro
          bitClear(Transit_status,rank);//marque la fin du mouvement.
        }//endif
      }//endif      
    }//"next rank, on passe au mouvement de l'auxiliaire suivant"



Pour rappel, le tableau Position[] contient une valeur numérique unsigned int étant une distance temporelle en ms de la position fin de course basse de l'auxiliaire APU désigné par rank.
Le tableau refPosition[] contient les valeurs en ms de durée de transit total entre fin de course basse et fin de course haute de chaque auxiliaire. Ce tableau est essentiel pour connaître le moment où un auxiliaire est complètement ouvert ou déployé. Pour l'état rétracté ou fermé complètement c'est la même valeur pour tout le monde: zéro. Pas la peine de faire un tableau pour ça. :badfinger:

La valeur(millis()-mem_time) mesure l'intervalle de temps écoulé entre deux passages dans la boucle.

Vous aurez aussi remarqué la valeur interswitch_control. Elle sert à autoriser ou inhiber en dernier ressort un mouvement. En effet, nous savons que si le Xr2 est posé au sol sur son train d’atterrissage, on ne peut pas le replier. De même, si nosecone fermé, pas d'ouverture possible de outerdoor. D'où interswitch_control.

Une fois tous ces calculs faits, on envoie le contenu de SIPOreg[0 à 2] dans les registres par la fonction déjà évoquée, updateRegister(SIPOreg);  c'est une mise à jour des registres à décalage de sortie: on rafraîchit l'affichage de toutes les leds APU.
Tout ceci n'est qu'un début, qui ne s'est pas mis au point tout à fait facilement. Mais un des principaux obstacles qu'était la synchronisation du cockpit avec le fichier scn a été surmonté. J'ai essayé toutes les configurations de départ possibles, y compris celles les plus improbables, et je n'ai pas réussi à prendre en défaut mes algorithmes pour l'instant.

Mais on n'est pas encore au bout de nos peines: il faut encore pouvoir envoyer un raccourci clavier (ou non) à chaque mouvement de switch. Ça a l'air simple comme ça, mais c'est plus compliqué qu'il n'y paraît.

 :explique: Bonne lecture, en attendant la suite!! :salut:
Title: Re: Le tableau de commande de Mars Bleu
Post by: antoo on 01 July 2017, 13:56:17
Intéressant!

A+
Title: Re: Le tableau de commande de Mars Bleu
Post by: jacquesmomo on 03 July 2017, 08:19:37
(...)
 Ça a l'air simple comme ça, mais c'est plus compliqué qu'il n'y paraît.
:trucdeouf: hébé...
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 03 July 2017, 08:39:34
@ Jacquesmomo, ne t'inquiètes pas, si j'ai réussi à faire fonctionner tout ça,
alors tout le monde peut le faire!!

@Antoo,  j'espère que ton projet avance bien.

@ tous les lecteurs, j'espère que la balade vous plaît.
Title: Re: Le tableau de commande de Mars Bleu
Post by: antoo on 03 July 2017, 21:14:32
Quote
@Antoo,  j'espère que ton projet avance bien.

Oui, vous aurez des news serieuses et photos demain soir :) .
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 08 October 2017, 19:25:12
Il est grand temps que je continue d'exposer mes élucubrations, les dernières exposées ici remontant à une date déjà
lointaine. C'est que cet été, je n'ai pas eu tellement de plages temporelles propices pour développer, ni faire des
montages électroniques.
Par dessus le marché, lorsque j'ai voulu démarrer mon système, plus grand chose ne fonctionnait. C'était assez
frustrant. Maintenant que j'ai repris la main, je peux continuer.

Je vous parlais dans un précédent post de....

          Envoi de raccourcis clavier par mouvement de switch ou bouton poussoir

La UNO ne pas être vue comme un clavier sans quelques dispositions préalables. Voir les posts de Hysot à ce sujet. La librairie HIDKeyboard doit être "included". La doc qui l'accompagne montre l'utilisation par envoi de chaîne de caractère direct: par exemple,  keyboard.pressKey (CTRL, "a").

Mais je ne voulais pas avoir une structure pleine de if{}/else{}, ni de switch/case. Pour ça, il fallait faire un tableau, et utiliser la commande keyboard.pressKey() avec des paramètres.

Après quelques recherches et essais pas toujours réussis, j'ai fini par mettre au point le bout de code suivant:

En en-tête pour charger la librairie:

# include<HIDKeyboard.h>
HIDKeyboard keyboard;


Dans les déclarations:

const byte XrModifier[]={0,0,0,0,1,4,1,1,1,1,1,4,0,1,1,1};
const char XrKey[]={32,32,32,103,98,114,121,92,118,103,117,111,32,111,107,97}


XrModifier[] contient les caractères de contrôle: 0, pas de caractère de contrôle
                       1 correspond à CTRL
                       4 correspond à ALT

XrKey[] contient les codes ASCII des lettres à envoyer pour correspondre aux raccourcis clavier.

Le bout de code formant la fonction:

void keyboard_command(byte start, byte offset, unsigned int command);
{
   for( byte i=start;i<16;i++)
      {
         if(bitRead(command, i)==1)
            {
               keyboard.pressKey(XrModifier[i+offset], XrKey[i+offset];
               temporelease();
            }
      }
}


 Pour les raccourcis APU, cette fonction est appelée par:

keyboard_command(3,0,(PISOreg[0]^previousPISOreg[0]));


J'ai inséré cette fonction dans le programme principal tournant dans la UNO: téléversement, puis flashouillage pour la transformer en clavier. L'essai montre que le script Lua se fige dès qu'on ouvre le port de communication.

Normal!! Si la UNO est en keyboard, alors elle ne peut pas reçevoir de données. La carte UNO n'est donc pas le bon dispositif. En fait, il faut une Arduino qui permette d'envoyer des codes clavier sans être en permanence en mode clavier.
La carte Leonardo est tout à fait recommandée, car j'ai pu l'insérer sur son support en remplacement de la UNO. Petit inconvénient, elle a encore moins de mémoire disponible que la UNO (Il faudra compacter davantage le code!!!). Il existe heureusement la possibilité d'utiliser une DUE dont la mémoire est bien plus spacieuse, et la cadence d'horloge bien plus rapide. Mais il faudra lui faire un support adapté, et prévoir un interface pour que son 3.3volts d'entrées/sorties puisse travailler sans dégâts pour elle avec le 5 volts des circuits environnants.

Dans un prochain post, je vous parlerai de l'adaptation de mon petit bout de code à la carte Leonardo.
Ça va permettre à mon système de commander le Xr2 par les raccourcis clavier, tout en commandant les
lumineux présents sur mon tableau de commande. Mais ça va se compliquer un peu! :badfinger:
Title: Re: Le tableau de commande de Mars Bleu
Post by: jacquesmomo on 09 October 2017, 00:04:44
Je suis toujours ça avec intéressement.... :applause:
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 09 October 2017, 22:46:05
Merci, Jacquesmomo!!
Et j'ai encore plein de trucs à exposer.
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 22 October 2017, 16:06:16
En effet, ça se complique dans la mesure où on va avoir deux façons d'envoyer un raccourci clavier. :wonder:
Premier mode: le changement d'état d'un switch provoque l'envoi d'un caractère.
Deuxième mode: l'appui sur un bouton-poussoir va lancer l'envoi d'un caractère, mais son retour à la position
initiale (on relâche le BP) ne va rien faire du tout.

Voici la nouvelle version, tenant compte de la syntaxe Leonardo, et de la possibilité switch/BP.



// Ce code commande un raccourci clavier pour  orbiter en fonction des bits de command
// J'ai ajouté un switch de sécurité: s'il est sur 1, alors l'envoi de caractère est autorisé
// s'il est sur 0, alors pas d'envoi de caractère.
// Avec le BP sur pin 3, je peux envoyer une commande de mouvement de gear sur changement d'état
// Ceci se fait avec la transmission de la variable XORdifference, modulée par switch_mode_mask
//
// Ici, c'est l'essai de ALT L (MAIN yaw vers la droite) sur la case 2 en mode BP
// On peut donc envoyer des caractères de contrôle d'Orbiter en mode switch ou en BP en fonction de APU_aux et switch_mode_mask

const byte secuSwitch=2;
const byte BP=3;
const byte led=13;
byte APU_aux;
byte secuSwitchstatus=0;

unsigned int var;
unsigned int old_var;
unsigned int switch_mode_mask;//si bit à 1, on est en mode"switch", si bit à 0, on est en mode "BP"

unsigned int XORdifference;
const byte xrmodifier[]={0,0,130,0,128,130,128,128,128,128,128,130,0,128,128,128};
const byte xrkey[]={32,32,108,103,98,114,121,92,118,103,117,111,32,111,107,97};
//Les deux lignes ci-dessus sont le tableau des raccourcis clavier auxquels on va s'adresser
//Les xrmodifier:128=>CTRL, et 130=>ALT. Pour info, 129=>SHIFT. Pas de modifier=>0.
//Les xrkey sont les codes ASCII des raccourcis clavier.

void setup()
{
pinMode(secuSwitch,INPUT);
pinMode(BP,INPUT);
pinMode(led,OUTPUT);
APU_aux=4;//commande MAIN yaw vers la droite
switch_mode_mask=8;//paramétrage en mode "switch"ou mode "BP"
}
void loop()

 {
   var=APU_aux*digitalRead(BP);
   XORdifference=(var^old_var);

   keyboard_command(3,0,XORdifference,switch_mode_mask);//appel de la fonction d'envoi de clavier, à installer.
   delay(50);
   old_var=var;
 }//End loop

//La fonction générant le raccourci clavier:
void keyboard_command(byte start,byte offset,unsigned int command,unsigned int switchModeMask)
    {
        secuSwitchstatus=digitalRead(secuSwitch);//ce secuSwitchstatus est là pour éviter un incident d'inaccessibilité
        digitalWrite(led, secuSwitchstatus);//signalisation de l'état de secuSwitchstatus sur la led 13 de la Leonardo
        boolean Switch_or_BP;   //variable booléenne  pour savoir si on est en mode Switch ou BP
        Keyboard.begin();
           for (byte i=start+offset;i<16+offset;i++)
            {
                Switch_or_BP=bitRead(switchModeMask,i);
                if ((bitRead(command,i)==1)&&(secuSwitchstatus==HIGH))
                    {
                         boolean bitvar=bitRead(var,i);//valeur pour transmettre l'état du bit de rang i de la variable globale var
                         xr_presskey(xrmodifier[ i ],xrkey[ i ],Switch_or_BP,bitvar);
                     }
             }
         Keyboard.end();
      }

//L'envoi des caractères:
 void xr_presskey(byte xrmodifier,byte xrkey,boolean SwitchOrBP,boolean bitVarStatus
 {
    if((SwitchOrBP==1)|(bitVarStatus==1&SwitchOrBP==0))
    {
    Keyboard.press(xrmodifier);
    Keyboard.press(xrkey);
    delay(20);
    }
    if((SwitchOrBP==1)|(bitVarStatus==0&SwitchOrBP==0))
    {   
    Keyboard.releaseAll();
    }
  }




En faisant varier la valeur de command, on va pouvoir définir l'envoi des raccourcis claviers. Et voilà!!

ATTENTION: Prévoir un dispositif d'arrêt d'urgence en hardware.

J'ai eu des ennuis de reprise en main de la Leonardo qui était partie à envoyer CTRL U toute les 5 secondes. Pour le Xr2 dans Orbiter, ça revenait à manœuvrer la porte de soute Baydoors, mais pour l'IDE Arduino, c'était le déclenchement d'un téléversement toute les 5 secondes. Du coup, plus moyen de changer le sketch tournant à l'intérieur.
J'ai fini par trouver: il faut laisser se faire un téléversement d'un sketch, mettons Fichier\Exemple\01.Basics\Blink. Avant qu'un nouveau CTRL U soit envoyé, il faut activer une nouvelle fenêtre, par exemple l'utilitaire Bloc Note qui recevra les caractères envoyés par la Leonardo, le temps que le téléversement se fasse. C'est comme ça que j'ai réussi à reprendre la main.
Pour éviter de nouveaux ennuis, j'ai installé un switch de sécurité en hardware. En cas de perte de contrôle par envoi intempestif de caractères par la Leonardo, la manœuvre du switch permettra de reprendre la main plus rapidement et plus facilement.
Par la suite, ayant maîtrisé l'affaire, j'ai pu retirer cette disposition de précaution.

Dans un prochain post, je vais m’employer à faire une petite vidéo pour montrer le fonctionnement de tout ça.
Je ne promets rien pour les délais, car j'ai encore beaucoup à faire pour rendre mes prototypes un peu jolis
à voir.
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 25 November 2017, 19:29:58
Afin de montrer que tout ce qui précède est fonctionnel, voici le lien de la vidéo promise dernièrement.
Je n'en suis qu'à moitié satisfait quant à la qualité, mais en l'état actuel des choses, pas moyen de
faire mieux :(. (Je sais que je devrais aller faire un stage chez Tex...)
Le lien:
https://www.youtube.com/watch?v=jycjemN2I5U

Je suis preneur de conseils pour les prises de vues, l'intégration de vidéos entre elles. Et aussi
de mettre une vidéo directement dans un post. Dans ce domaine, j'ai encore pas mal à apprendre.

Nous allons pouvoir passer à une autre partie du cockpit: il s'agit de l'équilibre du Xr2, et de
l'orientation des moteurs. Ça sera plus simple que la gestion des auxiliaires APU, vous verrez.

A +
Mars Bleu
Title: Re: Le tableau de commande de Mars Bleu
Post by: antoo on 27 November 2017, 12:42:28
Génial! Que c'est grisant  :love: !

A+
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 28 November 2017, 12:54:30
Oui! Il est toujours très plaisant de voir le simpit s'amplifier,
et gagner de nouvelles fonctions.
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 16 December 2017, 10:13:47
La gestion des auxiliaires APU étant opérationnelle, nous allons pouvoir passer à un nouveau TP.
Il n'est pas très spectaculaire, mais excellent au niveau de l'exercice, vous verrez.

J'ai choisi de m'occuper de:

           Bargraphs pour la gestion de l'orientation des moteurs principaux et l'équilibre du vaisseau


On a la possibilité d'orienter les moteurs principaux, et SCRAM (gimbal), ainsi que de manœuvrer la masse d'équilibrage (rentrée atmosphérique).

L'initialisation se fait aussi à partir des données extraites du scn, et transmises à la UNO par des fonctions encadrées par les fonctions "widdernix" du script Lua. Dans le cockpit original dessiné par Altea Aerospace, on a des indicateurs à aiguille dont la gamme n'est pas la même pour tous les moteurs.

Pour des raisons économiques, j'ai préféré utiliser des bargraphs de 15 leds, pilotables par un mot de 16 bits. Quinze leds, c'est bien pour avoir une position centrale, avec le 8° bit allumé, et 7 bits éteints de chaque côté. L'ennui, c'est que j'avais à ma disposition uniquement des bargraphs de 20 leds. Pour arriver à mes fins, j'ai pris une scie, et coupé le plus proprement possible mes quatre bargraphs afin d'obtenir des bargraphs de 15 leds. Le résultat est tout à fait satisfaisant. J'ai installé tout cela avec ses résistances de protection de 1KΩ par led, plus un trimmer 0 à 1KΩ par bargraph.
En effet, pour des raisons de luminosité, cette disposition était la meilleure. J'ai terminé l'ensemble en faisant un câblage rampant pour relier les bargraphs aux connecteurs 2x13 pôles.

(https://img15.hostingpics.net/pics/141367Spacecraftbalancebargraph.jpg)

On est encore un peu dans du provisoire qui va durer, mais c'est fonctionnel. Vous voyez qu'il y a des câbles disponibles(p.ex.sur la nappe 3). Pour l'instant, je ne sais pas s'ils vont servir.

Le tableau (provisoire qui dure) de commande:

(https://img15.hostingpics.net/pics/531779Spacecraftbalancebuttons.jpg)


Pour la gestion logicielle, j'associe les mémoires:    SIPOreg[6] à Pitch Main dir
                                                                          SIPOreg[7] à Yaw Main
                                                                          SIPOreg[8] à Pitch SCRAM dir
                                                                          SIPOreg[9] à Center Gravity shift


On doit connaître le temps de transit d'un bout à l'autre de la gamme de mouvement de l'appareil considéré. On en tire une équation du premier degré donnant la position par rapport à un point central. Un peu de maths, les gars!

J'ai mesuré:      pitch main dir:    5 secondes, soit 5000 ms pour une amplitude de ±0,017455
                       main yaw:          7.2 secondes, soit 7200 ms pour une amplitude de ± 0,12987
                       pitch scram dir:  6 secondes, soit 6000 ms pour une amplitude de ± 0,087156
                       gravity shift:      70 secondes, soit 70000 ms pour une amplitude de ±4,115


Comme j'ai besoin de la durée de référence, et qu'on s'aperçoit que 70000 ne peut pas être codé sur deux octets (unsigned int), j'ai décidé d'y mettre un coefficient de 1.25 plus petit. Ce qui fait qu'on aura 70/1,25=56. D'où:

                    Gravity shift   56 1,25 secondes, soit 56000 1,25ms pour une amplitude de ±4,115
                    Or 56000 tient dans deux octets (65535>56000): ça tombe bien.

On en tire les équations suivantes, avec level tiré de scn (à la bonne ligne):

   main pitch dir:       value=143225,43*level+2500
   main yaw:             value=27720,027*level+3600
   scram pitch dir:     value=34421,038*level+3000
   gravityshift:          value=6804,3842*level+28000

Ces calculs sont faits par le script Lua et envoyés par USB vers le sketch Arduino dans respectivement les cases Position[16 à 19], où les valeurs pourront être modifiées par appui sur les boutons-poussoirs de commande.

Dans un prochain post je vous ferai part des codes Lua et C++ nécessaires au bon fonctionnement de ce dispositif. Bonne lecture!
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 06 January 2018, 16:07:06
Et voici la suite....

J'ai choisi d'appeler la fonction gérant l'équilibrage du vaisseau

                          balance_bargraph_management()

Cette fonction contient plusieurs actions distinctes:

- filtration des actions commandées par les boutons poussoirs, en passant par la valeur Transit_balance_status.
Cette filtration est rendue nécessaire pour gérer l'action des BP de centrage.

- en fonction des valeurs des bits de Transit_balance_status, action sur les valeurs Position[16 à 19], tout en
tenant compte des différentes vitesses de transit (gimbal/gravity shift)

- allumage des leds des bargraphs concernés, en fonction des valeurs Position[16 à 19] venant d'être modifiées.

- rendre clignotante la led du bargraph Gravity shift pendant un transit, et gérer la led de discordance, allumée
si on veut faire un mouvement alors que l'APU est arrêté.

-envoi des raccourcis clavier.

Pour des raisons de compacité et de rapidité, j'ai préféré utiliser les fonctions bitwise ou les bitWrite plutôt que des if{}/else{}.

Donc, plutôt que de faire:


if  i=1
     {
        j=128
     }
Else if i=2
     {
        j=130
     }
   
Qui est lisible et propre,  j'ai écrit:

        j=128*(i==1)+130*(i==2)

C'est plus vilain, et ça se complique vite, au risque d'être indépannable si on a des problèmes. L'idée est de bien faire marcher et de refermer la boîte en espérant ne plus avoir à l'ouvrir! Avec pleinpleinplein de commentaires mis pour s'y retrouver.


              Filtration des actions par Transit_balance_status

Il faut tenir compte, bien entendu de l'action sur les boutons poussoirs, mais aussi tenir compte de l'action spécifique des BP de centrage, en maintenant un "appui centrage", une fois celui-ci initié jusqu'à ce que l'on se retrouve en position médiane pour les valeurs Position[16 à 19]

Pour la Leonardo, ça fait:

void balance_bargraph_management()
{
   Transit_balance_status=(PISOreg[2]&255)|(Transit_balance_status&128&(128*((Position[18]<27985)|(Position[18]>28015))))|(Transit_balance_status&64&(64*((Position[15]<2470)|(Position[15]>2530)|(Position[16]<3570)|(Position[16]>3630)|(Position[17]<2970)|(Position[17]>3030))));//élaboration des autorisations de mouvement.Vous avez vu comme ça pique les yeux, une ligne pareille? :arg:
 
  if (( Transit_balance_status&128)==128)
   {   //Si ordre de centrage Gravityshift, simulation d'appui BP mouvement gravityshift, jusqu'à être à environ 28000
      Transit_balance_status=Transit_balance_status|(32*(Position[18]<27985))|(16*(Position[18]>28015));
   }
  if (( Transit_balance_status&64)==64)
   {   //Si ordre de centrage gimbal, simulation d'appui BP mouvement gimbal, jusqu'à être à environ respectivement 2500, 3600 et 3000
           Transit_balance_status=Transit_balance_status|((8*(Position[16]<3570))|(4*(Position[16]>3630))|(2*(Position[15]<2470))|(Position[15]>2530)|(2*(Position[17]<2970))|(Position[17]>3030));

        }



                  Action sur les valeurs Position[16 à 19]

Dans une boucle, on scrute le temps passé depuis le dernier passage par là, pour changer les valeurs Position[16 à 19]. Il a fallu rajouter tout un tas de modérateurs pour tenir compte des différences de vitesse existant entre chaque auxiliaire. Par exemple, il a fallu réduire d'un facteur de 0.8 le "passage du temps" pour Gravity shift, de façon à pouvoir faire 70000 avec 56000, et tenir compte de la marche de l'APU.

                      Attention les yeux!


 for(byte i=15;i<20;i=i+2)//lecture de Transit_balance_status en vue mouvements gimbal et gravity shift
  {
   if (bitRead(Transit_balance_status, i-15)==1)
   {
                  Position[i-(i>15)]=Position[i-(i>15)]-((((millis()-mem_time)/(4+(i>17)))*4*(1+9*((i>17)*(bitRead(Transit_balance_status,7)==1)*(abs(Position[18]-(refPosition[18]/2))>700))))*(i>15|bitRead(Transit_balance_status,6)==0|Position[i ]>(refPosition[i ]/2)+30)*APUrunning);//décrémentation en général
              // décrémentation de Position[15, 16, ou 18]              coefficient de 0.8 pour Gravityshift    si proche centre Gravityshift, ralentissement mvt pour approche centre        inhibition mvt si: NON(i=15&digit 64 allumé&Position[15]<2530)
                if(Position[i-(i>15)]<50)//si dépassement position(à 50 ms près),...
                {
                  Position[i-(i>15)]=50;//recalage à la valeur min, c'est à dire pas loin de zéro, ceci afin d'éviter de passer <0
                }
      if(i<16)
      {
          Position[i+2]=Position[i+2]-((millis()-mem_time)*(i>15|bitRead(Transit_balance_status,6)==0|Position[i+2]>(refPosition[i+2]/2)+30)*APUrunning);//décrémentation pour SCRAM PITCH
                 // décrémentation de Position[17]                 inhibition de mvt si: NON(i=15&digit 64 allumé&Position[17]<3030)             et lié à marche APU
                 // cette inhibition de mvt ajoutée pour pouvoir centrer gimbal pitch MAIN et SCRAM même si décalage à cause d'un différentiel de fin de course
                    if(Position[i+2]<50)//si dépassement position(à 50 ms près),...
                      {
                        Position[i+2]=50;//recalage à la valeur min, c'est à dire loin de zéro, ceci afin d'éviter de passer <0
                      }
      }
   }
   if (bitRead(Transit_balance_status, i-14)==1)
   {
                Position[i-(i>15)]=Position[i-(i>15)]+((((millis()-mem_time)/(4+(i>17)))*4*(1+9*((i>17)*(bitRead(Transit_balance_status,7)==1)*(abs(Position[18]-(refPosition[18]/2))>700))))*(i>15|bitRead(Transit_balance_status,6)==0|Position[i ]<(refPosition[i ]/2)-30)*APUrunning);//incrémentation en général
              // incrémentation de Position[15, 16, ou 18]              coefficient de 0.8 pour Gravityshift    si proche centre Gravityshift, ralentissement mvt pour approche centre        inhibition mvt si: NON(i=15&digit 64 allumé&Position[15]>2470)

                if(Position[i-(i>15)]>refPosition[i-(i>15)]-50)//si dépassement refposition(à 50 ms près),...
                {
                  Position[i-(i>15)]=refPosition[i-(i>15)]-50;//recalage à la valeur max à 50 ms près
                }
      if(i<16)
      {
          Position[i+2]=Position[i+2]+((millis()-mem_time)*(i>15|bitRead(Transit_balance_status,6)==0|Position[i+2]<(refPosition[i+2]/2)-30)*(APUrunning));//incrémentation pour SCRAM PITCH
                 // incrémentation de Position[17]                 inhibition de mvt si: NON(i=15&digit 64 allumé&Position[17]>2970)             et lié à marche APU
                 // cette inhibition de mvt ajoutée pour pouvoir centrer gimbal pitch MAIN et SCRAM même si décalage à cause d'un différentiel de fin de course
                    if(Position[i+2]>refPosition[i+2]-50)//si dépassement refposition(à 50 ms près),...
                      {
                        Position[i+2]=refPosition[i+2]-50;//recalage à la valeur max à 50 ms près
                      }
        }
   }
  }//next i


Allez, on a presque fini!

                             Allumage des leds des bargraphs concernés:

Pour savoir quelle led de chaque bargraph allumer, j'ai mis:

  // boucle d'allumage des digits pour affichage de la position gimbal et gravity shift
  float barval=0;//barval pour BARgraph VALue
  for(byte i=15;i<19;i++)
  {
    barval=Position[i ];
    barval=(barval*15)/refPosition[i ];
    byte rank=barval;
    SIPOreg[i-9]=0;
    bitSet (SIPOreg[i-9], rank);
  }//next i



Mais il faut encore gérer le clignotement des leds du bargraph COGshift pour montrer qu'on est en mouvement:


// ligne ci-dessous: bargraph gravity shift: clignotement si appui BP, fixe si pas d'appui BP, ou arrivé en fin de course
  SIPOreg[9]=SIPOreg[9]&(((Onehz-32768)*((Transit_balance_status&48)>0))|((~(32767*((Transit_balance_status&48)>0)))|(32767*(Position[18]<60))|(32767*(Position[18]>(refPosition[18]-60)))));
//                         clignotement: -si BP fwd ou aft pressés            fixe: -si BP fwd ou aft NON pressé       OU -fin de course basse  OU    -fin de course haute
  bitWrite(SIPOreg[9],15,(((Transit_balance_status&255)>0)&(~APUrunning)));//Si commande mouvement gimbal ou gravity shift et APU offline, alors led rouge de discordance





Il reste encore:

                      envoi des raccourcis clavier

  keyboard_command(0,16,8,(PISOreg[2]^previousPISOreg[2])&255,PISOreg[2]&255,0);//appel de la fonction d'envoi de clavier start=0;offset=16;width=8,Status=état des BP,0 cad mode BP partout


Ça, c'était encore le plus simple.


En regardant bien, ça n'est pas si bien compliqué. On gère les ordres de centrage, puis les mouvements
contenus dans les valeurs Position[16 à 19] (décrémentation ou incrémentation). Une fois tous ces calculs
faits, on calcule quelles leds des bargraphs on allume, avant d'envoyer les raccourcis claviers pour que
Orbiter puisse suivre les variations qu'on a effectuées sur le simpit.

Je vous laisse digérer tout ceci, avant de vous parler d'un nouveau TP à propos d'un tableau de commande pour un docking réussi en orbite.

A bientôt
Mars Bleu
Title: Re: Le tableau de commande de Mars Bleu
Post by: jacquesmomo on 06 January 2018, 18:35:37
(https://www.surlatoile.com/smileys/repository/Drapeaux/0031.gif) Stupéfiant.....
(https://www.surlatoile.com/smileys/repository/Drapeaux/belgique-cool.gif) incroyable... une fois
(https://www.surlatoile.com/smileys/repository/Drapeaux/usa.gif) amazing !
(https://www.surlatoile.com/smileys/repository/Drapeaux/canada.gif) Tiguidou !

Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 06 January 2018, 20:13:56
Quote
(https://www.surlatoile.com/smileys/repository/Drapeaux/0031.gif) Stupéfiant.....

(https://www.surlatoile.com/smileys/repository/Drapeaux/belgique-cool.gif)incroyable...une fois

(https://www.surlatoile.com/smileys/repository/Drapeaux/usa.gif)amazing!

(https://www.surlatoile.com/smileys/repository/Drapeaux/canada.gif)Tiguidou!

C'est un peu tout ça, mais pour le produire, c'était (http://www.smileys-gratuits.com/smiley-fou/fou-4.gif), et puis (http://www.smileys-gratuits.com/smiley-fou/fou-5.gif).Mais surtout ça (http://www.smileys-gratuits.com/smiley-fou/fou-9.gif)

 :merci:@ Jacquesmomo
Title: Re: Le tableau de commande de Mars Bleu
Post by: nerofox on 06 January 2018, 23:24:05
chapeau bas pour la compacité du code  :wor:, malgré les commentaires je pense que tu sera le seul a pouvoir maintenir un tel programme  :badfinger:
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 07 January 2018, 17:45:27
(http://www.smileys-gratuits.com/smiley-merci/merci-4.gif) pour le...
Quote
chapeau bas

Pour la maintenance, j'espère pouvoir m'y retrouver.  :wonder:
Mais en principe, je ne dois plus avoir à tripoter là dedans.

Sinon, en ce moment, je patauge bien dans les échanges de données Arduino->Lua. J'ai du mal à ne
pas faire planter le script...
Title: Re: Le tableau de commande de Mars Bleu
Post by: Maverik09 on 08 January 2018, 03:04:50
Et bien, tout cela me semble d'une complexité incroyable...
Hâte de voir le résultat final !!
Bonne continuation
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 08 January 2018, 23:53:33
Merci, Maverick09.
Mais même si cela peut paraître compliqué, en fait, c'est parce qu'il
commence à y avoir pas mal de choses à gérer. Il faut diviser les gros trucs
en morceaux simples. Bon. N'empêche que parfois, je galère bien!  :wall:
Title: Re: Le tableau de commande de Mars Bleu
Post by: antoo on 09 January 2018, 01:15:49
Mais tu te débrouilles quand même très bien !
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 11 January 2018, 23:23:45
Merci, Antoo!
Au fait, j'espère que tu avances bien dans ton énorme projet...
Title: Re: Le tableau de commande de Mars Bleu
Post by: antoo on 24 January 2018, 00:46:33
Salut,

Ma foi ça avance, mais doucement. Là à l'instant où j'ecris ces mots, mon frere travaille sur les dll du shuttlePB :D .
A+
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 03 February 2018, 11:16:06
@ Antoo: l'essentiel est d'aller dans la bonne direction. Bravo pour ce grand projet.


Abordons maintenant la conception et la programmation d'un panneau essentiel pour une approche, et
un appontage réussi, le...... :hurle:tadaaaa...

                                                  Docking panel


      Pour réaliser un appontage dans de bonnes conditions, j'ai choisi d'avoir quatre joysticks.
L'idéal aurait été d'avoir seulement un joystick permettant d'orienter l'engin dans les 6 directions
de l'espace (+x;-x;+y;-y;+z;-z). Deux de ces joysticks auraient reproduit ce qui existe sur les
engins réels. Mais ça aurait été trop de boulot de micromécanique à réaliser. Je n'ai malheureusement 
un budget extensible à l'infini...
Plutôt que d'avoir à gérer le commutateur ROT/LIN, j'ai préféré avoir une option automatique, en
fonction du joystick actionné (un commut de moins,  :badfinger:!). D'où l'ensemble de 4 joysticks.
A cet ensemble, il faut rajouter le KILLROT, le commutateur RCS ON/OFF, celui de RCS à 100% ou
à 30%, le gros coup-de-poing rouge pour le UNDOCK sécurisé par un commutateur "Undock Armed",
et les lumineux associés. Total, 9 dispositifs de commande représentant 16 switches (ah bé, ça tombe
bien pour tenir dans un unsigned int)  et 10 lumineux de signalisation.

La réalisation en mode provisoire qui va durer un petit peu:

(http://nsm07.casimages.com/img/2018/02/02//18020208220523716615530763.jpg)



Ce qui a été délicat dans la construction de ce panel a été la mise au point de l'implantation des composants
 sur la plaque à pastilles de cuivre. Il a fallu faire des changements, et des parties de soudage/dessoudage
/ressoudage très laborieuses.

La plaque à pastilles in situ:

(http://nsm07.casimages.com/img/2018/02/03//18020301452523716615532591.jpg)

Trois parties figurent sur cette plaque:

         1°, la liaison entre l'ensemble des switches du panel, et les nappes de câbles en provenance
de la plaque portant les circuits d'élaboration de signal située derrière le panneau "craft balance"
         2°, la liaison entre la nappe de câbles en provenance du module SIPO et les leds de signalisation.
J'ai placé un trimmer variant de 0 à 1Kohm sur le retour vers GND de façon à pouvoir régler
 la luminosité des 5 leds associées (RCS On/ Mismatch/ Off), Translation/Rotation Mode)
         3°, afin d'alléger mon sketch Arduino, j'ai eu l'idée d'utiliser les switches dispos sur mes commutateurs,
et autre coup-de-poing pour avoir une signalisation complémentaire régie par de la logique combinatoire
assez rudimentaire. Par exemple, on peut régler la puissance des RCS (Normal=>100%/Low=>30%). Si
le lumineux "Normal" est allumé, alors, le lumineux "Low" sera éteint, et vice versa. En Bool, ça fait:
Normal=NON(Low). Donc, un circuit intégré 74HCT04 contenant 6 portes NON fait largement l'affaire, puisque
j'ai besoin de seulement trois portes NON.


Une fois tout ceci assemblé, connecté, et essayé, j'ai pu passer à l'amplification de mon sketch, avec l'écriture
de la fonction "docking_management()" qui va gérer les lumineux du panel, et l'envoi des caractères de contrôle
nécessaires à un appontage réussi.

Mais j'en parlerai dans un prochain post. Bonne lecture!
Title: Re: Le tableau de commande de Mars Bleu
Post by: antoo on 03 February 2018, 16:44:06
Je sens que Mars Bleu va nous construire un truc grandiose !

Bravo, ça démarre tès fort. J'ai hâte de voir tous ces éléments s'assembler !

A+
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 26 February 2018, 14:34:35
Me voici pour la suite. Ça va être un peu aride, mais nécessaire pour animer et piloter ce nouveau panel.

La mise au point de l'envoi des caractères de contrôle,et de la gestion des lumineux se fait par la fonction suivante:

                                   Contrôle du docking panel:




void Docking_panel_management()
    {
      boolean rotlin=((Miscstatus&3)>0);//variable locale booléenne qui permet de savoir si on est RCS ON ou OFF: FALSE si RCS est OFF         
      boolean RCSrot=((Miscstatus&1)==1);//lumineux allumé en mode "ROTATION"

      boolean RCSlin=((Miscstatus&2)==2);//lumineux allumé en mode "TRANSLATION"
      boolean RCSmismatch=(bitRead(PISOreg[1],6))^rotlin;//variable locale booléenne déterminant si discordance entre commut et état logique venant du SCN
      boolean RCSgreenled=(rotlin==0);
      boolean RCSyellowled=(rotlin==1);
// préparation des variables nécessaires pour les raccourcis claviers liés aux joysticks d'arrimage:
unsigned int joystick_switches=(PISOreg[2]&16128)+(PISOreg[1]&63);
unsigned int joystick_status=((PISOreg[2]^previousPISOreg[2])&16128)+((PISOreg[1]^previousPISOreg[1])&63);

if ((bitRead(PISOreg[1],6))^(bitRead(previousPISOreg[1],6))//si manoeuvre switch RCS ON/OFF...
   {
      Miscstatus=(Miscstatus&65532)+((1+(((Miscstatus&3)<2)==0))*bitRead(PISOreg[1],6));//le dernier bit de Miscstatus suit l'état du commutateur RCS ON/OFF
      if (RCSmismatch==1)// si, de surcroît pas de discordance...
         {
            keyboard_command(6,24,16,16384,0,65535);// envoi de "CTRL /" pour changer RCS  On<->Off
         }
   }
if ((bitRead(PISOreg[1],6))&&(RCSmismatch==0))//à condition que RCS sur "ON" et discordance éteinte....
   {
      if (((PISOreg[1]&63)!=0)&&((PISOreg[2]&16128)==0)&&(RCSlin==1))//si manoeuvre joystick ROT sans manoeuvre joystick LIN et  en mode LIN
         {                                                 //=>les deux derniers bits réglés à : 01 <=>mode ROT
           bitSet(Miscstatus,0);
           bitClear(Miscstatus,1);
           keyboard_command(6,24,16,64,0,65535);//envoi de "/" pour être en mode ROT
         }
      if (((PISOreg[2]&16128)!=0)&&((PISOreg[1]&63)==0)&&(RCSrot==1))//si manoeuvre joystick LIN sans manoeuvre joystick ROT et en mode ROT
         {                                                 //=>les deux derniers bits réglés à : 10 <=>mode LIN
           bitSet(Miscstatus,1);
           bitClear(Miscstatus,0);
           keyboard_command(6,24,16,64,0,65535);// envoi de "/" pour être en mode LIN
         }
      if (joystick_status!=0)//toujours à condition que RCS sur "ON" et discordance éteinte....
         {                        // envoi des raccourcis clavier de commande des RCS
             keyboard_command(0,24,16,joystick_status,joystick_switches,0);
         }
      if (((bitRead(PISOreg[1],7))^(bitRead(previousPISOreg[1],7)))&(bitRead(PISOreg[1],7)))//toujours à condition que RCS sur "ON" et discordance éteinte....
         {        // envoi KILLROT
           keyboard_command(7,24,16,128,0,65535);
         }
   }
 if (((bitRead(PISOreg[2],15))^(bitRead(previousPISOreg[2],15)))&(bitRead(PISOreg[2],15)))//si UNDOCK...
      {
          keyboard_command(14,24,16,32768,0,65535);//envoi de CTRL d
      }

Contrôle des leds de signalisation du panel:
  bitWrite(SIPOreg[3],0,RCSgreenled);//led verte RCS "OFF"
  bitWrite(SIPOreg[3],1,RCSmismatch);//led rouge RCS mismatch
  bitWrite(SIPOreg[3],2,RCSyellowled);//led jaune RCS "ON"
  bitWrite(SIPOreg[3],3,RCSrot);//led jaune mode ROTATION
  bitWrite(SIPOreg[3],4,RCSlin);//led jaune mode TRANSLATION
  bitWrite(SIPOreg[3],5,((Miscstatus&3)>0)&(bitRead(PISOreg[2],14))==0);//led verte RCS "normal", allumage conditionné à: RCS sur "ON"
 bitWrite(SIPOreg[3],6,((Miscstatus&3)>0)&(bitRead(PISOreg[2],14))==1);//led jaune RCS "low", allumage conditionné à: RCS sur "ON"
//Changement des "modifiers" relatifs aux commandes joystick selon RCS Normal/low:

      if (((bitRead(PISOreg[2],14))^(bitRead(previousPISOreg[2],14)))&((bitRead(PISOreg[1],6))&&(RCSmismatch==0)))
      {
          for(byte i=24;i<36;i++)
          {
              xrmodifier[i+(2*(i>29))]=128*(bitRead(PISOreg[2],14));
          }
      }
}//fin de la fonction dédiée au contrôle du docking panel



Les essais au sol, puis en orbite ont permis les dernières mises au point. L'appontage à l'ISS a montré que l'ergonomie de mon panneau est tout à fait satisfaisante. La commutation automatique entre le mode rotation et le mode translation est un vrai plus pour les approches finales.


A bientôt pour un nouveau rendez vous! :salut:
Title: Re: Le tableau de commande de Mars Bleu
Post by: jacquesmomo on 26 February 2018, 14:43:22
ça va être sympa tout ça...

Dis-moi... tu as commencé ton "tableau de commande" il y a combien de temps déjà ??  :wonder:
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 26 February 2018, 18:47:48
Quote
Dis-moi... tu as commencé ton "tableau de commande" il y a combien de temps déjà ??  :wonder:

Oùoùoùoulaâââ... Ça commence à remonter loin. J'ai commencé à regarder comment faire avec Lua fin 2013,
et dès début 2014, j'ai pu me lancer dans les premiers TP d'électronique. Mais il y a eu des essais infructueux,
 des impasses, ce qui fait que ça n'a pas pu aller aussi vite que j’aurais voulu. Et puis, il y a aussi les impératifs
 de la vie domestique, le travail (les travaux). En été, j'avance moins vite qu'en hiver, car les journées plus
longues me permettent de travailler davantage à l'extérieur.
En ce moment, je finalise les pilotes automatiques( Airspeed, Descent, Attitude, plus pilotes auto orbitaux
(pro/retrograde, N+/N-)), avec toute une flopée d'afficheurs 7 segments devant afficher les consignes.
Ensuite, je me pencherai sur la propulsion (Main, Scram, Hover), avec une approche plus facile   originale.
                                        Mais ça ne sera pas encore fini... :badfinger:
Parallèlement, je veux aménager le coin qui accueillera mon beau simpit (pas comme dans la pub EdF :) )
C'est que je commence à avoir pas mal de bazar, avec tous ces panels qui commencent à s'accumuler...

                    :explique:  :explique: :explique: De patience, preuve nous devons faire! :explique: :explique: :explique:

Title: Re: Le tableau de commande de Mars Bleu
Post by: hysot on 08 March 2018, 15:04:27
Salut Mars Bleu,

Je reviens un petit peu avec mon projet de cockpit toujours en tete.
J'ai regarde avec interet ton projet. Tu fais du tres bon boulot.
Je souhaiterais concevoir le miens sur une base similaire. J'essaie d'apprendre le Lua tout comme toi. C'est pas simple mais ca vient doucement.

J'essaie de faire fonctionner le bout de Lua de ton message  PREMIER CHALLENGE: Lire un fichier SCN mais sans succes...
Je parle bien evidemment de ces 4 bouts de codes:

Code: [Select]
-- ******************************************
-- ********read number lines from scn file***
-- ******************************************
function line_read (file)
    number_lines=0
    local g = io.open(file,"r")
    if g ~= nil then
        repeat
            t = g:read()
            number_lines=number_lines+1
        until t == nil
    g:close()
    end
end
-- *****************************************
-- *********end function line_read *********
-- *****************************************

Code: [Select]
-- *******************************************
-- ********load lines from scn file***********
-- *******************************************
function load_scnfile (file,n)
    slist={}
    local f = io.open(file,"r")
    if f ~= nil then
        for i=1,n do
            t = f:read()
            if t == nil then break end
            slist[i]=t
        end     
        f:close()
    end
    return slist
end
-- ******************************************
-- *********end function load_scnfile *******
-- ******************************************

Code: [Select]
-- *******************************************
-- ***********load ship status****************
-- *******************************************
function load_xr2_status (pattern)
    for i=1,number_lines-1 do
       s1 = slist[i]
       _,_,name,classname = string.find (s1, "(.-):(.+)")
       if (classname=='XR2Ravenstar') and (ship=='XR2Ravenstar') then
           name_ship=name
           for j=i, number_lines-1 do
               if string.match (slist[j], 'NOSECONE')~=nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
                   note:set_text('NOSECONE=>'..status..' '..level)
                   proc.wait_sysdt(0.41)
               elseif string.match (slist[j], 'GEAR')~=nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
                    note:set_text('GEAR=>'..status..' '..level)
                   proc.wait_sysdt(0.41)
               elseif string.match (slist[j], 'RADIATOR')~=nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
                   note:set_text('RADIATOR=>'..status..' '..level)
                   proc.wait_sysdt(0.41)
               elseif string.match (slist[j], 'HATCH')~=nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
                   note:set_text('HATCH=>'..status..' '..level)
    elseif slist[j]=='END' then
                   flag_out=1
                   break
               end                     
           end

Code: [Select]
--****************************************************************************
-- ********** begin program ************************* begin program *********
--*****************************************************************************
note = oapi.create_annotation()
note:set_pos (0.35,0.1,0.8,0.95)
note:set_colour ({r=0.9,g=0.5,b=0.2})

data_path = 'Scenarios/(Current state).scn'
intro = 'Load scn data'

note:set_text(intro)
proc.wait_sysdt(0.5)

note:set_colour ({r=0.9,g=0.0,b=0.0})

v=vessel.get_focusinterface()
ship=v:get_classname()
name_ship_focused=v:get_name()


-- ******************************************************
-- ***********begin call functions for scn file**********
-- ******************************************************

sfirst = line_read (data_path)

slist = load_file (data_path,number_lines)


if  ship=='XR2Ravenstar' then
    lstatus = load_xr2_status (ship)
elseif ship=='Xr5Vanguard' then
    note:set_text('Toward function loop load of XR5Vanguard')
    proc.wait_sysdt(2.01)
elseif ship=='ShuttleA' then
    note:set_text('Toward function loop load of ShuttleA')
    proc.wait_sysdt(2.01)
else
    note:set_text('vessel not implemented, simpit not activated')
    proc.wait_sysdt(2.01)
end
-- ******************************************************
-- ************ end call functions for scn file**********
-- ******************************************************
note:set_text('End of program')
proc.wait_sysdt(1)
note:set_text('  ')
proc.wait_sysdt(1)

On est bien d'accord que ce code est fait pour afficher les donnees directement dans orbiter?
On est bien d'accord que ces 4 bouts de code doivent etre assembles dans un meme et unique fichier script comme suit:

Code: [Select]
-- ******************************************
-- ********read number lines from scn file***
-- ******************************************
function line_read (file)
    number_lines=0
    local g = io.open(file,"r")
    if g ~= nil then
        repeat
            t = g:read()
            number_lines=number_lines+1
        until t == nil
    g:close()
    end
end
-- *****************************************
-- *********end function line_read *********
-- *****************************************

-- *******************************************
-- ********load lines from scn file***********
-- *******************************************
function load_scnfile (file,n)
    slist={}
    local f = io.open(file,"r")
    if f ~= nil then
        for i=1,n do
            t = f:read()
            if t == nil then break end
            slist[i]=t
        end     
        f:close()
    end
    return slist
end
-- ******************************************
-- *********end function load_scnfile *******
-- ******************************************

-- *******************************************
-- ***********load ship status****************
-- *******************************************
function load_xr2_status (pattern)
    for i=1,number_lines-1 do
       s1 = slist[i]
       _,_,name,classname = string.find (s1, "(.-):(.+)")
       if (classname=='XR2Ravenstar') and (ship=='XR2Ravenstar') then
           name_ship=name
           for j=i, number_lines-1 do
               if string.match (slist[j], 'NOSECONE')~=nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
                   note:set_text('NOSECONE=>'..status..' '..level)
                   proc.wait_sysdt(0.41)
               elseif string.match (slist[j], 'GEAR')~=nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
                    note:set_text('GEAR=>'..status..' '..level)
                   proc.wait_sysdt(0.41)
               elseif string.match (slist[j], 'RADIATOR')~=nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
                   note:set_text('RADIATOR=>'..status..' '..level)
                   proc.wait_sysdt(0.41)
               elseif string.match (slist[j], 'HATCH')~=nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
                   note:set_text('HATCH=>'..status..' '..level)
    elseif slist[j]=='END' then
                   flag_out=1
                   break
               end                     
           end


--*****************************************************************************
- ********** begin program ************************* begin program *********
--*****************************************************************************
note = oapi.create_annotation()
note:set_pos (0.35,0.1,0.8,0.95)
note:set_colour ({r=0.9,g=0.5,b=0.2})

data_path = 'Scenarios/(Current state).scn'
intro = 'Load scn data'

noteTop:set_text (intro)
proc.wait_sysdt(0.5)

note:set_colour ({r=0.9,g=0.0,b=0.0})

v=vessel.get_focusinterface()
ship=v:get_classname()
name_ship_focused=v:get_name()


-- ******************************************************
-- ***********begin call functions for scn file**********
-- ******************************************************

sfirst = line_read (data_path)

slist = load_file (data_path,number_lines)


if  ship=='XR2Ravenstar' then
    lstatus = load_xr2_status (ship)
elseif ship=='Xr5Vanguard' then
    note:set_text('Toward function loop load of XR5Vanguard')
    proc.wait_sysdt(2.01)
elseif ship=='ShuttleA' then
    note:set_text('Toward function loop load of ShuttleA')
    proc.wait_sysdt(2.01)
else
    note:set_text('vessel not implemented, simpit not activated')
    proc.wait_sysdt(2.01)
end
-- ******************************************************
-- ************ end call functions for scn file**********
-- ******************************************************
note:set_text('End of program')
proc.wait_sysdt(1)
note:set_text('  ')
proc.wait_sysdt(1)


J'ai bien fait attention au fait que tu utilises le scenario (Current state).scn pour le lancement du script. J'ai bien compris comment lancer un script lua dans un scenario orbiter et j'ai aussi pu afficher des donnees directement dans orbiter mais mon code etait different. Pourtant, avec le tiens, rien ne se passe. Du coup, si tu pouvais m'eclaircir un peu. Deja, est ce que mon script est correct ou manque t'il une partie que tu n'avais pas mentionee? L'ordre dans lequel j'ai positionne les codes est peut etre mauvais?

merci du coup de pousse :)
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 11 March 2018, 09:32:27
Dans Orbiter, Lua est assez farceur, car il suffit d'un simple oubli de parenthèse, ou bien d'une
erreur dans la structure du script pour que plus rien ne marche, sans aucune indication sur l'endroit
et le type d'erreur.
C'est pour ça que je développe à tout petits pas, et que je fait de nombreuses sauvegardes intermédiaires.

Je voulais mettre le script en entier d'un bloc, mais j'ai atteint la limite de 20 000 caractères. C'est pour
ça que j'ai mis la fonction "xr2_payload_setting (payload_tank, nb_tank_payload,payload_max_capacity,payload_set,payload_i) dans une autre post, à fusionner pour que ça soit fonctionnel. Je l'ai mis au point hier soir, en
enlevant les parties ne concernant pas la transmission des données, ni la boucle de rafraîchissement.
On se concentre juste sur la lecture du fichier SCN.

Code: [Select]
-- ******************************************
-- ********read number lines from scn file***
-- ******************************************
function line_read (file)
    number_lines=0
    local g = io.open(file,"r")
    if g ~= nil then
        repeat
            t = g:read()
            number_lines=number_lines+1
        until t == nil
    g:close()
    end
end
-- *****************************************
-- *********end function line_read *********
-- *****************************************

-- *******************************************
-- ********load lines from scn file***********
-- *******************************************
function load_file (file,n)
    slist={}
    local f = io.open(file,"r")
    if f ~= nil then
        for i=1,n do
            t = f:read()
            if t == nil then break end
            slist[i]=t
        end     
        f:close()
    end
    return slist
end
-- ******************************************
-- *********end function load_scnfile *******
-- ******************************************


-- *******************************************
-- ***********load xr2 status****************
-- *******************************************

function load_xr2_status (pattern)
    status_array={}
    level_array={}
position={}
RCSstatus=1--valeur par dÈfaut dans le SCN
docked=0--valeur par dÈfaut dans le SCN
Miscstatus=1--valeur par dÈfaut (RCS en ROT)
    flag_out=0
    main_fuel_tank=0
    scram_fuel_tank=0
    lox_tank=0
    nb_tank_main_fuel=0
    nb_tank_scram_fuel=0
    nb_tank_lox=0
    name_ship=""
SIPOstatus=0
SIPOtransit_status=0
    for i=1,40 do
        status_array[i]=""
        level_array[i]=""
if (i<19)==true then
position[i]=""
end
    end
    for i=1,number_lines-1 do
       s1 = slist[i]
       _,_,name,classname = string.find (s1, "(.-):(.+)")
--***************************************************************************
--*****************************************************Begin Xr2 settings****
--***************************************************************************
       if (classname=='XR2Ravenstar')  and (name==name_ship_focused) then
           name_ship=name
           status_array[1]=v:get_rcsmode()
           note:set_text('Mode rcs'..'=>'..status_array[1])
           proc.wait_sysdt(0.21*afficher)
           main_fuel=v:get_propellanthandle(0)
           level_array[1]=v:get_propellantmass(main_fuel)
           note:set_text('Main fuel=>'..level_array[1]..'kg')
           proc.wait_sysdt(0.21*afficher)
           rcs_fuel=v:get_propellanthandle(1)
           level_array[2]=v:get_propellantmass(rcs_fuel)
           note:set_text('Rcs fuel=>'..level_array[2]..'kg')
           proc.wait_sysdt(0.21*afficher)
           scram_fuel=v:get_propellanthandle(2)
           level_array[3]=v:get_propellantmass(scram_fuel)
           note:set_text('Scram fuel=>'..level_array[3]..'kg')
           proc.wait_sysdt(0.5*afficher)
           for j=i, number_lines-1 do           
               if string.match (slist[j], 'APU_FUEL_QTY')~=nil then
                   _,_,aux,level = string.find(slist[j],"(.+) (.+)")
                   level_array[4]=level*268
                   note:set_text('APU fuel'..'=>'..level_array[4]..'kg')
                   proc.wait_sysdt(0.5*afficher)
               elseif string.match (slist[j], 'APU_STATUS')~=nil then   --dÈbut process 13 auxiliaires
                   _,_,aux,status = string.find(slist[j],"(.+) (.+)")
                   power=15
   level=0
   delay=0
   sprocess=process(SIPOtransit_status,SIPOstatus,power,status,level,delay)    
   note:set_text('Status APU'..'=>'..SIPOstatus)
                   proc.wait_sysdt(0.5*afficher)
   elseif string.match (slist[j], 'NOSECONE')~=nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
   power=14
   delay=20000
   sprocess=process(SIPOtransit_status,SIPOstatus,power,status,level,delay)
   note:set_text('NOSECONE==>'..SIPOstatus..' '..SIPOtransit_status)
                   proc.wait_sysdt(0.5*afficher)
   elseif string.match (slist[j], 'AIRLOCK')~=nil and string.match (slist[j], 'IAIRLOCK')==nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
   power=13
   delay=10000
   sprocess=process(SIPOtransit_status,SIPOstatus,power,status,level,delay)
   note:set_text('AIRLOCK==>'..SIPOstatus..' '..SIPOtransit_status)
                   proc.wait_sysdt(0.5*afficher)
   elseif string.match (slist[j], 'CHAMBER')~=nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
   power=12
   delay=28000
   sprocess=process(SIPOtransit_status,SIPOstatus,power,status,level,delay)
   note:set_text('CHAMBER==>'..SIPOstatus..' '..SIPOtransit_status)
                   proc.wait_sysdt(0.5*afficher)
   elseif string.match (slist[j], 'IAIRLOCK')~=nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
   power=11
   delay=10000
   sprocess=process(SIPOtransit_status,SIPOstatus,power,status,level,delay)
   note:set_text('IAIRLOCK==>'..SIPOstatus..' '..SIPOtransit_status)
                   proc.wait_sysdt(0.5*afficher)    
               elseif string.match (slist[j], 'BAY_DOORS')~=nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
   power=10
   delay=22000
   sprocess=process(SIPOtransit_status,SIPOstatus,power,status,level,delay)
   note:set_text('BAY DOORS==>'..SIPOstatus..' '..SIPOtransit_status)
                   proc.wait_sysdt(0.5*afficher)
   elseif string.match (slist[j], 'SCRAM_DOORS')~=nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
   power=9
   delay=3000
   sprocess=process(SIPOtransit_status,SIPOstatus,power,status,level,delay)
   note:set_text('SCRAMDOORS==>'..SIPOstatus..' '..SIPOtransit_status)
                   proc.wait_sysdt(0.5*afficher)
   elseif string.match (slist[j], 'HOVER_DOORS')~=nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
   power=8
   delay=5000
   sprocess=process(SIPOtransit_status,SIPOstatus,power,status,level,delay)
   note:set_text('HOVERDOORS==>'..SIPOstatus..' '..SIPOtransit_status)
                   proc.wait_sysdt(0.5*afficher)
   elseif string.match (slist[j], 'RCOVER')~=nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
   power=7
   delay=33000
   sprocess=process(SIPOtransit_status,SIPOstatus,power,status,level,delay)
   note:set_text('RETRODOORS==>'..SIPOstatus..' '..SIPOtransit_status)
                   proc.wait_sysdt(0.5*afficher)
   elseif string.match (slist[j], 'HATCH')~=nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
   power=6
   delay=6600
   sprocess=process(SIPOtransit_status,SIPOstatus,power,status,level,delay)
   note:set_text('HATCH==>'..SIPOstatus..' '..SIPOtransit_status)
                   proc.wait_sysdt(0.5*afficher)
               elseif string.match (slist[j], 'RADIATOR')~=nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
   power=5
   delay=32000
   sprocess=process(SIPOtransit_status,SIPOstatus,power,status,level,delay)    
                   note:set_text('RADIATOR=>'..SIPOstatus..' '..SIPOtransit_status..'  Position:'..position[5])
                   proc.wait_sysdt(0.5*afficher)
               elseif string.match (slist[j], 'AIRBRAKE')~=nil then
                   _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
   power=4
   delay=3300
   sprocess=process(SIPOtransit_status,SIPOstatus,power,status,level,delay)    
                   note:set_text('AIRBRAKE=>'..SIPOstatus..' '..SIPOtransit_status)
                   proc.wait_sysdt(0.5*afficher)
          --[[     elseif string.match (slist[j], 'GEAR')~=nil then
       _,_,_,status,level = string.find(slist[j],"(.+) (.+) (.+)")
   power=3
   delay=6700
   sprocess=process(SIPOtransit_status,SIPOstatus,power,status,level,delay)    
                   note:set_text('GEAR=>'..SIPOstatus..' '..SIPOtransit_status)
                   proc.wait_sysdt(0.5*afficher)]] --fin traitement des 13 aux
   elseif string.match (slist[j], 'Landed')~=nil then
   --MSB de position[3] laissÈ ‡ 0 afin d'indiquer que le vaisseau est posÈ. Calcul fait par position[3]=position[3]+32768
   flightflag=0
   note:set_text('Ship landed')
   proc.wait_sysdt(0.5*afficher)
   elseif string.match (slist[j], 'Orbiting')~=nil then
   --MSB de position[3] ‡ 1 afin d'indiquer que le vaisseau est en vol. Calcul fait par position[3]=position[3]+32768
   flightflag=1
   note:set_text('Ship not landed')
   proc.wait_sysdt(0.5*afficher)
   elseif string.match (slist[j], 'MAIN0DIR')~=nil then
   _,_,_,main_yaw,main_pitch,main= string.find(slist[j],"(.+) (.+) (.+) (.+)")
   position[15]=math.floor(-143225.43*main_pitch+2500) --calcul position main pitch en ms
   position[16]=math.floor(27720.027*main_yaw+3600)--calcul position main yaw en ms
   note:set_text(' Main pitch='..position[15]..' Main yaw='..position[16])
   proc.wait_sysdt(0.5*afficher)
   elseif string.match (slist[j], 'SCRAM0DIR')~=nil then
   _,_,_,scram_yaw,scram_pitch,scram= string.find(slist[j],"(.+) (.+) (.+) (.+)")
   position[17]=math.floor(-34421.038*scram_pitch+3000) --calcul position scram pitch en ms
   note:set_text(' Scram pitch='..position[17])
   proc.wait_sysdt(0.5*afficher)    
   elseif string.match (slist[j], 'ATTITUDE_HOLD_DATA')~=nil then
   _,_,_,pitch,bank,status1,PitchAoA,level = string.find(slist[j],"(.+) (.+) (.+) (.+) (.+) (.+)")
   position[18]=math.floor(-6804.3742*level+28000) -- calcul de la valeur de position de gravity shift en 1.25 ms
   pitch=10*pitch--on met pitch en dixiËmes de degrÈs. Par contre, bank reste en degrÈs.
   bank=1*bank
   note:set_text('Data ATTITUDE_HOLD_DATA')
   proc.wait_sysdt(0.5*afficher)
   note:set_text('pitch='..pitch)
   proc.wait_sysdt(0.5*afficher)    
   note:set_text('bank='..bank)
   proc.wait_sysdt(0.5*afficher)    
   note:set_text('status1='..status1)
   proc.wait_sysdt(0.5*afficher)    
   note:set_text('PitchAoA='..PitchAoA)
   proc.wait_sysdt(0.5*afficher)
   note:set_text('level='..level)
   proc.wait_sysdt(0.5*afficher)
   note:set_text('Gravity Shift='..position[18])
   proc.wait_sysdt(0.5*afficher)
   PitchAoA=16*PitchAoA
   elseif string.match (slist[j], 'RCSMODE')~=nil then --dÈbut Èlaboration Miscstatus comprenant l'Ètat des RCS...
   _,_,aux,RCSstatus = string.find(slist[j],"(.+) (.+)")
   note:set_text('Etat RCS='..RCSstatus)
   proc.wait_sysdt(0.5)
   elseif string.match (slist[j], 'DOCKINFO')~=nil then  --...savoir si on est dockÈ ou non...
       docked=4
   elseif string.match (slist[j], 'LOX_QTY')~=nil then
                   _,_,aux,level = string.find(slist[j],"(.+) (.+)")
                   level_array[24]=level*364
                   note:set_text('LOX quantity'..'=>'..level_array[24]..'kg')
                   proc.wait_sysdt(0.5*afficher)
   elseif string.match (slist[j], 'CUSTOM_AUTOPILOT_MODE')~=nil then --... savoir si Descent ou Attitude en fonction...
   _,_,aux,Autopilot_status = string.find(slist[j],"(.+) (.+)")
   Autopilot_status = Autopilot_status*64--Autopilot_status=1 pour Attitude Hold ON/AutopÓlot_status=2 pour Descent ON
--=>Autopilot varie entre 64 et 128
   elseif string.match (slist[j], 'AIRSPEED_HOLD_ENGAGED')~=nil then-- ... savoir si Airspeed hold en fonction...
   _,_,aux,Airspeed_autopilot_status = string.find(slist[j],"(.+) (.+)")
   Airspeed_autopilot_status = Airspeed_autopilot_status*8
   elseif string.match (slist[j], 'AIRSPEED_HOLD_DATA')~=nil then
   _,_,aux,Airspeed_set = string.find(slist[j],"(.+) (.+)")
   Airspeed_set=Airspeed_set*10
   Airspeed_set=math.min(Airspeed_set, 65535)
   note:set_text('Airspeed setting'..'=>'..Airspeed_set..'dm/s')
                   proc.wait_sysdt(0.5*afficher)
   elseif string.match (slist[j], 'DESCENT_HOLD_DATA')~=nil then -- ...savoir si Autoland en fonction, et la consigne (Descent_set)
       _,_,_,Descent_set,Set2,Autoland= string.find(slist[j],"(.+) (.+) (.+) (.+)")
   note:set_colour ({r=0.2,g=0.5,b=0.9})
   note:set_text('Descent_set=>'..Descent_set..'  Set2==>'..Set2..' Autoland==>'..Autoland)
   proc.wait_sysdt(0.5)
   Autoland=Autoland*32
   Descent_sign=0
   Descent_set=Descent_set*10--on doit transmettre des dÈcimËtres.
   if Descent_set<0 then     --(Type d'unitÈ incompatible, sinon?) On multiplie par 10 pour avoir des dÈcimËtres par seconde.
       Descent_sign=256      -- RÈglage du 9∞ bit pour Miscstatus
   end
   Descent_set=math.abs(Descent_set)
   note:set_colour ({r=0.9,g=0.5,b=0.2})
   note:set_text('Descent_sign=>'..Descent_sign..'  Set2==>'..Set2..' Autoland==>'..Autoland)
   proc.wait_sysdt(0.5)    
elseif slist[j]=='END' then
                   flag_out=1
   if pitch>=0 then-- rÈglage du signe du pitch
Pitch_set=pitch
   else
Pitch_set=math.abs(pitch)--si pitch<0, calcul pour retrouver une valeur <0 sur la Leonardo
   end
   if bank>=0 then-- rÈglage du signe du bank
Bank_set=bank
   else
Bank_set=math.abs(bank)--si bank<0, calcul pour retrouver une valeur <0 sur la Leonardo
   end    
   Miscstatus=Descent_sign+Autopilot_status+Autoland+PitchAoA+Airspeed_autopilot_status+docked+RCSstatus -- ici, on a un octet occupÈ
--le multiplicateur suivant est 256 (9∞bit)
   note:set_text('SIPOstatus=>'..SIPOstatus..'  SIPOtransit_status==>'..SIPOtransit_status)
   proc.wait_sysdt(0.5)
   note:set_text('Miscstatus=>'..Miscstatus)
   proc.wait_sysdt(0.5)    
                   break
               end                      --Endif du Xr2
 
           end                          --Next j
--***************************************************************
--************************************End Xr2 settings***********
--***************************************************************
--************************************Begin Xr2 payload setting**
--***************************************************************

       elseif(classname=='XR2PayloadCHM') then
           CHM_set=0
           CHM_capacity=0
           CHM_i=i
           lpayload=xr2_payload_setting(main_fuel_tank, nb_tank_main_fuel, CHM_capacity,CHM_set,CHM_i)
       elseif(classname=='XR2PayloadMainFuel') then
           main_fuel_set=4
           main_fuel_max_capacity=3350
           main_fuel_i=i
           lpayload=xr2_payload_setting(main_fuel_tank, nb_tank_main_fuel, main_fuel_max_capacity, main_fuel_set,main_fuel_i)
       elseif(classname=='XR2PayloadSCRAMFuel') then
           scram_fuel_set=6
           scram_fuel_max_capacity=3350
           scram_fuel_i=i
           lpayload=xr2_payload_setting(scram_fuel_tank, nb_tank_scram_fuel, scram_fuel_max_capacity, scram_fuel_set,scram_fuel_i)
       elseif(classname=='XR2PayloadLOX') then
           lox_set=9
           lox_max_capacity=10545
           lox_i=i
           lpayload=xr2_payload_setting(lox_tank, nb_tank_lox, lox_max_capacity, lox_set, lox_i)
       elseif(classname=='XR2PayloadLOX_Half') then
           lox_set=9
           lox_max_capacity=5272.5
           lox_i=i
           lpayload=xr2_payload_setting(lox_tank, nb_tank_lox, lox_max_capacity, lox_set, lox_i)
       elseif(classname=='XR2PayloadEmptyLOX') then
           lox_set=9
           lox_max_capacity=0
           lox_i=i
           lpayload=xr2_payload_setting(lox_tank, nb_tank_lox, lox_max_capacity, lox_set, lox_i)
--********************************************************
--*****************************End Xr2 payload setting****
--********************************************************
       end
    end                                 --Next i




end
-- ****************************************
-- *******end function load_xr2_status ***
-- ****************************************

-- ********************************************
-- *******begin function process APU_status ***
-- ********************************************
function process(SIPOtransit_stat,SIPOstat,power,status,level,delay)
   if((status%2)==1)then
SIPOstatus=SIPOstat+(2^power)
   end
   if(status%3==2)then
   --if (status==2)==true then
    note:set_text('Status vu ‡ 2 ou 3='..status)
proc.wait_sysdt(0.5)
SIPOtransit_status=SIPOtransit_stat+(2^power)
   end
    if(status%4==3)then
--if(status==3)==true then
    note:set_text('Status vu ‡ 3='..status)
proc.wait_sysdt(0.5)
SIPOtransit_status=SIPOtransit_stat+(2^power)
   end
   if (power<15)then
position[power]=level*delay
   end
end

-- ******************************************
-- *******end function process APU_status ***
-- ******************************************

Quelques commentaires:
La fonction principale (Main) se trouve à la fin. Je pense que mettre les fonctions appelées dans le Main
est une façon de déclarer ces fonctions.
La fonction "line_read(file) ouvre le fichier "current scenario.scn" afin de connaître le nombre de lignes à lire.
Load_file (file, n) va charger dans le tableau slist[] chaque ligne du SCN.
Une fois le fichier SCN chargé dans le tableau, et les initialisation effectuées, la fonction"load_xr2_status (pattern) va ouvrir une boucle chargée de repérer la partie "Xr2" dans le SCN.
Ceci fait, on charge ce qui nous intéresse pour l'initialisation du cockpit; il y en a pas mal en tout.
La partie"Xr2 payload setting" est un peu en friche pour l'instant. Mais elle est tout à fait capable
de prendre en compte une éventuelle cargaison à bord.
La fonction " process(SIPOtransit_stat,SIPOstat,power,status,level,delay)" va élaborer l'ensemble des données
à transmettre à la Leonardo afin qu'elle puisse les utiliser convenablement.
Enfin, la fonction "function xr2_payload_setting (payload_tank, nb_tank_payload,payload_max_capacity,payload_set,payload_i)" qui suit est sûrement à revoir, car elle n'a pas
été retouchée depuis le début de mes travaux.
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 11 March 2018, 09:40:35
Voici la dernière fonction pour que ça soit complet:
Code: [Select]
-- ***********************************************
-- *********** Xr2 payload setting ***************
-- ***********************************************
function xr2_payload_setting (payload_tank, nb_tank_payload,payload_max_capacity,payload_set,payload_i)
    for k=payload_i, number_lines-1 do
        if string.match (slist[k], 'ATTACHED')~=nil then
            _,_,attached,slot,carrier = string.find(slist[k],"(.+):(.+),(.+)")
        elseif (string.match (slist[k], 'PRPLEVEL')~=nil or classname=='XR2PayloadEmptyLOX') and name_ship_focused==carrier then
            if classname~='XR2PayloadEmptyLOX' then
                _,_,aux,level = string.find(slist[k],"(.+):(.+)")
            elseif classname=='XR2PayloadEmptyLOX' then
                level=0
            end
            carrier=""
            payload_tank=level*payload_max_capacity+payload_tank
            nb_tank_payload=nb_tank_payload+1
            level_array[payload_set+nb_tank_payload]=level*payload_max_capacity
            status_array[payload_set+nb_tank_payload]=slot+1
            flag_out=1
            if payload_set==4 then                                 
                nb_tank_main_fuel=nb_tank_payload
            elseif payload_set==6 then
                nb_tank_scram_fuel=nb_tank_payload
            elseif payload_set==9 then
                nb_tank_lox=nb_tank_payload
            end
            break
        elseif (classname=='XR2PayloadCHM') and (name_ship_focused==carrier) then
            carrier=""
            level_array[9]=1
            status_array[9]=1
            flag_out=1
            break   
        elseif slist[k]=='END' then
            break
        end
    end
end
-- ****************************************
-- ******* end function payload setting ***
-- ****************************************
Mais ça pourra être plus simple si l'appel de cette fonction est inactivé, car pour l'instant, elle n'est
pas de grande utilité. Pour inactiver, enlever tous les "elseif" du "payload setting".

En ce qui concerne mes travaux actuels, beaucoup de soudures et de câblages: je suis en train de
faire les affichages numériques des consignes des pilotes automatiques (qui, par ailleurs sont fonctionnels).
Il y a 21 afficheurs 7 segments à câbler, plus les lumineux On/Off, Pitch/AoA, etc... :siffle:
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 11 March 2018, 09:44:37
Et j'allais oublier la fonction "Main", celle qui appelle les autres, à mettre tout à la fin du script:
Code: [Select]
--********************************************************************************
-- ********** begin program ************************* begin program ***************
-- ********************************************************************************
note = oapi.create_annotation()
note:set_pos (0.55,0.1,0.8,0.95)
note:set_colour ({r=0.9,g=0.5,b=0.2})


intro = "Lecture des données du Xr2 Ravenstar"
note:set_text(intro)
proc.wait_sysdt(1)

note:set_text("  ")
proc.wait_sysdt(0.5)

data_path = 'Scenarios/(Current state).scn'
note:set_text(data_path)
proc.wait_sysdt(1)


v=vessel.get_focusinterface()
ship=v:get_classname()
name_ship_focused=v:get_name()

-- ******************************************************
-- ***********begin call functions for scn file**********
-- ******************************************************
afficher=2   --value <>0 for screen display
sfirst = line_read (data_path)

slist = load_file (data_path,number_lines)

if  ship=='XR2Ravenstar' then
    lstatus = load_xr2_status (ship)
    note:set_text('Toward function loop load of XR2')
    proc.wait_sysdt(1)
note:set_text('')
 
-- ici, mettre la boucle de scrutation pour rafraîchissement des données du cockpit
elseif ship=='Xr5Vanguard' then
    note:set_text('Toward function loop load of XR5Vanguard')
    proc.wait_sysdt(2.01)
elseif ship=='ShuttleA' then
    note:set_text('Toward function loop load of ShuttleA')
    proc.wait_sysdt(2.01)
else
    note:set_text('vessel not implemented, simpit not activated')
    proc.wait_sysdt(2.01)
end
-- ******************************************************
-- ************ end call functions for scn file**********
-- ******************************************************
    note:set_text('End program')
    proc.wait_sysdt(1.5)
note:set_text('')
Title: Re: Le tableau de commande de Mars Bleu
Post by: jacquesmomo on 11 March 2018, 11:51:18
 :music: Aîe don't bien comprendre C++  :trucdeouf: It is impressionnant...  :eek: indeed!!!
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 11 March 2018, 23:21:53
Nan, c'est pas compliqué...  ;) Ce que nous avons ci-dessus, est en Lua. Ce script lit les données,
les met en forme pour les transmettre par le port USB. Dans l'Arduino tourne un sketch en C++, ou presque.
(Le langage Arduino est proche du C et du C++). Je l'ai fait pour qu'il reçoive ces données, les traite et gère
les lumineux par l'intermédiaire de modules Parallel Input Serial Output (PISO) et de modules Serial Input Parallel Output (SIPO) :mouais:
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 29 June 2018, 21:25:57
J'ai malheureusement été assez silencieux dernièrement.... Le peu de temps disponible a été mis à profit pour programmer les pilotes automatiques du Xr2. C'est le pilote auto d'attitude qui m'a le plus donné du fil à retordre.
En effet, il a fallu garder la cohérence du pilote du Xr2 avec l'affichage du pitch/AoA et du bank. Ceci malgré de nombreuses exceptions à gérer. En particulier le bank inversé, et les domaines de vol interdits.
De plus, j'ai relevé des incohérences dans le Xr2, auxquelles j'ai pu remédier dans une certaine mesure, mais
pas partout.
J'essaierai de faire un post montrant les solutions retenues pour l'assemblage des afficheurs numériques avant la
fin de la semaine prochaine.
Title: Re: Le tableau de commande de Mars Bleu
Post by: antoo on 29 June 2018, 23:27:43
Cool d'avoir des news !
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 30 June 2018, 09:59:54
Merci, Antoo.
J'ai vu que de ton côté, ça n'a pas l'air facile. J'espère que vous allez vous en sortir.
Malheureusement, je ne sais pas assez de choses pour pouvoir vous sortir de là.
Bon courage!
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 06 July 2018, 09:20:57
Comme hostingpics n'est plus, j'ai  hébergé des images chez casimages.
Un utilisateur de casimages sait-il quel lien utiliser pour les faire apparaître dans le texte?
J'ai essayé les liens proposés sans succès pour l'instant... Merci pour tout renseignement.
Title: Re: Le tableau de commande de Mars Bleu
Post by: jacquesmomo on 06 July 2018, 11:46:35
Moi, sur les conseils de Pappy2, j'utilise Zupimage
https://www.zupimages.net/

C'est gratuit, ça marche bien, et les liens aussi.
Donc, à tester.... :beer:
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 06 July 2018, 12:43:49
Merci, Jacquesmomo!
J'essaie ça tout de suite. Tant pis pour casimages...
Title: Re: Le tableau de commande de Mars Bleu
Post by: Mars Bleu on 06 July 2018, 15:12:24
Avant de partir en vacances, je tenais à vous faire part de....
Construction d'afficheurs


Il a fallu pas mal de tâtonnements pour arriver à un montage pratique. J'ai finalement choisi de placer
les displays et les convertisseurs BCD sur un ensemble de petites cartes empilées les unes sur les autres.

Pour commencer, les displays sont fixés sur des barrettes sécables elles mêmes soudées sur une petite
plaque à pastilles. Les câblage se fait en faisant arriver les 9 câbles sous les displays 7 segments (Vcc,
segment a, b, c, d, e, f et g, plus le DP), et au dessus de la plaque à trous. On peigne bien les câbles...
Et voilà ce que ça donne pour le display du contrôle d'attitude. Trois groupes de displays: de gauche
à droite, un groupe de deux displays pour le calibre (0.5°, ou bien 2.5°), un deuxième groupe de displays
pour le pitch, avec un signe "-", le troisième groupe pour l'affichage du bank.

ATTENTION: Les displays sont à anode commune. Pour allumer le segment, on met le segment à GND.

(https://zupimages.net/up/18/27/579z.jpg)


Notez que le 3° display à partir de la gauche a moins de câbles: il s'agit du signe moins du pitch.

L'image suivante montre une carte portant les CD4543 convertissant un demi-octet pour un affichage
sur les 7 segments. J'ai mis des résistances de 1kohms pour régler la luminosité.

(https://zupimages.net/up/18/27/vf86.jpg)

Ici, les cartes empilées. Il s'agit de l'afficheur "airspeed". Le premier groupe de trois afficheurs est là
pour la calibration: 25, 5, 1, ou 0.1 m/s. Le deuxième groupe de 5 afficheurs affiche la consigne "airspeed"
en m/s, et un chiffre après la virgule (DP)
(https://zupimages.net/up/18/27/vijy.jpg)

Là, autre point de vue...
(https://zupimages.net/up/18/27/nr7y.jpg)

Enfin, pour relier la sortie des modules SIPO concernés aux entrées des circuits BCD, j'ai dû faire pas mal
de neuro-chirurgie... (Quatre connecteurs 2X13 pôles, ça fait 104 soudures, tout de même!)
(https://zupimages.net/up/18/27/tkwd.jpg)

Après, "yapuka" faire les bons branchements et programmer tout ça...

Voilà un petit aperçu de ce que j'ai bricolé, en attendant les faces avant gravées au laser...

(https://nsm09.casimages.com/img/2018/07/06//18070608383823716615794775.jpg)

Prochainement, je vous raconterai comment j'ai programmé tout ça. A bientôt! :salut: