passare un vettore ad una funzione (risolto)

ho scelto di passare i 3 valori per non far ripetere inutilmente i calcoli nella funzione a parità di posizione e orientamento del sensore

questa è la chiamata:

transformation(magnetic_x, magnetic_y, magnetic_z);

questa la funzione:

void transformation(float uncalibrated_values[0], float uncalibrated_values[1], float uncalibrated_values[2])
{...

purtroppo ancora non comprendo perchè non compila, ho confrontato con altre funzioni, questa è la prima volta che provo con i vettori

@stefa24 mi pare sei un pò in confusione per quanto riguarda la logica

o passi un array di float (e magari anche quanti elementi contiene) (A)

oppure passi semplicemente 3 float ad una funzione (B), quindi nella chiamata metti le singole celle del vettore e nella funzione NESSUNA quadra, la funzione accetta 3 float e basta. Se poi gli passi 3 float non da un array non gli cambia nulla.

Per quello che devi fare mi sembra meglio il caso (B)
Quindi hai semplicemente la funzione

void transformation(float a,float b,float c) { qui elaboro}

e la chiamata

transformation(1.2 , 3.2 , 4.5);    oppure transformation(uncalibrated_values[0],uncalibrated_values[1],uncalibrated_values[2]);

Stai passando alla funzione transformation tre valori che hai definito come float.
La funzione però l'hai definita in modo tale da richiedere tre array di tipo float, il primo di lunghezza zero (e qui hai già un errore un array di lunghezza zero è inamissibile), il secondo di lunghezza 1 e il terzo di lunghezza 2.
Chiaro che le due cose non sono compatibili, passi float a un parametro di tipo array di float e il compilatore è infastidito da questo.
In più dentro transformations lavori su array quindi vedi tu, nid69ita mi ha anticipato, ma cambiare la firma della funzione non ti risolverà il problema di logica che hai all'interno della stessa. Rinnovo il consiglio di tornare sui tuoi passi e analizzare la funzione di trasformazione per trovare l'errore grazie a messaggi di debug

scusate ma [] mettendo un indice non serve anche per accedere ad una determinata posizione del vettore?

stefa24:
scusate ma [] mettendo un indice non serve anche per accedere ad una determinata posizione del vettore?

ripeto. la tua funzione VUOLE semplicemente 3 float.
void transformation(float a,float b,float c) { qui elaboro}

Se i tre valori che gli passi li prendi da un array, oppure 3 variabili non array o anche 3 costanti... al compilatore non interessa.

Se invece fai una funzione trasform a cui passi un array di float, allora è diverso.

Questo ti da errore
void transformation(float uncalibrated_values[0], float uncalibrated_values[1], float uncalibrated_values[2])
{...
ed è giusto. Quello è la definizione della funzione, NON può essere legata alle variabili che userai.
La funzione quando la definisci DEVE essere una cosa generica.
void transformation(float a,float b,float c) { qui elaboro}

stefa24:
scusate ma [] mettendo un indice non serve anche per accedere ad una determinata posizione del vettore?

Si se stai leggendo il valore

float a = arrayDiFloat[0]; //Leggo la posizione zero dell'array e la assegno alla variabile a

no se stai definendo la variabile o un paremtro di una funzione, in tal caso dichiari quanto è grande l'array

float arrayDiFloat[5]; //Dichiari un array di lunghezza 5 di tipo float
void laMiaFunzione(float vettoreDaElaborare[2]){...} //Dichiari una funzione che non ritorna nulla che ha come parametro un array di float di lunghezza 2

I casi sono due: o tu hai una funzione che opera su un numero (che poi sia un elemento di array non é importante) e allora le devi passare un numero
O tu hai una funzione che opera su un intero array in una singola chiamata, allora la chiami una volta sola passandole tutto l'array. Io per completezza modificherei la funzione si da passarne anche la lunghezza dell'array, così da non avere problemi di lettura (o peggio scrittura) da o in posti strani della memoria.
Se sei nel primo caso la sintassi é
For (qualcosa che cicli fino alla lunghezza dell'array)
{
funzione (array[variabile in for]);
}

Nel secondo é

Funzione (array);

@fabpolli occhio che non puoi passare la dimensione del vettore
il gcc stranamente compila sta bruttura
void laMiaFunzione(float vettoreDaElaborare[2]){...}
ma secondo me non considera il 2 tra parentesi.

Tieni conto che il compilatore ragiona e "traduce" il tutto con puntatore
void laMiaFunzione(float *vettoreDaElaborare){...}
che può dire dove inizia il vettore in memoria ma non quanti elementi sono

Un array lo passi tutto, alla logica del programmatore sta trovare un modo per indicare quanti elementi sono validi, o con altro parametro oppure (come per le stringhe classiche) ultimo elemento con valore speciale (0 per le stringhe)

Intanto ringrazio
la situazione è questa, nello sketch ho un ciclo FOR, per 3 valori che devo passare a una funzione, in questa funzione ho dei cicli FOR che è inutile che vengano ripetuti a parità di posizione e orientamento del sensore magnetico
Questo nel SETUP()

int _hmc5883_Gauss_LSB_XY;
int _hmc5883_Gauss_LSB_Z;

float _magData_x, magnetic_x;
float _magData_z, magnetic_z;
float _magData_y, magnetic_y;
float _mag_vector;

float magnetic[3];
float calibrated_values[3];
//float uncalibrated_values[3];

nel LOOP()

magnetic[0] = magnetic_x;
magnetic[1] = magnetic_y;
magnetic[2] = magnetic_z;

  for (int k = 0; k < 3; k++)
  {
   transformation(magnetic);
  }

nella funzione TRANSFORMATION

void transformation(float uncalibrated_values[])
{
  // float calibrated_values[3];
  //calibration_matrix[3][3] is the transformation matrix
  //replace M11, M12,..,M33 with your transformation matrix data
  double calibration_matrix[3][3] =
  {
    {1.171, -.035, -.02},
    { -.064, 1.215, -.009},
    {.051, -.058, 1.228}

    //  {M11, M12, M13},
    // {M21, M22, M23},
    // {M31, M32, M33}
  };
  //bias[3] is the bias
  //replace Bx, By, Bz with your bias data
  double bias[3] =
  {
    6.423, 1.096, -14.26

    //  Bx,
    //  By,
    //  Bz
  };

  //calculation
  for (byte i = 0; i < 3; ++i)
  {
    uncalibrated_values[i] = uncalibrated_values[i] - bias[i];
  }

  float result[3] = {0, 0, 0};

  for (byte i = 0; i < 3; ++i)
    for (byte j = 0; j < 3; ++j)
    {
      result[i] += calibration_matrix[i][j] * uncalibrated_values[j];
    }

  for (byte  i = 0; i < 3; ++i)
  {
    calibrated_values[i] = result[i];
  }
byte i = 0;
i++;
Serial.println(i);
  
}

non ho errore ma mi sembra di avere dei cicli FOR ripetuti inutilmente

Ma... @stefa24 sta funzione è void !!
Che cosa deve fare ? Occhio che se passi un array, allora puoi modificare gli elementi dell'array,
se fai funzione con 3 parametri float... devi passarli per referenza !!

stefa24:
non ho errore ma mi sembra di avere dei cicli FOR ripetuti inutilmente

No, assolutamente nessuna ripetizione inutile. Tu nel calcolo hai per forza dei giri su 3 celle

Al massimo possiamo dire che la funzione da per scontato che il vettore che gli passi DEVE avere 3 celle. Se per caso gli passi un array di float con sole 2 celle... potrebbe dare un bel crash perchè il compilatore non verifica che tu vai a leggere ma soprattutto a scrivere OLTRE alla seconda cella.

nid69ita:
@fabpolli occhio che non puoi passare la dimensione del vettore
il gcc stranamente compila sta bruttura

Si hai ragione ma sono stato tratto in inganno proprio da gcc (ho fatto una prova al volo su pc)
E anche il resto è perfettamente corretto (si potrà dire???) infatti tutte le funzioni standard richiestono il parametro di lunghezza del vettore per le motivazioni che hai giustamente indicato tu

nid69ita:
Ma... @stefa24 sta funzione è void !!
Che cosa deve fare ? Occhio che se passi un array, allora puoi modificare gli elementi dell'array,
se fai funzione con 3 parametri float... devi passarli per referenza !!

grazie per la pazienza
questa funzione corregge i 3 valori grezzi che arrivano dal sensore mediante una matrice 3x3, è qui che nasce la mia perplessità, se devo passare un vettore dimensione [3], lo passo a un vettore dimensione [3], se uno un FOR nello sketch la funzione viene richiamata 3 volte per calcolare gli stessi valori.

Mettendo dei Serial.print ho capito che posso passare il vettore senza il ciclo FOR

Ho fatto così nel LOOP:

  transformation(magnetic, k);
  k++;

nella funzione:

void transformation(float uncalibrated_values[], byte k)
{

ho provato a portare fuori le istruzioni della funzione e le ho messe direttamente nello sketch:

 magnetic_x = _magData_x / _hmc5883_Gauss_LSB_XY * SENSORS_GAUSS_TO_MICROTESLA;
  magnetic_y = _magData_y / _hmc5883_Gauss_LSB_XY * SENSORS_GAUSS_TO_MICROTESLA;
  magnetic_z = _magData_z / _hmc5883_Gauss_LSB_Z * SENSORS_GAUSS_TO_MICROTESLA;

  magnetic[0] = magnetic_x;
  magnetic[1] = magnetic_y;
  magnetic[2] = magnetic_z;

  //  for (byte k = 0; k < 3; k++)
  //  {
  //    transformation(magnetic, k);
  // }
  /*
        Serial.print(magnetic[0]);
        Serial.print('\t');
        Serial.print(magnetic[1]);
        Serial.print('\t');
        Serial.println(magnetic[2]);
        Serial.println();
  */
  //  transformation(magnetic, k_);
  //  k_++;

  double calibration_matrix[3][3] =
  {
    {1.171, -.035, -.02},
    { -.064, 1.215, -.009},
    {.051, -.058, 1.228}
  };
  //bias[3] is the bias
  //replace Bx, By, Bz with your bias data
  double bias[3] =
  {6.423, 1.096, -14.26};

  //calculation
  for (byte i = 0; i < 3; ++i)
  {
    magnetic[i] = magnetic[i] - bias[i];
  }

  float result[3] = {0, 0, 0};

  for (byte i = 0; i < 3; ++i)
    for (byte j = 0; j < 3; ++j)
    {
      result[i] += calibration_matrix[i][j] * magnetic[j];
    }
  for (byte  i = 0; i < 3; ++i)
  {
    calibrated_values[i] = result[i];
  }

  Serial.print(calibrated_values[0]);
  Serial.print('\t');
  Serial.print(calibrated_values[1]);
  Serial.print('\t');
  Serial.println(calibrated_values[2]);
  Serial.println();


  //  _mag_vector = pow((pow(calibrated_values[0], 2) + pow(calibrated_values[1], 2) + pow(calibrated_values[1], 2)) , 0.5);
  // Serial.println(_mag_vector);

  delay(200);//It appears that delay is needed in order not to clog the port

ma ho risultati diversi:

 Serial.print(calibrated_values[0]);
  Serial.print('\t');
  Serial.print(calibrated_values[1]);
  Serial.print('\t');
  Serial.println(calibrated_values[2]);
  Serial.println();

da quelli che ottengo utilizzando la funzione, eppure ho verificato con SERIAL che i valori passati alla funzione sono i medesimi:

 magnetic[0] = magnetic_x;
  magnetic[1] = magnetic_y;
  magnetic[2] = magnetic_z;

qualcuno riesce a vedere l'errore

Tanto per cominciare un elemento in un array bodomensionale si chiaro ama con due indici
Es:
byte bidim [3][3]={...}
//dichiarazione
budim[0][0]
//primo elemento
bidim[1][0]
//secondo elemento
bidim[0][1]
//quarto elemento
Ecc

Inoltre "ma ho risultati diversi" potrebbe implicare che uno sia giusto ed uno sbagliato. Quale dei due é quello giusto? E una vilta capito ciò usa il metodo che lo fornisce. Se invece entrambi sono sbagliati per favore dicci in italiano che calcoli vuoi fare, perché, almeno io, non lo ho capito, e quindi tutto quello che é sintatticamente giusto (e visto che carica é tutto sintatticamente giusto) potrebbe essere soluzione.

Inoltre non ho capito il nesso tra "ma ho risultati diversi" e quella serie di Serial.print, sarebbe (se proprio) più utile conoscere cosa scrivono. Ma vedi punto precedente.
Scusa se sembro duro

Silente:
Tanto per cominciare un elemento in un array bodomensionale si chiaro ama con due indici
Es:
byte bidim [3][3]={...}
//dichiarazione
budim[0][0]
//primo elemento
bidim[1][0]
//secondo elemento
bidim[0][1]
//quarto elemento

@Silente ma cosa cavolo stai dicendo, innanzitutto la dichiarazione è di una matrice o array bidimensionale e secondo di poi gli esempi che hai fornito sono totalmente errati, mi sa che ti devi studiare come funzionano le matrici

Scusate non volevo sollevare un vespaio.
Ho continuato a fare prove e ho capito dove era l'errore.
I risultati ottenuti attraverso la funzione ora sono uguali a quelli che ottengo mettendo le istruzioni dentro al LOOP.
Lo sketch arriva da esempi allegati alle librerie della scheda, adesso non so se i risultati che ottengo sono sensati.
Ho seguito una procedura di calibrazione fornita in questo link

A me interessava ottenere il valore risultante del campo magnetico, che dovrebbe essere costante a parità di posizione per qualsiasi orientamento.
Al momento non ottengo questo ma forse ho il sensore di scarsa qualità, perchè quando faccio le letture dei registri uno di essi non restituisce sempre lo stesso valore.
Grazie per la pazienza.
Allego per condivisione, un file XLS, che concatenando i testi mi ha permesso di velocizzare la scrittura dei vettori

/*
  I2C comunication
  to read from registers
  magnetic sensor HMC5883L alias gy271

  CS pin 3v3
  SDA pin SDA +10k to 3v3
  SDO pin GND
  SCL pin SCL +10k to 3v3
  3v3 VCC
  GND GND
*/
#include <Wire.h>
#define DEVICE (0x1E)//HMC5883L_ device addressE
#define TO_READ (13)//num of bytes-1 we are going to read each time

byte buff[TO_READ];    //n bytes buffer for saving data read from the device

#define HMC5883L_Configuration_Register_A_    (0x00)  //  Read/Write
#define HMC5883L_Configuration_Register_B_    (0x01)  //  Read/Write
#define HMC5883L_Mode_Register                (0x02)  //  Read/Write
#define HMC5883L_Data_Output_X_MSBRegister    (0x03)  //  Read
#define HMC5883L_Data_Output_X_LSBRegister    (0x04)  //  Read
#define HMC5883L_Data_Output_Z_MSBRegister    (0x05)  //  Read
#define HMC5883L_Data_Output_Z_LSBRegister    (0x06)  //  Read
#define HMC5883L_Data_Output_Y_MSBRegister    (0x07)  //  Read
#define HMC5883L_Data_Output_Y_LSBRegister    (0x08)  //  Read
#define HMC5883L_Status_Register_             (0x09)  //  Read
#define HMC5883L_Identification_Register_A_   (0x0A)  //  Read
#define HMC5883L_Identification_Register_B_   (0x0B)  //  Read
#define HMC5883L_Identification_Register_C_   (0x0C)  //  Read

char* reg[] =
{
  "HMC5883L_Configuration_Register_A_",
  "HMC5883L_Configuration_Register_B_",
  "HMC5883L_Mode_Register",
  "HMC5883L_Data_Output_X_MSBRegister",
  "HMC5883L_Data_Output_X_LSBRegister",
  "HMC5883L_Data_Output_Z_MSBRegister",
  "HMC5883L_Data_Output_Z_LSBRegister",
  "HMC5883L_Data_Output_Y_MSBRegister",
  "HMC5883L_Data_Output_Y_LSBRegister",
  "HMC5883L_Status_Register_",
  "HMC5883L_Identification_Register_A_",
  "HMC5883L_Identification_Register_B_",
  "HMC5883L_Identification_Register_C_"
};

byte reg_[] =
{
  HMC5883L_Configuration_Register_A_,
  HMC5883L_Configuration_Register_B_,
  HMC5883L_Mode_Register,
  HMC5883L_Data_Output_X_MSBRegister,
  HMC5883L_Data_Output_X_LSBRegister,
  HMC5883L_Data_Output_Z_MSBRegister,
  HMC5883L_Data_Output_Z_LSBRegister,
  HMC5883L_Data_Output_Y_MSBRegister,
  HMC5883L_Data_Output_Y_LSBRegister,
  HMC5883L_Status_Register_,
  HMC5883L_Identification_Register_A_,
  HMC5883L_Identification_Register_B_,
  HMC5883L_Identification_Register_C_
};

int _hmc5883_Gauss_LSB_XY;
int _hmc5883_Gauss_LSB_Z;

float _magData_x, magnetic_x;
float _magData_z, magnetic_z;
float _magData_y, magnetic_y;
float _mag_vector;

float magnetic[3];
float calibrated_values[3];

byte k_ = 1;

byte SENSORS_GAUSS_TO_MICROTESLA;

void setup()
{
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
  //Turning on the sensor

  _hmc5883_Gauss_LSB_XY = 1100.0;
  _hmc5883_Gauss_LSB_Z = 980.0;

  SENSORS_GAUSS_TO_MICROTESLA = 100;

  writeTo(DEVICE, reg_[0], 0b00010000); //enter register value
  delay(100);
  writeTo(DEVICE, reg_[1], 0b00000000); //enter register value
  delay(100);
  writeTo(DEVICE, reg_[2], 0b00000000); //enter register value
  delay(100);

  for (int k = 0; k < 3; k++)
  {
    readFrom(DEVICE, reg_, TO_READ, buff); //read the acceleration data from the sensor

    Serial.println(reg[k]);
    Serial.print(k);
    Serial.print('\t');
    Serial.print("0x");
    Serial.print(reg_[k], HEX);
    Serial.print('\t');
    Serial.print(buff[k], BIN);
    Serial.println();
    delay(200);//It appears that delay is needed in order not to clog the port
  }
}

void loop()
{
  //  Serial.println("START++++++++++++++++++++++++++++++++++++++++++++++");

  for (byte k = 0; k < TO_READ; k++)
  {
    readFrom(DEVICE, reg_, TO_READ, buff); //read the acceleration data from the sensor
    // delay(200);//It appears that delay is needed in order not to clog the port
  }

  _magData_x = buff[4] | (buff[3] << 8);
  //Serial.println(buff[4]);

  _magData_y = buff[8] | (buff[7] << 8);
  //Serial.println(_magData_y);

  _magData_z = buff[6] | (buff[5] << 8);
  //Serial.println(_magData_z);

  magnetic[0] = _magData_x / _hmc5883_Gauss_LSB_XY * SENSORS_GAUSS_TO_MICROTESLA;
  magnetic[1] = _magData_y / _hmc5883_Gauss_LSB_XY * SENSORS_GAUSS_TO_MICROTESLA;
  magnetic[2] = _magData_z / _hmc5883_Gauss_LSB_Z * SENSORS_GAUSS_TO_MICROTESLA;

//   for (byte k = 0; k < 3; k++)
//    {
//      transformation(magnetic, k);
 //  }

  
  transformation(magnetic, k_);
  k_++;

  Serial.print(calibrated_values[0]);
  Serial.print('\t');
  Serial.print(calibrated_values[1]);
  Serial.print('\t');
  Serial.println(calibrated_values[2]);
  Serial.println();


    _mag_vector = pow((pow(calibrated_values[0], 2) + pow(calibrated_values[1], 2) + pow(calibrated_values[1], 2)) , 0.5);
   Serial.println(_mag_vector);

  delay(200);//It appears that delay is needed in order not to clog the port
}//fine loop

///////////////////////////////////////////////////////////////////////////////////
void readFrom(int device, byte reg_address, int num, byte buff[])
{
  Wire.beginTransmission(device); //start transmission to device
  Wire.write(reg_address);        //sends address to read from
  Wire.endTransmission(); //end transmission

  Wire.beginTransmission(device); //start transmission to device (initiate again)
  Wire.requestFrom(device, num);    // request TO_READ bytes from device

  int i = 0;
  while (Wire.available())   //device may send less than requested (abnormal)
  {
    buff[i] = Wire.read(); // receive a byte
    i++;
  }
  Wire.endTransmission(); //end transmission
}

///////////////////////////////////////////////////////////////////////////////////
void writeTo(int device, byte reg_address, byte val)
{
  Wire.beginTransmission(device); //start transmission to device
  Wire.write(reg_address);        // send register address
  Wire.write(val);        // send value to write
  Wire.endTransmission(); //end transmission
}

////////////////////////////////////////////////////////////////////////////////////

void transformation(float uncalibrated_values[], byte _k)
{ 
     
  // float calibrated_values[3];
  //calibration_matrix[3][3] is the transformation matrix
  //replace M11, M12,..,M33 with your transformation matrix data
  double calibration_matrix[3][3] =
  {
    {1.287,0.022,0.08},
{0.024,1.278,0.024},
{0.033,-0.01,1.129}
  };
  //bias[3] is the bias
  //replace Bx, By, Bz with your bias data
  double bias[3] =
  {1.287,0.024,0.033};


  //calculation
  for (byte i = 0; i < 3; ++i)
  {
    uncalibrated_values[i] = uncalibrated_values[i] - bias[i];
  }
 
  float result[3] = {0, 0, 0};

  for (byte i = 0; i < 3; ++i)
    for (byte j = 0; j < 3; ++j)
    {
      result[i] += calibration_matrix[i][j] * uncalibrated_values[j];
    }

  for (byte  i = 0; i < 3; ++i)
  {
    calibrated_values[i] = result[i];
//    result[i] = 0;
  }


}

i2c_registri.zip (19.1 KB)

Per inciso, volendo, ogni array/matrice è accessibile via il suo puntatore ai suoi elementi e, sempre volendo, si può facilmente fare una funzione a cui si passa solo il puntatore e questa accede a tutti gli elementi ...

Faccio un banale esempio con una matrice di float 3 righe 4 colonne ...

float matrice[3][4] = {{1.0, 1.1, 1.2, 1.3},
                       {2.0, 2.1, 2.2, 2.3},
                       {3.0, 3.1, 3.2, 3.3}};

void setup() {
   // put your setup code here, to run once:
   delay(500);
   Serial.begin(115200);
   //
   stampa((float *)matrice);
}

void loop() {
   // put your main code here, to run repeatedly:

}

void stampa(float * pmatrice) {
   byte i;
   for (i = 0; i < 12; i++) {
      if ( ((i + 1) % 4) == 0 ) {
         Serial.println(*(pmatrice+i));
      }
      else {
         Serial.print(*(pmatrice+i));
         Serial.print(" ");
      }
   }
}
  1. la scelta del tipo "float" è voluta per far vedere che il compilatore è intelligente e che se nel for aggiungo 1 al puntatore, il compilatore sa che deve spostartsi di QUATTRO bytes. Quindi, fino a quando il tipo è ben definito, basta spostarsi con una semplice somma sul puntatore.

  2. "if ( ((i + 1) % 4) == 0 ) {" serve solo per andare a capo ogni 4 elementi così da avere una stampa più pulita :wink:

Per il resto, il codice è banale ...

Guglielmo

interessante la provo