Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AutomationShield API Style Guide #42

Open
gergelytakacs opened this issue Apr 25, 2018 · 3 comments
Open

AutomationShield API Style Guide #42

gergelytakacs opened this issue Apr 25, 2018 · 3 comments
Assignees
Labels
AutomationShield common Common functionality for the entire library readme Important "sticky" posts. software Mostly software issue

Comments

@gergelytakacs
Copy link
Owner

gergelytakacs commented Apr 25, 2018

Development

Put an empty .development in the root folder in order to edit the examples and while working. Don't itegrate the file into the Gi repo!

Build status

  • Travis CI is used to do automated build tests, you can see the master build status here: Build Status

Naming conventions

Please stick to the Arduino API style guide that can be found here when writing the shield API's.

Namely:

  • Use begin() to initialize a library instance, usually with some settings. Use end() to stop it.
  • Use read() to read inputs, and write() to write to outputs, e.g. digitalRead(), analogWrite(), etc.

According to this the AutomationShield library will use:

  • begin() to initialize the board.

  • sensorRead() to read the outputs "y",

  • referenceRead() to read reference "r" (if there is one) and

  • actuatorWrite() to send input ''u".

  • calibration() to perform optional calibration tasks before moving into the loop.

  • bool _wasCalibrated is a Boolean flag to read calibration status.

All boards should use these basic functions so that the library remains consistent. Determine which type of input/output will be likely most used by the user and use those in these functions. If you want to use more types of sensor readings (voltage, physical units etc.) then it is suggested to get creative based on this. Such as

  • sensorReadVoltage() to read the outputs "y" in V,
  • sensorReadCelsius() to read the outputs "y" in degrees Celsius, etc.

Pins locations for the inputs and outputs should be stored as #define tokens. Use all capitals and begin the token with the name of the device, continue with an underscore, variable symbol of the quantity and the word pin. So, for example the output pin of the Opto shield will be OPTO_YPIN. Other examples of these tokens are:

  #define OPTO_RPIN 0   // Potentiometer runner (Reference, r)
  #define OPTO_YPIN 1   // LDR (Sensor)
  #define OPTO_YAUX 2   // Auxiliary LDR
  #define OPTO_UPIN 3   // LED (Actuator)

Header files for hardware API are named after the hardware, contain capitals. For example for the Magneto device the full name will be MagnetoShield, thus the API for the device will be initialized in the MagnetoShield.h header not magnetoshield.h. Similarly, the API will have the class, methods and other things in the MagnetoShield.cpp source file.

The API for the particular hardware will use the common header AutomationShield.h, which in turn will load other basic headers such as Sampling.h and PID.h. Thus, in the end, the user should just load the particular header in the example file, such as MagnetoShield.h.

The header (*.h) should just contain forward declarations of programming entities (e.g. void function()) but not the actual functions, these go into the source (*.cpp)

For naming functions use camel case, not snake case. Avoid underscores, if possible. Thus, you should use - myAwesomeFunction(), instead of my_awesome_function(). This is a thing of preference and consistence.

3.3 V compatibilty

  • New shields (except some older ones) have been designed to be 3.3V compatible. Thus, you have to compensate for the AVR devices, which have a 5 V logic. This can be done by setting the reference of the ADC to the external pin, which in turn should be connected to the 3.3 V pin on hardware. To do this, you can call in the begin() method: analogReference(EXTERNAL). See more here.

MATLAB

If you want to include experimental measurements, use the following naming conventions for the mat files:

  • C_ - from control
  • ID_ - from identification
    use any other information next and finish with the sampling rate. Thus a control experiment by PID sampled at 3000 microseconds will be C_PID_3000us.mat.
  • Careful of file naming and letter case. Windows doesn't care, Linux does. myFile.mat will work on Windows if you refer to it with lower case myfile.mat, it won't on Linux (e.g. when testing CI).
  • In MATLAB examples instead of clc and clear use startScript in the beginning, otherwise the continuous integration will fail, since the clear command clears those variables needed for CI. (startScript defines some exceptions for clear).
  • The variable to signify a CI run is CI_Test. You can test its existence with exist() to run CI specific parts of your code.
  • Algorithms that are expected to run for long times need to be curbed in CI. For example use an existence test for the variable CI_Test, which will limit solver iterations, optimization runtime, etc. (this is really specific to your application).
  • All scripts for examples must be self-contained. Script B should not need Script A to be run since a) the user does not know this and b) neither does CI. If you want to split examples, that is fine - but save the results to a *.mat file. For example modeling runs, but the model is saved and loaded in control examples. Don't just assume that a variable exists in the workspace.

Library file and folder structure

  • Details on the include paths and library structure are found here.
  • All *.h files must have an include guard macro, according to the FILENAME_H pattern.

Printing to serial
The primary point of any example is to output dynamic measurements to the plotter or for logging. Therefore any kind of diagnostic data is subject to conditional compilation, enabled by flags of the user. This functionality inside the header and cpp files is realized by the
AutomationShield.serialPrint("Message");
method. Please DO NOT USE the regular Serial.print() function inside header and realization files.

Shield releases

  • If there are more hardware versions of particular shield being developed, in software use token #define SHIELDRELEASE n to distinguish between different versions. The n should represent release order of specific version.

ATSAMD Compatibility

  • Assume 10 bit ADC resolution in order not to complicate things. ATSAMD has configurable resolution.
  • Assume 3.3 V ADC reference, boards should be compatible with the R3 for non-AVR boards.
  • Serial works without changes. The board does not reset upon accessing serial link, unlike in the case of AVR. Push reset button manually.
  • analogRead works without changes (but tolerates only 3.3 V!). Unless changed, the resolution is still 10bit. So by default 1023 level is 3.3 V.
  • If necessary use preprocessor directives to use different portions of code for different architectures. See more here, however, this seems not to work for the Arudino Zero, since its environment variable is ARDUINO_ARCH_SAMD and not ARDUINO_ARCH_SAM. So the following example works
#if defined(ARDUINO_ARCH_AVR)
  // AVR-specific code
#elif defined(ARDUINO_ARCH_SAMD)
  // SAM-specific code
#else
  // generic, non-platform specific code
#endif

or to a more C standard

#ifdef ARDUINO_ARCH_AVR
  // AVR-specific code
#elif ARDUINO_ARCH_SAMD
  // SAM-specific code
#else
  // generic, non-platform specific code
#endif

in this case of course you may employ #ifndef etc. preprocessor directives.

You may consult this tutorial for a decent start on C preprocessor basics for the Arduino IDE.

Others

  • Include a description as a comment at the beginning of files
  • Comment line-by-line in great detail
  • Do not initialize Serial and do not use Serial within the source code, only in examples.
  • If your board uses a servo do not create a separate header (.h) and implementation (.cpp) file. Since the IDE tries to build every implementation file in the library, this will cache the Servo library, which will then conflict with other AS devices. The solution is, in this case, just use a header file - it will not be included anywhere else but the examples.
  • Commit to Git more often then once a week.
  • Only commit when you've actually tested that things work or at least they build correctly.
  • Use commit messages that are sensible and descriptive enough. Do not comment messages like "New" or "Latest" or "My changes" etc.

Useful Arduino API environment variables

  • VARIANT_MCK Clock speed in Hz for ATSAMD, does not seem to work for AVR

Just for fun

  • Each header file shall from now on include the pre-processor token TIME_WASTED_HERE that shall express the time in hours wasted in finding bugs. :) (Thanks @AnnaVargova)
@gergelytakacs gergelytakacs added the AutomationShield common Common functionality for the entire library label Apr 25, 2018
@gergelytakacs
Copy link
Owner Author

@rkoplinger - mainly to you at the moment. :)

@gergelytakacs gergelytakacs changed the title Stick to Arduino API style gude Stick to Arduino API style guide / AutomationShield API Style guide Oct 23, 2018
@gergelytakacs gergelytakacs changed the title Stick to Arduino API style guide / AutomationShield API Style guide AutomationShield API Style guide Oct 23, 2018
@gergelytakacs gergelytakacs changed the title AutomationShield API Style guide AutomationShield API Style Guide Oct 23, 2018
@gergelytakacs gergelytakacs added the software Mostly software issue label Oct 25, 2018
@gergelytakacs gergelytakacs added the readme Important "sticky" posts. label Oct 29, 2018
@gergelytakacs gergelytakacs pinned this issue Jan 9, 2019
@gergelytakacs
Copy link
Owner Author

@EvaVargova, @corleone68, @lukasvadovic2 you should read these...

gergelytakacs referenced this issue Jun 25, 2019
@gergelytakacs I would like you to review the changes I made to the FloatShield library files. I have changed most of the things, but I believe that it is now, if nothing else, more easily readable. I am also including modified FloatShield example that already uses my version of library. I will be grateful for any form of feedback.
gergelytakacs referenced this issue Jun 27, 2019
@gergelytakacs error() and serialPrint() functions sometimes throw a warning message: "ISO C++ forbids converting a string constant to 'char*'" when used like they were meant to - serialPrint("text"). Sketch is compilable even without this change, this is just to satisfy the compiler by using the "more correct" argument type.
@Gabor7697
Copy link
Contributor

MagnetoShield: If the linearization point is defined as y0 in Arduino IDE and Arduino DUE is used we get the following compilation error: 'float y0' redeclared as different kind of symbol'. Solution: use y_0 for linearization point.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
AutomationShield common Common functionality for the entire library readme Important "sticky" posts. software Mostly software issue
Projects
None yet
Development

No branches or pull requests

4 participants