Connecter plusieurs PC sur le même Arduino

Je suppose que oui.... Sinon, il n'aurait même pas besoin d'un arduino, juste d'un bouton poussoir pour ouvrir la coupole. :face_without_mouth:

Bonsoir axelmaux

Le sens de ma question était, est ce que le programme Astro est indispensable, ou une autre façon de faire, comme une page Web était envisageable.

Cordialement
jpbbricole

De ce que je crois comprendre, le système sert à automatiser des acquisitions. Le logiciel ouvre la coupole, fait une série de prise de vue, referme la coupole.

@jpbbricole ah oui... J'avais mal compris.

La difficulté vient du fait que @thierry-astro veut utiliser 4 instances du logicel astro (qui ne communiquent pas ensemble) pour commander une seule interface d'ouverture.

Oui, ça joue pour faire ça avec un Arduino Méga, on peut répondre à l'instance du programme qui envoie la commande.

1 Like

@thierry-astro les 4 mini-pc et l'Arduino sont proche physiquement?

Oui les 4 PC sont proches physiquement et le wifi est disponible sur le site. Une information qui peut être important avec le logiciel N.I.N.A, il faut créer un profil pour chaque télescopique, avec le même profil il n'est pas possible de piloter deux télescopes. c'est pour cela que nous mettons un mini PC sur chaque setup. Jpbbricole a très bien résumé le rôle du logiciel qui sert à automatiser toutes les étapes des acquisitions et à gérer la coupole.

Compliqué d’écouter avec cette bibliothèque plusieurs ports les uns à la suite des autres car available() ne répondra OK que si un octet a été reçu correctement mais le transfert nécessite la réception de 10 bits donc si vous basculez entre les ports virtuels vous avez de fortes chances de rater une partie de la communication.

Si vous en avez uniquement 4 achetez un arduino mega et 3 adapteurs usb série et remplacez le uno.

Un PC sera connecté en usb et les autres par l’adaptateur aux ports matériels

Pour 4 ports série matériels, le code est simple, voici un exemple

class MiniPC {
  private:
    HardwareSerial *uart;

    static constexpr int debitBaud = 9600;
    static constexpr int brocheCapteurPorteOuverte = 10;
    static constexpr int brocheCapteurPorteFermee = 12;
    static constexpr int brocheRelais = 7;
    enum { OUVRIR = 'O', FERMER = 'C', STATUT = 'S', VERSION = '?', FORCER = '!' };

  public:
    MiniPC(HardwareSerial &port) : uart(&port) {}

    void configurer() {
      uart->begin(debitBaud);
      pinMode(brocheCapteurPorteOuverte, INPUT);
      pinMode(brocheCapteurPorteFermee, INPUT);
      pinMode(brocheRelais, OUTPUT);
      digitalWrite(brocheRelais, HIGH);
    }

    void ecouter() {
      switch (uart->read()) {
        case STATUT:  obtenirStatutPorte(); break;
        case OUVRIR:  ouvrirPorte();        break;
        case FERMER:  fermerPorte();        break;
        case VERSION: envoyerVersion();     break;
        case FORCER:  deplacerPorte();      break;
        default: break;
      }
    }

  private:
    static bool porteEstOuverte() {
      return HIGH == digitalRead(brocheCapteurPorteOuverte);
    }

    static bool porteEstFermee() {
      return HIGH == digitalRead(brocheCapteurPorteFermee);
    }

    static void ouvrirPorte() {
      if (!porteEstFermee() && porteEstOuverte()) deplacerPorte();
    }

    static void fermerPorte() {
      if (!porteEstFermee() && porteEstOuverte()) deplacerPorte();
    }

    static void deplacerPorte() {
      digitalWrite(brocheRelais, LOW);
      delay(500);
      digitalWrite(brocheRelais, HIGH);
    }

    void obtenirStatutPorte() {
      if (porteEstOuverte()) uart->write('O');
      else if (porteEstFermee()) uart->write('C');
      else uart->write('M');
    }

    void envoyerVersion() {
      uart->print(F("1.0"));
    }
};

// on définit les 4 ports d'écoute
MiniPC pcs[] = {MiniPC(Serial), MiniPC(Serial1), MiniPC(Serial2), MiniPC(Serial3)};

void setup() {
  for (MiniPC& pc : pcs) pc.configurer(); // on configure chaque interface
}

void loop() {
  for (MiniPC& pc : pcs) pc.ecouter();    // on écoute chaque interface
}

non testé bien entendu :slight_smile:

  • un des mini-PC est connecté directement sur le port usb du MEGA
  • les autres utilisent un Module adaptateur série FT232RL FTDI connecté d'un côté en USB au PC et de l'autres aux pins Tx et Rx du port Serial souhaité. Penser à connecter aussi le GND.

idéalement il faudrait bricoler un peu le Mega pour que l'ouverture du port série ne déclenche pas un reboot en mettant (après avoir chargé le code une fois pour toutes) un condensateur de 100 nanofarad entre le pin Reset et le GND du MEGA.

PS/ à noter que pour la lisibilité j'ai conservé ouvrirPorte() et fermerPorte() comme deux fonctions différentes alors que le code est le même, je suppose que le relai fonctionne en envoyant une impulsion (500ms est sans doute long) et que cela inverse automatiquement la position de la porte.

Un code un peu plus propre testerait les contacteur de fin de course pour s'assurer que la commande est bien terminée, là vous balancez l'ordre mais ne savez pas ce qu'il s'est passé.

Sinon, une autre solution pourrait être de mettre une carte Arduino NANO par PC, et de toute les connecter en I2C a une carte maître qui gère l'ouverture.

Vue qu'une carte Arduino NANO ne coûte que 3-4€ et qu'il y a moyen d'en mettre plus de 4 sur le bus I2C, alors qu'une carte Arduino MEGA coûte 30-40€, sa peut être intéressant...

J'y vois l'avantage de la simplicité, même si sa veut dire acheter plusieurs cartes qui seront clairement sous employés.

Le code est moins simple cependant — je suppose que vous proposez de le développer ?

vous ne pouvez pas parler d'un clone de Nano à 3€ et comparer au prix d'une MEGA "officielle". Une Mega 2560 PRO MINI c'est 10€ et 3 adaptateurs FTDI à 1€ pièce environ en commande en Asie.

Sinon comparer le prix de la Nano officielle, environ 30€ (26,40€ + livraison) x 4

Non, je ne maîtrise pas l'I2C, malheureusement, mais il me semble que s'est plus simple a faire...

Mais peut être que je me trompe, désolé.

comment pouvez vous juger que c'est plus simple si vous ne maîtriser pas ce type de communication ? ça me dépasse.

Non ce n'est pas plus simple, avec 4 ports UART vous avez 4 buffers matériels séparés et donc une vraie gestion possible de la communication asynchrone en parallèle avec identification directe de l'émetteur alors que vous aurez un seul bus en I2C et à gérer vous même les communications qui potentiellement se superposent, mémoriser l'émetteur pour lui répondre en cas d'interrogation etc...

C'est 100x plus simple avec une UART et la classe HardwareSerial fournie avec Arduino.

D'accord, alors excusez moi, je me base simplement sur mon expérience personnelle et mes connaissances pour proposer un idée...

Pour moi, cette solution était plus simple, visiblement sa n'est pas votre avis, OK.
Vous êtes plus expérimentés, donc vous avez sûrement raison...

Je ne maîtrise pas ce type de communication au sens où je ne sais pas dépanner un problème, ou coder tout un système I2C, mais j'ai déjà utilisé des code pour l'I2C sans rencontrer de grande difficulté, alors que je n'ai jamais vraiment réussis a utiliser les ports UART de l'Arduino MEGA.

Bonjour guillaume_lrt

C'est le principe du forum, je l'applique également :wink:
J'aime beaucoup travailler l'i2C, on peut aller assez "loin" avec, j'y avais aussi pensé, mais dans le cas présent, @thierry-astro a un programme qui tourne, il suffit d'y "greffer" la gestion de plusieurs ports (je suis entrain de le faire).

Bonne journée
jpbbricole

Si tous les mini-pc et l'arduino sont proche, la solution de @jpbbricole est la plus simple et la plus économique.

L'idée n'est pas mauvaise, et c'est bien de proposer des alternatives.

L'implémentation est moins facile cependant.

Merci à tous d'avoir bien pris le temps de regarder et de me donner différentes solutions, je vous en remercie tous mais l'idée de J-M-L me convient parfaitement. Je vais me procurer l'Arduino Mega ainsi que les modules USB série FT232 et me mettre au travail, je vous tiendrai informé une fois les tests effectués. Sincères salutations.

Bonjour thierry-astro

J'ai adapté ton programme pour 4 utilisateurs (Serial, Serial1, Serial2 et Serial3)
En cas de réponse, commandes ? et S, la réponse est envoyée à l'utilisateur, exemple pour ?:
portSerie[user]->print("1.0"); // Réponse àl'utilisateur du port série

Le programme:

/*
Name:       AF_thierry_astro_MultiplesPc.ino
Created:	31.03.2025
Author:     thierry_astro/jpbbricole/IA
Remarque:	Plusieurs PC transmettent sur un Arduino
			https://forum.arduino.cc/t/connecter-plusieurs-pc-sur-le-meme-arduino/1368868
*/
// Variables
int doorPin  = 10;
int doorPinClose  = 12;
int relayPin = 7;
byte inByte = 0;
int doorState = 0;
int doorStateClose = 0;

// Le protocole de communication avec le driver ASCOM est assez simple et repose sur 5 commandes de base que voici:

int OD = 79;          // Open door, le driver ASCOM va transmettre un O (OPEN)soit le code ascii 79
int CD = 67;          // Close door, le driver ASCOM va transmettre un C (CLOSE) soit le code ascii 67
int DS = 83;          // Door status, le driver ASCOM va transmettre un S (STATUS) soit le code ascii 83
int INFOVERSION = 63; // Info version du code de la carte Arduino, le driver ASCOM va transmettre un ? soit le code ascii 63
int BYPASS = 33;      // Permet de bypasser la vérification des capteurs et de faire déplacer le toit, le driver ASCOM va transmetrte un ! soit le code ascii 33

// Porta série
HardwareSerial* portSerie[] = {&Serial,  &Serial1, &Serial2, &Serial3}; // Tableau des ports série (sans Serial)
const int portSerieNombre = sizeof(portSerie) / sizeof(portSerie[0]);  // Nombre de ports série dans le tableau

void setup()
{
	for (int i = 0; i < portSerieNombre; i++)
	{
		portSerie[i]->begin(9600); // Initialiser tous les ports série à 9600 bauds
	}
	digitalWrite(relayPin, HIGH);
	pinMode(doorPin, INPUT);
	pinMode(doorPinClose, INPUT);
	pinMode(relayPin, OUTPUT);
	//Serial.begin(9600);
	Serial.println("\nUn Arduino pour " + String(portSerieNombre) + " PC")	;
}

// La loop attend une commande provenant du driver ASCOM

void loop()
{
	for (int s = 0; s < portSerieNombre; s++)
	{
		if (portSerie[s]->available())  // Vérifie si des données sont disponibles
		{
			inByte = portSerie[s]->read(); // Lecture de l'octet
			commandeExecute(inByte, s); // Exécute la commande s = utilisateur (port série)
		}
	}
	
	delay(100);
	
}

// Exécution de la commande
void commandeExecute(int inByte, int serialUser)
{
	if (inByte == DS) // Si le driver ASCOM transmet un S pour STATUT, alors on va retourner le statut du toit (O pour OPEN ou C pour CLOSE)
	{
		GetDoorState(serialUser);
	}
	
	if (inByte == OD ) // Si le driver ASCOM transmet un O pour OPEN DOOR, alors on va ouvrir le toit
	{
		OpenDoor();
	}
	
	if (inByte == CD ) // Si le driver ASCOM transmet un C pour CLOSE DOOR, alors on va fermer le toit
	{
		CloseDoor();
	}
	
	
	if (inByte == INFOVERSION ) // Si le driver ASCOM transmet un ? pour INFO VERSION, alors on va retourner la version du code de la carte Arduino
	{
		InfoVersion(serialUser);
	}
	
	
	if (inByte == BYPASS ) // Si le driver ASCOM transmet un ! pour MOVE DOOR, alors on va ouvrir ou fermer le toit dans la vérification sur la position la porte
	{
		moveDoor();
	}
}

// Cette fonction permet de fermer le toit, elle va cependant s'assurer que le toit est bien en position OUVERT avant.

void CloseDoor()
{
	doorStateClose = digitalRead(doorPinClose); // Interrogation du sensor (contact magnétique du toit en position CLOSE) attribué à l'état CLOSE
	doorState = digitalRead(doorPin);           // Interrogation du sensor (contact magnétique du toit en position OPEN)attribué à l'état OPEN
	if (! (HIGH == doorStateClose && HIGH == doorState ) )  // On s'assure que le toit est bien en position OPEN
	{
		if (HIGH == doorStateClose)
		{
			moveDoor();
		}
	}
}


// Cette fonction permet d'ouvrir le toit, elle va cependant s'assurer que le toit est bien en position CLOSE avant.

void OpenDoor()
{
	doorStateClose = digitalRead(doorPinClose); // Interrogation du sensor (contact magnétique toit FERMÉ)attribué à l'état CLOSE
	doorState = digitalRead(doorPin);           // Interrogation du sensor (contact magnétique toit OUVERT)attribué à l'état OPEN
	if (! (HIGH == doorStateClose && HIGH == doorState ) ) // On s'assure que le toit est bien en position (fermé)CLOSE
	{
		if (HIGH == doorState)
		{
			moveDoor();
		}
	}
}


// Cette fonction retourne le statut du toit: OPEN, CLOSE ou en MOVE
// Le statut est retourné au driver ASCOM via un port série

void GetDoorState(int user)
{
	doorState = digitalRead(doorPin);
	if (LOW == doorState)
	{
		portSerie[user]->print("O");
		//Serial.print("O");
		
	}
	doorStateClose = digitalRead(doorPinClose);
	if (LOW == doorStateClose)
	{
		portSerie[user]->print("C");
		//Serial.print("C");
	}

	if (HIGH == doorStateClose && HIGH == doorState )
	{
		portSerie[user]->print("M"); // Réponse àl'utilisateur du port série
		//Serial.print("M");
	}
	
	
	delay(200);
}


// Cette fonction retourne la version du code Arduino
void InfoVersion(int user)
{
	//Serial.print("1.0");
	portSerie[user]->print("1.0"); // Réponse àl'utilisateur du port série
}


// Cette fonction actionne le relais afin de faire déplacer le toit
void moveDoor()
{
	digitalWrite(relayPin, LOW);
	delay(500);
	digitalWrite(relayPin, HIGH);
}

C'est testé, fonctionne.

N'hésites pas à poser des questions :wink:

Bonne journée
jpbbricole

1 Like