Mandare array da arduino a raspberry

Ciao a tutti,
vorrei inviare un array di dati (float) da arduino a raspberry; sono riuscito per ora a collegare i due dispositivi (tramite i2c e convertitore di livelli logici) e passare una variabile intera da arduino a raspberry.
Non so proprio come fare per inviare un array di dati (non sono espertissimo dell'ambiente).
grazie per l'aiuto!
questo è il codice funzionante per mandare la variabile "a" a raspberry:

#include <Wire.h>

#define SLAVE_ADDRESS 0x04
int a = 100;

void setup() {
pinMode(13, OUTPUT);
Serial.begin(9600); // start serial for output
// initialize i2c as slave
Wire.begin(SLAVE_ADDRESS);

// define callbacks for i2c communication
Wire.onRequest(sendData);

}

void loop() {
delay(100);
}


// callback for sending data
void sendData(){
Wire.write(a);

}

Ciao, devo dire che non sono espertissimo del protocollo i2c e libreria wire.h, perciò prendi con le pinze quello che dico, potrebbe non essere esatto.

Da quel che ho capito, tramite i2c e wire.h, puoi trasmettere solo, byte, stringhe di byte, e array di byte, di conseguenza non hai un metodo diretto per trasmettere un array di float.

Se tu sei in grado di ricevere una stringa con raspberry, potresti inviare l'array di float , elemento per elemento sotto forma di stringa.

esistono implementazioni in c, della funzione ftoa() che trasforma un float in un array di char, che poi puoi trasmettere con write.
ecco un sito dovo sono implementate le funzioni necessarie, compatibili con arduino, linguaggio C.

La cosa si preannuncia, impegnativa e non semplice, sarebbe meglio se si potesse utilizzare la normale comunicazione seriale.

Grazie per la celere risposta.
capisco il problema...quindi il miglior metodo per passare dati da arduino a raspberry sarebbe?

in sostanza dovrei leggere le temperature da una serie di sensori, e sfruttare i pin analogici di arduino per i sensori di corrente; raspberry deve solo ricevere i valori letti dai sensori da arduino....

Ti propongo la soluzione, che adotterei io, visto che è facile trasmettere due interi con la libreria write.h
dividerei il valore float, in due numeri, che invierei a raspberry come due interi.

Esempio

float temperatura=10.25;
float appoggio=0;

int intero=(int)temperatura; //intero contiene il valore 10

appoggio=temperatura-intero;

int decimali=(int)(appoggio*10); //decimali contiene 2

wire.write(intero);
wire.write(decimali);

quando poi ricevi questi interi, puoi ricomporli in un float su rasperry

valore=intero+(decimali/10);

ok giusto, a me allora basta mandare interi...il problema è che se io scrivo:

wire.write(intero);
wire.write(decimali);

raspberry mi legge solo l'ultima variabile...quindi decimali...

non so come si programma su quella scheda, ma dovresti fare in questo modo.

arduino invia il primo intero e si mette in attesa di una risposta con while e read

raspberry riceve il primo intero e trasmette un segnale di "ricevuto" basta un numero

arduino riceve il segnale, e trasmette il secondo numero

raspberry riceve il secondo numero .

ok provo, se riesco posto la soluzione, grazie!

L'I2C è un protocollo seriale con word a 8bit, come suggerisce la tipologia di protocollo il metodo piu sensato per mandare i dati è serializzarli in un vettore di parole(byte). Per questi compiti è comoda l'implementazione di strutture.

strcut{
int a;
float b;
double c;
char d[10];
} frame;

Implementata la struttura sui due dispositivi (avendo l'accuratezza di verificare e gestire la compatibilità tra tipi) il compito risulta molto semplice, invio la serie di byte che inizia a &frame e finisce a &frame + sizeof(frame) - 1.

Wire.write(&frame, sizeof(frame));

Dall'altra parte non mi rimane che leggere i byte e collocarli serialmente al loro posto, il primo andrà all'indirizzo &frame il secondo a &frame+1 cosi via fino a &frame+sizeof(frame)-1. L'implementazione della lettura con una buona libraria I2C alle spalle si esegue anche con 3 comandi in croce.

@RobertoBochet, ti ringrazio anche io perché ho imparato qualcosa di nuovo :slight_smile: , mi dispiace solo di aver consigliato metodi "laboriosi" e poco efficaci, speriamo che legga prima di tribolare con altre soluzioni.

Hai consigliato il metodo derivato dalla tua esperienza, e va benissimo cosi. La potenza del forum sta nel esperienza cumulativa data dal numero di partecipanti. Il metodo da me consigliato è piu vicino al livello macchina cosi da evitare inutile complessità, il modello TCP/IP insegna.

Grazie, proverò anche questa!comunque ho risolto così,grazie al suggerimento di torn24:

codice arduino:

#include <Wire.h>

#define SLAVE_ADDRESS 0x04
int i = 0;
int a []= {50,60,70,80};


void setup() {
pinMode(13, OUTPUT);
Serial.begin(9600); // start serial for output
// initialize i2c as slave
Wire.begin(SLAVE_ADDRESS);

// define callbacks for i2c communication
Wire.onReceive(receiveData);
Wire.onRequest(sendData);

}

void loop() {
delay(100);
}

// callback for received data
void receiveData(int byteCount){

while(Wire.available()) {
i = Wire.read();
}
}


// callback for sending data
void sendData(){
Wire.write(a[i]);
}

codice raspberry:

import smbus

a = [0]*4

bus = smbus.SMBus(1)

for i in range (0,4):

 bus.write_byte(0x04, i)
 a[i] = bus.read_byte(0x04)


print (a)

RobertoBochet:
L'I2C è un protocollo seriale con word a 8bit, come suggerisce la tipologia di protocollo il metodo piu sensato per mandare i dati è serializzarli in un vettore di parole(byte). Per questi compiti è comoda l'implementazione di strutture.

strcut{

int a;
float b;
double c;
char d[10];
} frame;



Implementata la struttura sui due dispositivi (avendo l'accuratezza di verificare e gestire la compatibilità tra tipi) il compito risulta molto semplice, invio la serie di byte che inizia a &frame e finisce a &frame + sizeof(frame) - 1.


Wire.write(&frame, sizeof(frame));



Dall'altra parte non mi rimane che leggere i byte e collocarli serialmente al loro posto, il primo andrà all'indirizzo &frame il secondo a &frame+1 cosi via fino a &frame+sizeof(frame)-1. L'implementazione della lettura con una buona libraria I2C alle spalle si esegue anche con 3 comandi in croce.

RobertoBochet:
L'I2C è un protocollo seriale con word a 8bit, come suggerisce la tipologia di protocollo il metodo piu sensato per mandare i dati è serializzarli in un vettore di parole(byte). Per questi compiti è comoda l'implementazione di strutture.

strcut{

int a;
float b;
double c;
char d[10];
} frame;



Implementata la struttura sui due dispositivi (avendo l'accuratezza di verificare e gestire la compatibilità tra tipi) il compito risulta molto semplice, invio la serie di byte che inizia a &frame e finisce a &frame + sizeof(frame) - 1.


Wire.write(&frame, sizeof(frame));



Dall'altra parte non mi rimane che leggere i byte e collocarli serialmente al loro posto, il primo andrà all'indirizzo &frame il secondo a &frame+1 cosi via fino a &frame+sizeof(frame)-1. L'implementazione della lettura con una buona libraria I2C alle spalle si esegue anche con 3 comandi in croce.

Ciao,
volevo provare a mandare dati da arduino tramite il metodo delle strutture che mi hai consigliato, ma non ne vengo a capo. in particolare nell'espressione:

Wire.write(&frame, sizeof(frame));

mi dice:
expected primary-expression before ',' token

Ciao mi inserisco visto che sto facendo una cosa analoga per un robot quadrupode dove la parte di gestione meccanica è demandata a arduino e la parte di "ragionamento" a raspberry....chiaramente non so se hai dei motivi per farlo ma nel mio caso alla fine ho optato per la comunicazione seriale. nel mio caso invio matrici di numeri tramite la seriale (sotto forma di stringhe) e faccio il parser della stessa lato raspberry.
nel mio caso uso python come linguaggio lato raspberry e la lettura dei dati è semplice.....

raghi:
Ciao mi inserisco visto che sto facendo una cosa analoga per un robot quadrupode dove la parte di gestione meccanica è demandata a arduino e la parte di "ragionamento" a raspberry....chiaramente non so se hai dei motivi per farlo ma nel mio caso alla fine ho optato per la comunicazione seriale. nel mio caso invio matrici di numeri tramite la seriale (sotto forma di stringhe) e faccio il parser della stessa lato raspberry.
nel mio caso uso python come linguaggio lato raspberry e la lettura dei dati è semplice.....

Ciao..anch'io uso python lato rasp. Il protocollo i2c ho iniziato ad usarlo perché da ignorante non sapevo come affrontare la comunicazione in altri modi! Per cui se esiste un metodo migliore cambio sistema! Riesci per favore a darmi qualche dritta? Basta un esempio base..
Alla fine devo passare un array float di grandezza 15/20 (ancora non so la dimensione finale)
Grazie mille!

Guarda nel codice che ti ho postato io c'è un mancato cast che impedisce al compilatore di risolvere la funzione.
Dato che la funzione write dispone del prototipo
write(const char*, unsigned int)
Basta eseguire il cast del puntatore a frame in un puntatore a char

Wire.write((char*) &frame, sizeof(frame));

è magari scrivere struct e non strcut come nel codice che ti ho postato, chiedo venia.

raghi:
nel mio caso uso python come linguaggio lato raspberry e la lettura dei dati è semplice.....

Si grazie al cavolo su raspberry pi un parsing di testo ha un peso relativamente minore rispetto a quello che ha su AVR, nella comunicazione tra due dispositivi autonomi solitamente non ha senso impiegare linguaggio testuale, spero che tu ti riferisca ad inviare le matrici come array di byte, trattandola come matrice di generici ottetti.

Aspetta calmiamoci un attimo e pensiamo, I2C ha delle caratteristiche il protocollo seriale gestito da UART altre, se non hai bisogno delle caratteristiche di I2C perché lo stai impiegando?

RobertoBochet:
Guarda nel codice che ti ho postato io c'è un mancato cast che impedisce al compilatore di risolvere la funzione.
Dato che la funzione write dispone del prototipo
write(const char*, unsigned int)
Basta eseguire il cast del puntatore a frame in un puntatore a char

Wire.write((char*) &frame, sizeof(frame));

è magari scrivere struct e non strcut come nel codice che ti ho postato, chiedo venia.
Si grazie al cavolo su raspberry pi un parsing di testo ha un peso relativamente minore rispetto a quello che ha su AVR, nella comunicazione tra due dispositivi autonomi solitamente non ha senso impiegare linguaggio testuale, spero che tu ti riferisca ad inviare le matrici come array di byte, trattandola come matrice di generici ottetti.

Ottimo proverò così...grazie!

Comunque sto usando l'i2c perchè ho altri dispositivi già collegati, e mi risultava semplice collegare anche arduino come periferica per leggere i sensori (temperatura e potenza). Ma ripeto, se mi dite che ci sono altri protocolli provo a cambiare sistema...anche se per ora non saprei come fare!

Siamo in un ambiente molto complesso da gestire, se su un PC, ram, peso del programma e velocità di computazione di funzioni matematiche non sono cruciali in ambiente AVR diventano determinante per produrre un prodotto funzionante.
Se si hanno due MCU che devono comunicare tra si loro ad alta priorità e a loro volta devono interagire con sensori e attuatori su bus, come sembrerebbe nel caso di raghi ha senso predisporre due interfacce differenti, una ad alta velocità ed una a bassa.
Ovviamente l'impiego di due interfacce diverse comporta degli svantaggi, quali il peso dello sketch finale che aumenta, l'uso di ram che anche esso cresce, e una complessità HW e SW (indovina un po') anche questi lievitano.
Senza conoscere le specifiche del tuo progetto è difficile determinare quale sia la scelta piu ragionevole.

RobertoBochet:
Siamo in un ambiente molto complesso da gestire, se su un PC, ram, peso del programma e velocità di computazione di funzioni matematiche non sono cruciali in ambiente AVR diventano determinante per produrre un prodotto funzionante.
Se si hanno due MCU che devono comunicare tra si loro ad alta priorità e a loro volta devono interagire con sensori e attuatori su bus, come sembrerebbe nel caso di raghi ha senso predisporre due interfacce differenti, una ad alta velocità ed una a bassa.
Ovviamente l'impiego di due interfacce diverse comporta degli svantaggi, quali il peso dello sketch finale che aumenta, l'uso di ram che anche esso cresce, e una complessità HW e SW (indovina un po') anche questi lievitano.
Senza conoscere le specifiche del tuo progetto è difficile determinare quale sia la scelta piu ragionevole.

Ammetto che la tua risposta va un po' oltre le mie conoscenze, per cui non ho capito molto;ti faccio comunque un riassunto di quello che sto facendo.
Sto usando un raspberry pi come master che prenderà tutte le decisioni e gestirà l'interfaccia web(già implementato il tutto e funzionante). Ad esso sono collegati una serie di pcf8574 per l'attuazione di moduli relè o la lettura di pulsanti fisici (anche questo già implementato e funzionante).
Tutta la parte di sensoristica volevo gestirla con arduino in modo da velocizzare il tutto e renderlo più dinamico. I sensori principali sono per ora:
-x sensori di temperatura (ds18b20).
-y sensori di potenza
-z lettore RFID (inviare riferimento tag)
i dati raccolti dai sensori li devo passare a raspberry che poi deciderà cosa fare.

Il passaggio dei dati non dev'essere necessariamente "realtime", in quanto il mio sistema fisico ha una certa inerzia per cui può tollerare eventuali delay tra lettura e passaggio dati.

RobertoBochet:
r

Wire.write((char*) &frame, sizeof(frame));

Non devo usare Wire.sand()??