jvoermans / Wind_Input_V1

Sketch for measuring pressure and IMU using Platformio
0 stars 0 forks source link

using etl #4

Closed jerabaul29 closed 1 year ago

jerabaul29 commented 1 year ago

I cannot recommend enough to use the etl library to use arrays: see the arduino-packaged version:

https://github.com/ETLCPP/etl-arduino

Could be a good addition to the libs, and using it rather than native arrays will be much safer and more ergonomic :) .

jvoermans commented 1 year ago

@jerabaul29

I've been looking at this this morning, and indeed its very handy. I'm struggling a bit in understanding one aspect though, and couldn't find the answer myself on the etlcpp website. If I run the edited example sketch in the Arduino IDE, see below, it creates a vector with 12 numbers.

// make sure that we do not rely on the STL
#define ETL_NO_STL

#include "Embedded_Template_Library.h"
#include "etl/vector.h"

int count = 0;

template <typename T>
void print_vector(etl::ivector<T> const & vec_in)
{
  Serial.print(F("print vector content | size "));
  Serial.print(vec_in.size());
  Serial.print(F(" | capacity "));
  Serial.println(vec_in.capacity());
  Serial.print(F("content | "));

  for (T const & elem : vec_in)
  {
    Serial.print(elem);
    Serial.print(F(" | "));
  }

  Serial.println();
}

void setup()
{
  Serial.begin(115200);
  delay(100);
  Serial.println(F("booted"));

  etl::vector<int, 12> vec_int;

  Serial.println(F("initialized vec_int"));
  print_vector(vec_int);

  while (count < 12) {
    vec_int.push_back(2);
    Serial.println(F("pushed to vec_int"));
    print_vector(vec_int);
    count++;
  }
}

void loop()
{
}

But if I put the while loop into the loop part of the sketch, i.e.,:

void setup()
{
  Serial.begin(115200);
  delay(100);
  Serial.println(F("booted"));

  etl::vector<int, 12> vec_int;

  Serial.println(F("initialized vec_int"));
  print_vector(vec_int);
}

void loop()
{
  while (count < 12) {
    vec_int.push_back(2);
    Serial.println(F("pushed to vec_int"));
    print_vector(vec_int);
    count++;
  }
}

I get the error: 'vec_int' was not declared in this scope Do you know why? I though it is already initialized in the setup()...

jerabaul29 commented 1 year ago

This is because of scoping. In C++, variables are only valid as long within their scope (basically, more or less the block of code defined by the nearest enclosing brackets). What happens is that you define vect_int in the setup function, and vec_in is available in this scope (ie between the {} of the setup function, but not outside. When you try to use vec_in from within loop{}, which is another function with a scope that is not "within" setup, then vec_in is not available. So this is perfectly normal, and not related to etl - any object, array, etc, that you create locally in setup, would also not be available in loop. See for more information explanations like:

In your case, this is easy enough to fix: something like (note: to get automatic coloring of snippets, you can add the name of the language, here "cpp", after the 3 back ticks; would work the same for coloring for python (just write python), bash, matlab, etc; this makes things easier to read :) : "```cpp" ):

etl::vector<int, 12> vec_int;

void setup()
{
  Serial.begin(115200);
  delay(100);
  Serial.println(F("booted"));

  Serial.println(F("initialized vec_int"));
  print_vector(vec_int);
}

void loop()
{
  while (count < 12) {
    vec_int.push_back(2);
    Serial.println(F("pushed to vec_int"));
    print_vector(vec_int);
    count++;
  }
}

This effectively moves vec_int to the scope of the full program, making it a global variable, which is available from everywhere for the duration of the whole program.

In big programs, global variables are a bit "evil", as it is really hard to reason about them, make sure they are not modified from multiple places etc; this is why, in th eOMB, I usually:

https://github.com/jerabaul29/OpenMetBuoy-v2021a/blob/754e84098409607f0cd39af3f9588810210aaf35/legacy_firmware/firmware/plain_gps_drifter/gnss_manager.h#L60-L63

that is part of the gnss manager class:

https://github.com/jerabaul29/OpenMetBuoy-v2021a/blob/754e84098409607f0cd39af3f9588810210aaf35/legacy_firmware/firmware/plain_gps_drifter/gnss_manager.h#L26-L66

https://github.com/jerabaul29/OpenMetBuoy-v2021a/blob/754e84098409607f0cd39af3f9588810210aaf35/legacy_firmware/firmware/plain_gps_drifter/gnss_manager.h#L68

https://github.com/jerabaul29/OpenMetBuoy-v2021a/blob/754e84098409607f0cd39af3f9588810210aaf35/legacy_firmware/firmware/plain_gps_drifter/gnss_manager.cpp#L5

Note the difference between declaration (saying something exists); this can be made multiple time through the program (for example, here the declaration takes place in a header file through extern, and that that will be imported from a number of files), and declaration (actually booking the memory for the object and creating it), that should only happen ever once (the declaration in the cpp file). See for more information:

This is a bit a long explanation, and I discuss a few concepts in addition of "just" fixing the bug, but these are quite important / key for understanding C++, and these are actually quite simple once you wrap your head around them, so it would be useful that you spend a few minutes making sure all is clear :) . If not, feel free to ask :) .

jvoermans commented 1 year ago

Thanks. It is actually quite a bit to get my head around. I guess the logic parts are ok to understand, but working with it may take a while! :)

I've just had some time to get all the sensors/breakouts in the sketch to see whether they work normally. It is not pretty but I should be able to clean up slowly. I just had a question regarding writing data from the vector to SD-card. Any recommendations how to do that most efficiently? I can't seem to find an option in the ETL where the complete vector can be printed, so I followed the ETL example instead by doing it element-wise, but then to SD card: https://github.com/jvoermans/Wind_Input_V1/blob/405fe29ff8eabed5ca188a080793a91667c71216/src/main.cpp#L49-L58

but this seems to take quite a while to write to the SD-card https://github.com/jvoermans/Wind_Input_V1/blob/405fe29ff8eabed5ca188a080793a91667c71216/src/main.cpp#L142-L144 1000 elements (4000 bytes) takes 850ms. That sounds way too long?

jerabaul29 commented 1 year ago

Yes, it does is a bit the first time... But after you go through it a few times, you will see that it actually makes sense and it is not so complicated. Really there are quite few things this boils down to: if you make sure you have understood "declaration vs defintion" and "scope" you should be fine to go with these :) .

The SD card is something else, opening a separate issue about it :) .

Apart from the SD card, keeping it open so that we can discuss further if declaration / definition / scoping is still unclear and you want to ask some more questions :) .