Era stagione di pin remoti....

Bene, sono qui a chiedere un consiglio. Primo descrivo la scena: niente che esca dal mio laboratorio, ma vorrei avere delle uscite distribuite, mi spiego: mettiamo di avere più arduino, che comunicano tra loro, ad esempio come le innumerevoli case domotiche modellino che vogliono mettere il cancello, qui sul forum. Bene io ho dunque enne, con enne intero e maggiore di uno, Arduini, che sono tra loro in connessione, usando quello che si vuole, canbus, rs485, Wi-Fi, magia . Ora dal posto di comando l'ammiraglio Nelson, che sono sempre io, vuole accendere, spegnere, interrogare, pwemmeare o analogoleggere un pin di un arduino remoto, chesso' all'altro lato del banco di lavoro, collegato via seriale, oppure dall'altro lato del sistema solare, collegato via le estensioni spaziali del protocollo tcp-ip. Insomma la parte ferraglia non mi interessa. Il mio domando è questo: Posto che io so farlo in maniera specifica, chesso', per accendere spedisco un byte specifico sulla seriale, e in fondo al filo lo slave legge quel byte e fa il lavoro, non è questo quello che cerco. Perché così sono costretto a scrivere una serie di comandi differenti per ogni possibile combinazione di azioni, connessioni, letture, slave Io cerco un metodo per fare una cosa del tipo: scrivi(pin,stato), interroga (pin), leggianalogico(pin), scrivipwm (pin, valore), intercambiabili con le corrispondenti digitalread ( ecc ecc, dove però pin può essere sia locale che remoto, al momento della scrittura non mi interessa, semmai al momento della inizializzazione. Il bello è che io sono convinto che qualcosa del genere esiste, agli albori della mia ardustoria ne avevo trovato traccia, mi sembra qui sul forum. Ma adesso non trovo più nulla, sbaglio a cercare o mi sono sognato tutto? Nel caso mi fossi sognato tutto, secondo voi si tratta di idea buona oppure di cacxata pazzesca? PS buona domenica

Mettiamo che sei connesso via seriale ai tuoi slave, potresti mandare una roba del genere:

IDSCHEDADigitalWrite(5,1)

Tutti gli slave riceveranno il comando ma solo quella interessata eseguirà il comando.

Potresti anche mettere tutto dentro una funzione: DigitalWriteRemote(ID, 5, 1);

e risparmiare caratteri sul comando da inviare: #ID-5-1 (ID-PIN-HIGH)

Guarda anche PJON

Grazie, Ho visto Pjon, mi sembra un gran bel lavoro, ma non è prorpio quello he intendo io, forse faccio confuzione. ci ponzo sopra un poco e poi vedo se nasce qualcosa. perchè, e qui scrivo liberamente, senza un pensioero antecedente, anche Pjon si limita a interpretare, con codice Ad Hoc e scritto nello scketch i comandi arbitrari che gli vengono spediti da un master io pensavo ad una libreria di remotaggio, mi si passi il termine, che offre comandi standardizzai e trasmette pacchetti "ignoti" allo scketc (come vacca si scrive questa parola....), pacchetti noti solo a lei, che non interessano allo "end user" OK OK, digestione pesante, adesso alka seltzer

Non so se ho capito…

esempio:

mettiamo che ho la libreria “Comandoremoto” e la importo su master e slave.

Dal master utilizzo la funzione DigitalWriteRemote(ID, 5, 1); contenuta nella libreria. Dalla parte dello slave, senza scrivere una sola riga di codice, il led collegato al pin 5 si accende.

E’ questo che intendi?

Ecco si,una cosa simile, inizializzo gli slave dando indirizzo e pin resi disponibili, inizializzare il master dando la lista dei pin disponibili presso gli slave e, correttamente, specifico il canale di trasmissione chesso' seriale o pjon o internet E poi gli slave non hanno codice dedicato

... un po' quello che fa la libreria "Firmata".

QUI un vecchio WiKi.

Guglielmo

Mica male, grazie, se ho ben capito va solo da pc a arduino, ma stasera me la smonto e imparo

… in pratica, lato Arduino, è un “interprete” di comandi. Poi, che i comandi li mandi da PC o li mandi da qualche altra cosa … lato Arduino è ininfluente.

Guglielmo

Beh, sono qui perchè avevo bisogno, per un mio progetto di una casa modello domotizzata di mettere alcuni arduino, forse 3 o 4 in giro per il modello e comandare e interrogare i pin remoti.
ne ho giaà parlato all’inizio di quasta discussione
So che esiste blink e firmata e anche una cosa chiamata theremino, ma non mi sono trovato con nessuno dei tre, avevo bisogno di una cosa contemporanemanete piu’ grezza, ma anche piu’ universale
Non sono capace di programmare in C++, anche in C un poco zoppico, ma ho tirato fuori una cosa che potrebbe essere interessante
Scritta tutta in C dovrebbe essere abbastanza hardware independant da girara magari anche su quelle imitazioni di arduino che sono le nodemcu, non so, magari ne prendo una e provo
non usa un canale specifico di comunicazione, ma prende un puntatore a Stream e usa quello
ha un minimo di rilevamento errore e ri-tentativo, ma queste cose dovrebbero piuù essere a carico del canale di comunicazione che dell’esecutore di ordini
segnala con un codice di errore l’eventuale mancata comunicazione o errore nel comando
NOn,e questo mi preoccupa un poco, dicevo non controlla la correttezza di quello che si fa, esattamente come potete scrivere sul pin 1 mentre va la seriale, qui potete scrivere o cambiare il pinmode di un pin remoto già impegnato, conoscere la topologie della rete e sapere chi puo’ fare cosa è compito del programmatore

Andate avanti, che c’è una nuova versione di libreria, nella prossima pagine

keywords.txt (886 Bytes)

PinRemoti.h (15.6 KB)

Vado avanti qui, che ho una connessione erratica e ho perso un paio di volte il messaggio, adesso è postato e non si perde più come si usa?
si include la libreria, la potete mettere nella cartella libriries, in una sottocartella sua, io naturlamente la ho chiamata pinremoti
si apre un canale di comunicazione (uno Stream) e lo si passa alla funzione apposita
la funzione apposita: essì, non sapendo programmare in CPP ho fatto tutto in C e funzioni
c’è un esempio, che vi allego qui, e magari ci sta anche in chiaro

// Era stagione di Pin remoti
// Nelson StandardOil


/*  permette il (tele)comando di Pin su arduino remoti
    come si usa:

    sulla/e macchina/e controllata/e si richiama periodicamente la funzione
    remotaggio() senza argomenti
     questa funzione si occupa di tutta la gestione degli ordini da remoto
     il loro riconoscimento, la loro esecuzione, dare conferma di esecuzione
     ed eventualmente restituire il valore letto da una digitalRead o una analogRead

    sulla/e macchina/e controllante/i si richiamano le funzioni
    remotePinMode()
    remoteDigitalWrite()
    remoteDigitalRead()
    remoteAnalogRead()
    remoteAnalogWrite()
      che a parte un primo argomento indicante la macchina controllata sono
      equivalenti a quelle normalmente usate

    Inizializazione
    si definisce l'indirizzo della macchina con una
     remotoindirizzo(char indirizzo), che accetta un carattere (una char) e lo considera come
     l'indirizzo assegnato alla macchina, restituisce in un char l'indirizzo stesso
     se chiamata senza argomenti restituisce l'indirizzo assegnato
    Si assegna eventualmente un time-out adeguato al canale utilizzato
     remototimeout(int timeout), ha valore di default 10ms
     se chiamata senza argomenti restituisce il timeout attivo
    Si assegna un oggetto di tipo Stream alla comunicazione con:
     remotoflusso(Stream* oggettoditipostream)
     anche questa se chiamata senza argomenti restituisce il puntatore allo Stream utilizzato
    Se serve conoscere se l'ultimo comando è andato a buon fine si puo' fare
     un test con la remotoerrore()
     se chiamata senza argomenti restituisce l'ultimo errore
     se chiamata con argomento setta l'errore
     se chiamata con argomento 0 azzera l'errore

    UNA NOTA SULLA SICUREZZA
      Queste funzioni NON e ripeto NON controllano alcunchè
      se in un programma "locale" usate come output un input,
      indirizzate PWM un pin che PWM non è o cose simili avrete dei
      malfunzionamenti
      ANCHE IN UN PROGRAMMA "REMOTO", la correttezza dei pin
      e la conoscenza "topologica" della vostra configurazione
                   e' VOSTRA RESPONSABILITA'


*/

// dichiarazione delle librerie
#include <SoftwareSerial.h>
SoftwareSerial canale(2, 3); // RX, TX


#include <PinRemoti.h>

void setup()
{
    Serial.begin(9600);
    canale.begin(1200);
    remotoflusso(&canale);

    if (analogRead(14) > 100)
    {
        remotoindirizzo('B');
        Serial.print(F("Gestione pin remoti, unita': "));
        Serial.println(remotoindirizzo());
        Serial.println("ricevitore");
    }
    else
    {
        remotoindirizzo('A');
        remotePinMode('B', 13, OUTPUT);
        remotePinMode('B', 9, OUTPUT);
        Serial.print(F("Gestione pin remoti, unita': "));
        Serial.println(remotoindirizzo());
        Serial.println("trasmettitore");
    }
}


void loop()
{
    if (remotoindirizzo() == 'A')
    {
        remoteDigitalWrite('B', 13, HIGH);

        if (remotoerrore())
        {
            Serial.println("errore di comunicazione");
        }

        if (remoteDigitalRead('B', 13))
        {
            Serial.println("Led acceso");
        }
        else
        {
            Serial.println("Mancata accensione led, consiglio ripetere pinMode");
        }

        delay(1000);
        remoteAnalogWrite('B', 9, 250);

        if (remotoerrore())
        {
            Serial.println("errore di comunicazione");
        }

        delay(1000);
        remoteDigitalWrite('B',  13, LOW);

        if (remotoerrore())
        {
            Serial.println("errore di comunicazione");
        }

        if (!remoteDigitalRead('B', 13))
        {
            Serial.println("Led spento");
        }
        else
        {
            Serial.println("Mancato spegnimento led");
        }

        delay(1000);
        remoteAnalogWrite('B', 9, 16);

        if (remotoerrore())
        {
            Serial.println("errore di comunicazione");
        }

        delay(1000);
        Serial.println(remoteAnalogRead('B', 14));

        if (remotoerrore())
        {
            Serial.println("errore di comunicazione");
        }
    }
    else
    {
        remotaggio();
    }
}

remotepinslave.ino (4.13 KB)

Scusate se scrivo sempre nuovi post, ma la mia connessione è erratica, quindi devo scrivere poco e postare spesso dicevo, nell'esempio trovate sia un trasmettitore che un ricevitore, sono pensati per usare due UNO a seconda se all'avvio trova o no un pin a massa (sempre mettere a massa con una resistenza) esegue la parte trasmettitore o la parte ricevitore per tutte e due le parti serve inizializzare una seriale (software) e passarla alla funzione poi per il ricevitore basta citare la remotaggio() ciclicamente per il trasmettitore usare le remotedigitalwrite e simili

a dopo che sento andare via la connessione

Siccome sono partiro da quancosa di trovato qui sul forum e da idee che avevo letto ci sono alcune limitazioni: le macchine si riconoscono con un carattere, io ho voluto usare lettere maiuscole, ma qualunque cosa non sia un \0 va bene (meglio però usare cose leggibili) oddio, a rigore non è vero; i caratteri codice 128 e 129 sono start e stop trasmissione, non usiamoli come nome di macchian, grazie

+1

Grazie, almeno uno di otto lo posso ringraziare. Altro da dire? Certo. La libreria è paritetica, ogni macchina può essere controllante, perché sia anche controllata basta richiamare regolarmente la remotaggio(). Questo permette a più macchine di comandarne altre, connessione molti a molti, diciamo cosi. Ma ci espone al rischio di collisione, più master che occupano lo stesso canale. Questo è un problema del canale, non dell'esecutore, ma magari in futuro penso a un embrione di arbitraggio Nulla impedisce a due macchine di scambiarsi. I ruoli, una volta comanda una, poi l'altra Si può anche, per completezza, dare il comando remoto usando il proprio stesso indirizzo, in quel caso la funzione viene eseguita localmente, non ce impegno del canale

Standardoil: Altro da dire?

scusa ma sono troppo ignorante per conversare costruttivamente sui protocolli di comunicazione, se non quelle due cose scritte ad inizio thread.

Il +1 è anche un incoraggiamento a continuare, perchè ogni tanto fa anche piacere leggere un thread che non parli solo di led, blink, display e millis :P :D

Non lo ho detto, ma la macchina controllata può eseguire un suo codice, la funzione remotaggio() non è bloccante, anzi è piuttosto veloce se non ha nulla da ricevere, elabora anche l'input byte a byte, per velocizzare Mi raccomando di non fare tra controllante e controllata cose antitetiche, non provate a mettere output alto da remoto pin che in locale avete dichiarato input pullup, si rovinerebbe la mcu Stasera vorrei fare delle prove di velocità

OK, ho fatto delle prove di velocità ed ho scoperto un piccolo errore
cominciamo con l’errore: era sbagliata la gestione del timeout, risultava costante e non programmabile
ho corretto la libreria
tempi:
la remotaggio() da sola senza nulla da fare impiega da 15 a 30 microsecondi, ho fatto delle misure alla buona
le azioni piu’ o meno impegnano tutte lo stesso tempo,
a 1200 bps tra 25000 e 350000 microsecondi alla macchina controllata
tra 30000 e 45000 microsecondi alla macchina controllante
, che mi sembrano ancora un tempo ragionevole per la domotica
stranamente la analogwrite è sempre mediamente più veloce delle altre
cambiare il timeout influsice solo su canale dsturbato, le funzioni restituiscono fallito dopo un tempo massimo di 5 volte il timeout (io avevo calcolato 3, aiutatemi a capire dove ho sbagliato, grazie)
cambiare la velocità non cambia tanto quanto si pou’ pensare il tempo
passare a 9600 fa schedere i tempi a circa 16000 microsecondi sul ricevitore e 25000 al trasmettitore
in compenso diventano molto più stabili, molto meno variabili
metto qui il programma che ho usato per provare i tempi

// Era stagione di Pin remoti
// Nelson StandardOil
// Versione che misura i tempi

// dichiarazione delle librerie
#include <SoftwareSerial.h>
SoftwareSerial canale(2, 3); // RX, TX

#include <PinRemoti.h>

// variabili per i tempi
unsigned long int inizio;
unsigned long int durata;
unsigned long int massimo;
unsigned long int minimo;
unsigned long int mostra;




void setup()
{
    Serial.begin(9600);
    canale.begin(9600);
    remotoflusso(&canale);
    remototimeout(100);

    if (analogRead(14) > 100)
    {
        remotoindirizzo('B');
        Serial.print(F("Gestione pin remoti, unita': "));
        Serial.println(remotoindirizzo());
        Serial.println("ricevitore");
    }
    else
    {
        remotoindirizzo('A');
        Serial.print(F("Gestione pin remoti, unita': "));
        Serial.println(remotoindirizzo());
        Serial.println("trasmettitore");
    }
}


void loop()
{
    if (remotoindirizzo() == 'A')
    {
        if (Serial.available())
        {
            char cx = Serial.read();

            switch (cx)
            {
                case 'm':
                    // pinmode
                    inizio = micros();
                    remotePinMode('B', 13, OUTPUT);
                    durata = micros() - inizio;

                    if (remotoerrore())
                    {
                        Serial.println("errore di comunicazione");
                    }

                    Serial.print("Pinmode, durata: ");
                    Serial.println(durata);
                    // attivo anche l'altro piedino
                    remotePinMode('B', 13, OUTPUT);

                    // non serve misurare
                    if (remotoerrore())
                    {
                        Serial.println("errore di comunicazione");
                    }

                    break;

                case 'a':
                    // accendo
                    inizio = micros();
                    remoteDigitalWrite('B', 13, HIGH);
                    durata = micros() - inizio;

                    if (remotoerrore())
                    {
                        Serial.println("errore di comunicazione");
                    }

                    if (remoteDigitalRead('B', 13))
                    {
                        Serial.println("Led acceso");
                    }
                    else
                    {
                        Serial.println("Mancata accensione led, consiglio ripetere pinMode");
                    }

                    Serial.print("Digitalwrite HIGH, durata: ");
                    Serial.println(durata);
                    break;

                case 's':
                    // spengo
                    inizio = micros();
                    remoteDigitalWrite('B', 13, LOW);
                    durata = micros() - inizio;

                    if (remotoerrore())
                    {
                        Serial.println("errore di comunicazione");
                    }

                    if (!remoteDigitalRead('B', 13))
                    {
                        Serial.println("Led spento");
                    }
                    else
                    {
                        Serial.println("Mancato spegnimento led, consiglio ripetere pinMode");
                    }

                    Serial.print("Digitalwrite LOW, durata: ");
                    Serial.println(durata);
                    break;

                case 'q':
                    // attivo PWM
                    inizio = micros();
                    remoteAnalogWrite('B', 9, 250);
                    durata = micros() - inizio;

                    if (remotoerrore())
                    {
                        Serial.println("errore di comunicazione");
                    }

                    Serial.print("Analogwrite, durata: ");
                    Serial.println(durata);
                    break;

                case 'w':
                    // attivo PWM
                    inizio = micros();
                    remoteAnalogWrite('B', 9, 50);
                    durata = micros() - inizio;

                    if (remotoerrore())
                    {
                        Serial.println("errore di comunicazione");
                    }

                    Serial.print("Analogwrite, durata: ");
                    Serial.println(durata);
                    break;

                case 'r':
                    // leggo analogico
                    inizio = micros();
                    remoteAnalogRead('B', 14);
                    durata = micros() - inizio;

                    if (remotoerrore())
                    {
                        Serial.println("errore di comunicazione");
                    }

                    Serial.print("Analogread, durata: ");
                    Serial.println(durata);
                    break;

                case 'e':
                    // leggo digitale
                    inizio = micros();
                    remoteDigitalRead('B', 13);
                    durata = micros() - inizio;

                    if (remotoerrore())
                    {
                        Serial.println("errore di comunicazione");
                    }

                    Serial.print("Digitalread, durata: ");
                    Serial.println(durata);
                    break;

                default:
                    break;
            }
        }
    }
    else
    {
        if (Serial.available())
        {
            // un carattere disponibile
            char cx = Serial.read();

            if (cx == '0')
            {
                // resetto i tempi
                massimo = 0;
                minimo = 100;
            }
        }

        inizio = micros();
        remotaggio();
        durata = micros() - inizio;

        if (massimo < durata)
        {
            massimo = durata;
            Serial.print("Trovato nuovo massimo: ");
            Serial.println(massimo);
            Serial.print("minimo: ");
            Serial.println(minimo);
        }

        if (minimo > durata)
        {
            minimo = durata;
            Serial.print(" Trovato nuovo minimo: ");
            Serial.println(minimo);
        }
    }
}

e anche allego la nuova versione della libreria
dove ho messo argomento di default a zero per la funzione remototimeout

PinRemoti.h (15.6 KB)

Ho scovato questa libreria (non l'ho provata) che legge lo stato dei pin, potrebbe tornarti utile per inserire un controllo

Grazie, ci guardo

Ciao ragazzi, a me quello a cui state pensado sembra veramente quello che fa Firmata. Firmata non fa altro che standardizzare i comandi per le chiamate a sistema dell’arduino e permettere che questi vengano comunicati dall’esterno e interpretati da una sorta di virtual machine interna al device. Considerate che un interprete sull’arduino gira a velocita’ comiche, se in piu’ i comandi letti dall’interprete vengono mandati da un altro device attraverso un canale di comunicazione diventa tutto pressoche’ inutile. Ad esempio solo chiamando digitalWrite(13, HIGH); delay(10); digitalWrite(13, LOW); e misurando il tempo richiesto per l’esecuzione di questi 3 comandi o misurando con l’oscilloscopio la durata effettiva del delay, e’ possibile comprendere quanto questo approccio sia poco efficace. Per esempio utilizzando questo approccio sarebbe problematico attuare velocemente i pin per effettuare una lettura da un sensore o generare un impulso binario.

E’ sicuramente piu’ sicuro ed efficace inviare un pacchetto che simboleggia una chiamata ad una funzione piu’ complessa, che puo’ essere composta da centiana di comandi ed essere al sicuro gia nella memoria del device target. Con approccio Firmata la stessa funzione occupa un sacco di banda e’ enormemente piu’ lenta ad essere eseguita e durante la trasmissione qualcosa potrebbe sempre andare storto per colpa dell’interferenza.