text:
Uneven stepper motor acceleration / code execution
I have created a library to control a stepper motor. I have a controller that accepts a pull signal, and then executes a step, so my code needs to generate a state change in order to make the controller execute a single step.
I have a part of the code responsible for acceleration. It runs in main loop as often as possible. The acceleration is given in steps/s/s and speed in steps/s. Here is the method in question:
void StepperMotor::accelerate() {
  speed = start_accelerating_speed + (micros() - startAccelTime) / 1000000.0 * acceleration;
  step_time = 1000000 / speed;
}

start_accelerating_speed is set to micros() when the motor starts. Let's say acceleration = 200.
The step_time is used by the code in the main loop to check if it is time to make a step.
The code seems to work fine, however, when executed, the motor starts accelerating as expected, then increases speed rapidly by let's say 10% of the target speed and keeps accelerating smoothly for some time. This pattern repeats. Jumps can be only heard from changing motor speed or buzzer sound (I use a buzzer instead of a motor for easy debugging). Printing speeds on the serial port kills the performance completely making the code wait for the serial port.
I have used this code to measure loop time without adding a significant Serial.println() overhead.
// Runs in main loop, loops and step_time defined earlier.
loops++;
if (loops >= 10000) {
  Serial.println(micros()-loop_time);
  loop_time = micros();
  loops = 0;
}

Conclusion: the loop takes about 56 microseconds to execute, less than 70 when motor is running and accelerating. Running the stepper motor in this setup with 1000 steps per second requires a min. loop time of 1000 microseconds (or 1 millisecond). The code should run smoothly.
I ran the code in pure C++ and plotted the results in Matlab. The result is linear acceleration.
I have tried slowing down the main loop to 50 ms per loop, and slowing down the motor and acceleration accordingly so I could also print the speeds on serial port; then everything works fine.
Any form of delay() is never used in the code.
Tested with ATmega 328 and ATmega 2560 with same results.
It's been about a month and I can't find a similar issue on the internet.
Does anyone know what might be happening here?
P.S.
I know that linear acceleration is sub-optimal, but I'd like to resolve the current issue first.
I'm including the full source code for this class. I have stripped down the code to the bare minimum. The issue still persists. The tone of the buzzer seems to be affected by enabling the second motor, printing on serial port etc. regardless of the fact that execution of the loop never exceeds 1 ms.
main.cpp
#include <Arduino.h>
#include <StepperMotor.h>

StepperMotor motor_1(3, 2, 4);

void setup(void) {
  Serial.begin(115200);
  motor_1.start();
}

void loop(void) {
  motor_1.update();
}

StepperMotor.cpp

// Constructor
StepperMotor::StepperMotor(uint8_t step_pin_, uint8_t enable_pin_, uint8_t direction_pin_):
step_pin(step_pin_), enable_pin(enable_pin_), direction_pin(direction_pin_) {
  // Initiating pinouts
  pinMode(step_pin, OUTPUT);
  pinMode(enable_pin, OUTPUT);
  pinMode(direction_pin, OUTPUT);

  // Setting pin states
  digitalWrite(step_pin, LOW);
  digitalWrite(enable_pin, HIGH);
  digitalWrite(direction_pin, LOW);
}

// Called while accelerating. Recalculate speed and check if target speed has been reached.
void StepperMotor::accelerate() {
  // Using start time - calculate current speed and step time.
  speed = start_accelerating_speed + (micros() - startAccelTime) / 1000000.0 * acceleration;
  step_time = 1000000 / speed;

  // Stop accelerating if target speed is reached
  if (speed >= target_speed) {
    accelerating = false;
  }
  // Serial.println(speed);
}

// Realising basic steps needed to start motor and prepare variables.
void StepperMotor::startMotion() {
  Serial.println("Start"); // Debug

  // Prepare variables for step control
  prev_step_time = time;
  speed = 0;
  step_time = 0;

  // Prepare acceleration
  startAccelTime = time;
  start_accelerating_speed = 0;
  accelerating = true; // Enable acceleration
}

// Overloaded methods for starting a motor.
// Start in the same direstion and speed as before.
void StepperMotor::start() {
  startMotion();
}

void StepperMotor::update() { // Main control method. Executed in loop by Stepper.cpp
  time = micros();

  if (time-prev_step_time >= step_time) { // Is it time to step?
    step_pin_state = !step_pin_state;    // Alter pin variable
    digitalWrite(step_pin, step_pin_state);    // Write pin state to pinout

    prev_step_time = time;
  }

  if (accelerating) { // If target speed not reached: accelerate
    accelerate();
  }
}

StepperMotor.h
// StepperMotor.h

#ifndef STEPPERMOTOR_H
#define STEPPERMOTOR_H

#include <Arduino.h>

class StepperMotor {
public:
  // Constructor
  StepperMotor(uint8_t step_pin_, uint8_t enable_pin_, uint8_t direction_pin_);

  // Methods
  void start();

  // Main loop method called by StepperController
  void update();

private:
  // Pins
  uint8_t step_pin;      // Change of state = 1 step.
  uint8_t enable_pin;    // 0 = Disabled  1 = Enabled
  uint8_t direction_pin; // 0 = CW        1 = CCW

  double target_speed = 1000; // In steps per second

  // Timers
  unsigned long time;
  unsigned long startAccelTime;
  unsigned long startAccelTimeMillis;
  unsigned long step_time; // Indicates time between steps in microseconds
  unsigned long prev_step_time;
  unsigned long prev_accel_time;       // Usually the same as prev_stepTime //change comment

  double speed;        // Indicates the motor's speed in steps per second
  bool step_pin_state; // Indicates current state of step pin. FALSE = LOW; TRUE = HIGH

  bool direction;      // Indicates the motor's rotation direction
  bool moving;         // Indicates if stepper is moving or not. Do not confuse with enable - enable can be used to hold motor in place.

  void startMotion();
  void accelerate();

  bool accelerating = false;
  double acceleration = 200; // In steps per second^2
  double start_accelerating_speed;
};

#endif // STEPPERMOTOR_H

Please include a complete compilable code in your question. The problem might be in the rest of the code and not in the little snippet, that you showed.

Thank you for your answer. The snippet is a part of quite large library. Even though I think that most if not all of the class' code does not affect the issue - I have edited the original post with full class source code. I hope it can be quite easily ran without the rest of library.
Please also note that I develop the code via platformio on VSCode, hence the  library is included.

There is quite a lot going on in this library. Some suggestions: 1. Remove everything but the core algorithm you want to test, in order to get a minimal testable example. If it still shows the problem, update the question and replace your library with that example. 2. Instrument loop() to measure the maximum (not average) loop execution time. 3. Call micros() only once in update(), and don't call it again in accelerate(): for consistency, you want all computations to be based on the same notion of “current update time”.

Thanks for suggestions @EdgarBonet. I will set micros only once in a loop from now as a good practice. I have measured maximum loop time. It's at most ~340 µs (when motor accelerates). A bit more than I would like but probably occurs only several times in the time period as average was much lower. Nevertheless it's lower than max of 1000 µs required to test speed of 1000 steps/s. I will replace the code with stripped down version if/when i create it. For now the problem persists and I still have some things to try first.

I tested this sketch by looking at the step pin on an oscilloscope. What
I see is a square signal with a period that decreases smoothly at first,
then in a manner that gets more and more jerky, with visible jumps.
It turns out this is due to the time taken by the loop() iterations.
On my tests, it takes about 85 µs. Doesn't look like much, but it
has a significant impact on the timings, because the signal period has
to be a multiple of the loop() execution period. When the signal
period is large, this constraint does not cause any visible effect. When
the signal period is short, however, the fact that it decreases by
integer multiples of the loop() period makes visible jumps. The last
jump is a variation by about 8.5% (85 µs / 1 ms).
The solution is to change the way the prev_step_time variable is
updated. In the current version of the code, it is updated as
prev_step_time = time;

This means that prev_step_time stores the time when the previous step
was performed. You may instead update it like this:
prev_step_time += step_time;  // increment by step period

In this case, that variable holds the time at which the previous step
was scheduled. This implies that timing errors are not cumulative: if
one signal period is a bit too long because of the above mentioned
rounding, then this will be compensated by the next period being
shorter. In the end, you do get some jitter, but no systematic frequency
errors.

Edit: Your program is calling accelerate() to re-compute the step
period at every loop() iteration. Most of these computations are just
thrown away. All this involves quite a bit of floating point
computations, which makes the main loop slow. You would get a smoother
movement if you recompute the step period only after having performed a
step. The algorithm is as follows:
if (it's time to do a step):
    do the step
    compute next step period

As a first approximation, the next step period is equal to the previous
one, and the average speed within that period is equal to the expected
speed at the middle of that time interval. This speed can then be used
to compute a better approximation of the next step period, which gives
the following formula for updating the step period:
step_period ← 1 / speed(current_step_time + step_period / 2)

I tried this strategy and, according to my scope, the frequency sweep is
indeed smoother. Here is my test code. Note that I did change some
notations:
// Return the speed (in steps/s) at time t (in us).
// Implementation skipped.
double speed(unsigned long t);

void update()
{
    // Do nothing until it's time to perform a step.
    if (micros() - prev_step_time < step_period)
        return;

    // Do the step.
    step_pin_state = !step_pin_state;
    digitalWrite(step_pin, step_pin_state);

    // Update timing variables.
    prev_step_time += step_period;
    step_period = 1e6 / speed(prev_step_time + step_period/2);
}

Note that now, most iterations of loop() will do nothing other than
evaluate
if (micros() - prev_step_time < step_period) return;

which makes the loop very fast and improves the smoothness of the
acceleration.
There is one caveat with this approach though: the start of the movement
is very sensitive to the initial value of step_period. I found no
better idea than to initialize it at the exact value for the first step:
step_period = 1e6 * sqrt(2/acceleration);

The square root is expensive to compute, but this is done only once.

Absolutely brilliant :)

Your answer seems to be on point. The oscilloscope must have helped a bit. Honestly, I had thought about the multiples of loop time being the limiting factor, but I didn't think it would make such a difference. Your answer helped me as much as it was possible. However, I can see that the issue persists to some level. I think it is okay for now, but I assume that I'd need to get something with a faster clock to achieve smoother operation. All things considered, I've checked the AccelStepper library, and it does not support speeds larger than 1000 - so it seems like the clock is the limit.

@WojciechKosela: see amended answer.

@EdgarBonet thank you, that's very interesting. You've presented me with a new approach to the issue. I will continue my journey with this topic and post any new ideas, if I find any in the future. I hope it will help the others.

For anyone who might be looking up this topic in the future, I want to post some of my findings, directions and keywords regarding this question.
I have been experiencing large jumps in speed when accelerating. Now I know why.
Time between steps changes slowly with larger speeds. As time measurements were limited by loop time - only possible values of time were: n * loop time. With this in mind - jumps i experienced were caused by executing step each n-1 loops (assuming that previously it was executed each n loops). As my loop took about 80us it was very noticeable and fooled me into thinking that limited loop frequency can't be the sole reason for this. It can.
For anyone having the same problem as me. I have a STRONG ADVICE. Use Arduino timer/counter. That's what I did. It is designed for this purpose and it's the proper way. Don't know how to use timers? Learn it. Even if you think that it is overkill for what you are trying to do. Firstly: you can't unlearn it, so you won't be leaving empty handed no matter what. Secondly: if you try implementing anything more into this code, i.e. serial communication - It will interrupt the timings and you will never have peace with this timings. Timers (interrupts) eliminate all those issues.
And at last some important notes about timer interrupts. Use carefully. Some timers are used by Arduino for things like millis() / micros(). All the timers are used for PWM outputs. Choose wisely and be aware what are you disabling by using a given timer.
Also read some "don't"s of what can be done inside timer interrupts. Basically avoid anything that itself uses interrupts, so digitalWrite(), Serial.print(), delay(). For pin outputs you have to use port manipulation.
It is a lot of to worry about, but if you are reading this topic - you might be wanting to generate some precise signal with Arduino. If that's the case - you better try using timers/counters, it would probably take you less time than troubleshooting (and realizing you have to use interrupts anyway) regular timers.

That's good advice: timers are a bit complex but can definitively give you spot-on timings. Some remarks: 1. The best timings are achieved with PWM mode, by updating the compare register in the timer interrupt ISR. 2. digitalWrite() does not rely on interrupts. The reason you may prefer direct port manipulation is because it is way faster.

@EdgarBonet Instead of direct port access I prefer the library "digitalWriteFast" by Watterot/Armin Joachimsmeyer, that compiles to single instructions, of course only with compile-time constant parameters. (Disclaimer: I know how to use SFRs. But this way it is much more intuitive and beginner-friendly.)

@EdgarBonet it may be true that digitalWrite() does not rely on interrupts. Also, as far as i know it takes about 4us per write, where port manipulation takes one or a few clock cycles (~0.1 us). Nevertheless I have experienced catastrophic events when updating pins with digitalWrite() during ISR. Whatever was happening, it resulted with memory corruption and subsequent controller crash, a few lines of code later. Diverging from digitalWrite() to port manipulation fixed the issue, although it might have been for another reason than I remember.


text:
AccelStepper.h - How can I quickly increase the speed of a NEMA 17 motor?
I'm pretty new to Arduino. I am trying to build a self-balancing robot. I am using A4988 drivers, an ESP32 microcontroller, NEMA 17 motors, and a 6050 MPU.
The problem is that, although the speed variable changes according to the position of the MPU, the motors rotate at a slow and constant speed, without varying according to the inclination of the robot.
Here is the code:
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#include <AccelStepper.h>

#define STEP_IZQ 26
#define DIR_IZQ 27
#define STEP_DER 12
#define DIR_DER 13

AccelStepper stepperizq(AccelStepper::FULL2WIRE,STEP_IZQ,DIR_IZQ);
AccelStepper stepperder(AccelStepper::FULL2WIRE,STEP_DER,DIR_DER);
Adafruit_MPU6050 mpu;

float kp = 20;
float ki = 0.5;
float kd = 30;

float angulo_grad, error, cumError, rateError, output, lastError;
float pid_error_temp, pid_i_mem, pid_setpoint, gyro_input, pid_output, pid_last_d_error;
int speed, outputAbs;

void setup(void) {
  Serial.begin(115200);
  while (!Serial)
    delay(10); // will pause Zero, Leonardo, etc until serial console opens

  Serial.println("Adafruit MPU6050 test!");

  // Try to initialize!
  if (!mpu.begin()) {
    Serial.println("Failed to find MPU6050 chip");
    while (1) {
      delay(10);
    }
  }
  Serial.println("MPU6050 Found!");
  mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
  mpu.setGyroRange(MPU6050_RANGE_500_DEG);
  mpu.setFilterBandwidth(MPU6050_BAND_5_HZ);

  pinMode(DIR_IZQ, OUTPUT);
  pinMode(DIR_DER, OUTPUT);

  stepperizq.setMaxSpeed(3000);
  stepperder.setMaxSpeed(3000);
  stepperizq.setAcceleration(1000); // 1000
  stepperder.setAcceleration(1000); // 1000
}

void loop() {
  // Get new sensor events with the readings
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  angulo_grad = atan((a.acceleration.x)/(a.acceleration.z))*(180/3.14);            // 0 to 90 degrees
  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  // pid
  /////////////////////////////////////////////////////////////////////////////////////////////////

  pid_error_temp = angulo_grad;
  if ((pid_error_temp > -2.0) && (pid_error_temp < 2.0)) pid_error_temp = 0.0;

  pid_i_mem += ki * pid_error_temp;                                 // Calculate the I-controller value and add it to the pid_i_mem variable
  if (pid_i_mem > 800) pid_i_mem = 800;                                       // Limit the I-controller to the maximum controller output
  else if (pid_i_mem < -800) pid_i_mem = -800;
  // Calculate the PID output value
  pid_output = kp * pid_error_temp + pid_i_mem + kd * (pid_error_temp - pid_last_d_error);
  if (pid_output > 5000) pid_output = 5000;                                     // Limit the PI-controller to the maximum controller output
  else if (pid_output < -5000)pid_output = -5000;

  if (output < 50 && output > 50) output = 0;
  pid_last_d_error = pid_error_temp;
  ////////////////////////////////////////////////////////////////////////////////////////////////////
  //motors nema 17
  //////////////////////////////////////////////////////////////////////////////////////////////////////////////
  outputAbs = (int)abs(pid_output);
  speed = map(outputAbs, 0, 5000, 0, 3000);

  stepperizq.setSpeed(speed);
  stepperder.setSpeed(speed);

  if (pid_output<0) {
    digitalWrite(DIR_IZQ, LOW);
    digitalWrite(DIR_DER, HIGH);
  }
  else if (pid_output>0) {
    digitalWrite(DIR_IZQ, HIGH);
    digitalWrite(DIR_DER, LOW);
  }
  stepperizq.runSpeed();
  stepperder.runSpeed();
}

Just a guess, but can it be, that your loop() is running to slow for it to keep up with the necessary steps? If for example the sensor readings are taking too long (in the range of the period between two consecutive steps), then each execution of runSpeed() would find, that it always was time to do a step, doing exactly one step and then exiting to the rest of loop(). That would limit your speed to one step per loop() iteration, which probably has a constant duration. You could try to only get new measurements at set intervals (like every x ms)

Agree with @chrisl.   Try wrapping the measurement & calculations in an if (millis() - last > interval){...} throttle.

I added this:

currentMillis = millis();
if(currentMillis - previousMillis >=100){
previousMillis = currentMillis;
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
angulo_grad = atan((a.acceleration.x)/(a.acceleration.z))*(180/3.14);            //0 to 90 degrees

}

And it worked. Thank you all for ypur help

To write down my guess from the comments in a proper answer:
When a stepper motor driven with AccelStepper shows a constant speed, though the speed is set to different values, it suggests, that the time interval of the steps is defined by something else.
The runSpeed() function works by saving a timestamp of the last step and then checking the elapsed time on the basis of the set speed, to check if the time for another step has come and if yes, then execute exactly one step. For this to work correctly, you need to call this function within intervals smaller than the smallest period between two consecutive steps for your speed.
If for whatever reason you call the function with larger intervals, the runSpeed() function will always see, that the time for a new step has come, but it will always only do one step per execution. Thus you overall get one step per runSpeed() execution, and this is determined by the rest of your code, not the set speed.
The rest of the code in loop() is for getting the measurements of the MPU and calculating the resulting speeds from that. Probably this is taking too long and thus hindering the AccelStepper library from running the motor at the specified speeds. So you need to provide a larger timeslot for the stepper driving on your ESP by cutting down on your MPU sampling rate. This is easiest done by using
// Running MPU sampling and calculation only every 100ms
if(millis() - previousMillis >= 100){
  previousMillis += 100;
  // MPU and calculation code here
}
// Running the stepper code on every loop iteration
stepperizq.runSpeed();
stepperder.runSpeed();

which is the non-blocking coding style used in the BlinkWithoutDelay example. If you don't know how to use millis(), there are many tutorials online for that.

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
What is the purpose of Serial.println() without an argument?
I am attempting to control a stepper motor with Sparkfun's Big Easy Driver, and I see the line "Serial.println();" they put in the example code. Why is there no argument and what function does this serve?
//Declare pin functions on Arduino
#define stp 2
#define dir 3
#define MS1 4
#define MS2 5
#define MS3 6
#define EN  7

//Declare variables for functions
char user_input;
int x;
int y;
int state;

void setup() {
  pinMode(stp, OUTPUT);
  pinMode(dir, OUTPUT);
  pinMode(MS1, OUTPUT);
  pinMode(MS2, OUTPUT);
  pinMode(MS3, OUTPUT);
  pinMode(EN, OUTPUT);
  resetBEDPins(); //Set step, direction, microstep and enable pins to default states
  Serial.begin(9600); //Open Serial connection for debugging
  Serial.println("Begin motor control");
  Serial.println();
  //Print function list for user selection
  Serial.println("Enter number for control option:");
  Serial.println("1. Turn at default microstep mode.");
  Serial.println("2. Reverse direction at default microstep mode.");
  Serial.println("3. Turn at 1/16th microstep mode.");
  Serial.println("4. Step forward and reverse directions.");
  Serial.println();
}

prints everything in the argument, followed by a newline .... in other words, prints just a newline

when you post  code in a question, select all of the code and press ctrl-k or click the {} button .... all of the code will be indented by 4 spaces, which causes  it to be displayed as code ...... upvote for being concerned with code formatting

That's simple. Thanks! So if you had printed text (surrounded by quotation marks) before, the same effect would be achieved by putting in a "\n", correct?

yes, serial.print("\n"); gives same result as serial.println();

@jsotola: No, Serial.println() outputs a '\r' before the '\n', which Serial.print("\n") doesn't.

To complement jose can u c's answer: the Arduino Serial object uses
CRLF as the end-of-line marker. That's an ASCII CR (carriage return,
or '\r' in C) followed by ASCII LF (line feed, '\n' in C). Thus,
Serial.println();

is equivalent to
Serial.print("\r\n");

This is a cool expansion on some fundamental formatting stuff. Thank you for the info

It simply prints a newline to the serial monitor. Just for spacing.

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Send data to API from Arduino with ESP8285 Strange Error
I have an Arduino with few sensors, and I want to send all of data to my API over ESP8285 what is connected to the wifi.
Its almost working fine, except one thing.
I have these AT commands:
String postRequest =
    "POST /hello HTTP/1.1" + String("\r\n") +
    "Host: 192.168.88.186" + "\r\n" +
    "Cache-Control: no-cache" + "\r\n" +
    "Content-Type: application/x-www-form-urlencoded" + "\r\n" +
    "Content-Length: " + String(data.length()) + "\r\n\r\n" +
    String(data) + "\r\n";

void connectWifi()
{
  espclient.println("AT+CWMODE=1");
  String connectcmd = "AT+CWJAP=\"" + ssid + "\",\"" + w_password + "\"";
  espclient.println(connectcmd);

  delay(3000);
  if (espclient.find("OK"))
  {
    Serial.println("Connected!");
  }
  else
  {
    connectWifi();
    Serial.println("Cannot connect to wifi");
  }
}

void espStatus()
{
    String tmpResp = espclient.readString();
    Serial.print("ESPLOG:");
    Serial.println(tmpResp);
}

void httppost()
{
  espclient.println("AT+CIPMUX=0");
  espclient.println("AT+CIPSTART=\"TCP\",\"" + server + "\",5000"); //start a TCP connection.
  if (espclient.find("OK"))
  {
    Serial.println("TCP connection ready");
  } else {
    espStatus();
  }
  espclient.println("AT+CIPSTATUS");
  espStatus();

  Serial.println("PRINT REQUEST ==================================");
  Serial.println(postRequest);
  Serial.println("PRINT REQUEST ==================================");

  espclient.println("AT+CIPSEND="+String(postRequest.length()));
  do {
    delay(1000);
    if (espclient.find(">"))
    {
      break;
    }
  }
  while(true);
  espclient.print(postRequest);
  delay(500);
  espStatus();
  espclient.println("AT+CIPCLOSE");
}

SETUP:
void setup() {
  Serial.begin(9600);
  Serial.println("Starting the modules....");

  espclient.begin(9600);
  connectWifi();
  Serial.println("ESP Module is ready");
}

LOOP:
void loop() {
    httppost();
    delay(5000);
}

And I get this error(?) message:
TCP connection ready
ESPLOG:
AT+CIPSTATUS

STATUS:2

OK

PRINT REQUEST ==================================
POST /hello HTTP/1.1
Host: 192.168.88.186
Cache-Control: no-cache
Content-Type: application/x-www-form-urlencoded
Content-Length: 13
name=ESPModul

PRINT REQUEST ==================================
ESPLOG: Q�J5U�S�!*HZYlo QQA��HV�^\��
H��銒)       �&�C��y \�R
�r�+����H�

TCP connection ready
ESPLOG:
AT+CIPSTATUS

STATUS:2

OK

PRINT REQUEST ==================================
POST /hello HTTP/1.1
Host: 192.168.88.186
Cache-Control: no-cache
Content-Type: application/x-www-form-urlencoded
Content-Length: 13
name=ESPModul

PRINT REQUEST ==================================
ESPLOG: Q�J5U�S�!*HZYlo QQA��HV�^\��
H����)      �&AC��y \�R
�r�+����H�

UPDATE The new /error/ message:
ESPLOG:Q�J5U�SS�CT��he���EE))���H��
����    )�H��HK�
Ca����E�K�V,YCCb

UPDATE2 I restarted the arduino, and now I am getting this:
TCP connection ready
PRINT REQUEST ==================================
POST /hello HTTP/1.1
Host: 192.168.88.186
Cache-Control: no-cache
Content-Type: application/x-www-form-urlencoded
Content-Length: 13

name=ESPModul

PRINT REQUEST ==================================
ESPLOG:
AT+CIPSTATUS

STATUS:2

OK
AT+CIPSEND=155

link is not vAT+CIPCLOSE

ERROR

UPDATE3: This method is working
void testHTTP()
{
  Serial.println("Establishing TCP connection");
  espclient.println("AT+CIPSTART=\"TCP\",\"" + server + "\",5000");
  delay(1000);
  Serial.println("Sending out data…");
  espclient.println("AT+CIPSEND=16");
  espclient.println("GET / HTTP/1.1");
  espclient.println();
  espclient.println("AT+CIPCLOSE");
}

If I connect the ESP to my PC with TTL adapter, and I write the commends manually, then its working fine. And yes, the ESP is connecting correctly to the wifi, I tested it.
The main solution was to put "delay(1000);" after "CIPSEND=".
I hope my fumbling can help to someone in the future.

add one more \r\n for mandatory empty line after HTTP request header. "Content-Length: " + String(data.length()) + "\r\n\r\n" +.

Serial.println("ESPLOG: "+tmpResp), prints some random memory content at address calculated by the +. use Serial.print("ESPLOG:"); Serial.println(tmpResp);

wait for > after CIPSEND

@Juraj: No, why? Overload resolution for "ESPLOG: "+tmpResp will interpret it as String("ESPLOG: ") + tmpResp, which uses overloaded binary + for String type. Everything is correct in that expression: it does concatenate two Strings into a new String. It is unnecessarily "heavy", but otherwise perfectly correct.

@Juraj Thanks for the advice, I tried what you said, but I have the same issue. The new error message is a bit different. I added the new message to the post.

you still print wrong and you still don't wait for >

@Juraj No, I just didn't updated in the code. But now I updated those parts.

try not to request status between connection and data sending

@AnT, "ESPLOG" is const char*. what does a + do for pointer type?

There's no "+ for a pointer type" here. This is a binary +, which has two equally important operands. One operand is const char[7], another is String. This launches a process called overload resolution. And overload resolution will conclude that the best match in this case is overloaded operator + for two String operands. It will let const char[7] to decay to const char * and then it will implicitly convert it to a temporary String object. Then it will add (concatenate) two String objects forming a String result.

To put it shorter, if just one operand of binary + is a String (no matter which), the other operand will typically be implicitly converted to a String as well. And you end up with concatenation and a new String.

@AnT, yes, you are right

@G3ph4z, did you set the baud rate of AT firmware to 9600 baud?

@Juraj Sorry, I was AFK. Yea, I changed the baud in the ESP's firmware. I will test the code without ESPStatus, as you said before.

So I tried, but nothing. It doesn't send me any packet, also I can ping the ESP modul.

maybe the esp8266 crashed on connecting because of insufficient powering


text:
Parsing Integers from Serial data stream
I'm trying to send sensor data from my Remote Control to my Bot via Bluetooth.
It's 6 numbers that I would like to have read as integers on the other side.
I'm printing them to Serial on the Remote side with the numbers separated by commas. I've also added a start marker "<" and an end marker ">".
The incoming data from the remote looks like this in the Bots Serial Monitor:
<1,1,1,1,1,512>
<1,1,1,1,1,512>
<1,1,1,1,1,513>
<1,1,1,1,1,512>
<1,1,1,1,1,512>
etc
Before adding in the markers I was trying to use Serial.parseInt() to do this, but I kpet getting out of order numbers (probably from no start marker?).
if (Serial1.available() > 0) {

 trig1 = Serial.parseInt();
 trig2 = Serial.parseInt();
 trig3 = Serial.parseInt();
 trig4 = Serial.parseInt();
 trig5 = Serial.parseInt();
 pot = Serial.parseInt();

if (Serial.read() == '\n') {
}
}

But now that I have the markers I don't know the best way to initialize the code.  Anyone have any ideas on how to parse these 6 numbers into usable integers?
EDIT:  I've wrote a code based on VE7JRO's comments.
uint16_t myArray[6] = {};
int counter = 0;

void setup(){

Serial.begin(9600);

}

void loop(){
  if (Serial.available() > 0) {
  char* pch = strtok(Serial.read,"<>,\r\n");
   }
while(pch != NULL){
  myArray[counter] = atoi(pch);
  pch = strtok(NULL, "<>,\r\n");
  counter += 1;
 }

 trig1 = myArray[0];
 trig2 = myArray[1];
 trig3 = myArray[2];
 trig4 = myArray[3];
 trig5 = myArray[4];
 pot   = myArray[5];

 Serial.print (trig1);
 Serial.print (", ");
 Serial.print (trig2);
 Serial.print (", ");
 Serial.print (trig3);
 Serial.print (", ");
 Serial.print (trig4);
 Serial.print (", ");
 Serial.print (trig5);
 Serial.print (", ");
 Serial.println(pot);
 }

I'm getting this error code: invalid use of non-static member function
for this line:
      char* pch = strtok(Serial.read,"<>,\r\n");

Other than that. I subbed out the test input that  VE7JRO put in and inserted "Serial.read". Not sure if that is the correct way to do this.  Any ideas?
I tried your second sketch.  It kind of worked.  The data that printed to the serial monitor looked like this:
1, 1, 1, 1, 1, 519
518, 1, 1, 1, 1, 519
1, 1, 1, 1, 19, 9
1, 1, 1, 1, 1, 519
1, 1, 1, 1, 1, 519
1, 1, 1, 1, 1, 518
1, 1, 519, 518, 1, 518
1, 1, 519, 518, 1, 518
1, 1, 518, 518, 1, 518
1, 1, 1, 1, 1, 8
1, 1, 1, 1, 1, 519
1, 1, 518, 1, 1, 1
8, 1, 518, 1, 1, 1
1, 1, 519, 1, 1, 1
1, 1, 1, 519, 1, 1
1, 1, 1, 519, 1, 1
1, 1, 1, 1, 1, 519
1, 1, 1, 1, 1, 518
1, 1, 1, 1, 519, 8
1, 1, 1, 1, 1, 518
1, 1, 1, 1, 1, 519
1, 1, 1, 1, 1, 518
1, 1, 1, 1, 1, 518
1, 1, 1, 1, 1, 520
it should have all been   1, 1, 1, 1, 1, 518(ish).

The parseInt has a timeout. That can slow down a sketch. You could fill a buffer with data (one byte each time) and when all the data is read then do a sscanf. For parseInt you have to skip the comma. The "<" and ">" markers is very good. Please give a minimal sketch that reads data from the serial monitor so we can test it.

Here is a sketch that uses strtok() and atoi() to parse the data and store the results in an integer array.
char testInput[] = "<1,2,3,4,5,512>\r\n";
uint16_t myArray[6] = {};

void setup(){

  Serial.begin(9600);

  int counter = 0;
  char* pch = strtok(testInput,"<>,\r\n");

  while(pch != NULL){
    myArray[counter] = atoi(pch);
    pch = strtok(NULL, "<>,\r\n");
    counter += 1;
  }

  // Print out the contents of the integer array.
  for(int i = 0; i < counter; i++){
    Serial.println(myArray[i]);
  }

}

void loop(){}

EDIT
Based on your comments, I have another sketch for you to try.
// Sample input: <1,2,3,4,5,512>
char testInput[40];
uint16_t myArray[6] = {};
int counter = 0;

void setup(){
  Serial.begin(9600);
}

void loop(){

  if(Serial.available() > 0){

    Serial.readBytesUntil('\n', testInput, 40);

    char* pch = strtok(testInput,"<>,\r\n");

    while(pch != NULL){
      myArray[counter] = atoi(pch);
      pch = strtok(NULL, "<>,\r\n");
      counter += 1;
    }

    Serial.print (myArray[0]);
    Serial.print (", ");
    Serial.print (myArray[1]);
    Serial.print (", ");
    Serial.print (myArray[2]);
    Serial.print (", ");
    Serial.print (myArray[3]);
    Serial.print (", ");
    Serial.print (myArray[4]);
    Serial.print (", ");
    Serial.println(myArray[5]);

    counter = 0;
  }
}

This is very helpful!  I think I understand most of it.
Does this really all run in the setup?
I don't want to print the array, but rather use each int as a variable in the rest of my sketch.  Is there a function to use for that?   Sorry I'm a bit of a beginner and just barely grasping this as a whole

All the code is in setup() for testing purposes. The integer array contains the 6 integers and can be used as variables in the rest of your sketch. Every time you receive new data, it should be parsed using strtok().

So would this give me the variables from the the array?
trig1 = myArray[1];
trig2 = myArray[2];
trig3 = myArray[3];
trig4 = myArray[4];
trig5 = myArray[5];
pot = myArray[6];
I can't test right now otherwise I would just test myself.  Excited to find the answer!

Yes, you could do that, or just use the array directly e.g. if(myArray[0] > 1){ //do something}.

Thank you so much, this was very helpful!

I edited the OP with my code.  Getting an error on one of the lines

I edited the OP with the results of your second sketch. Mixed results.

Try sending a \n at the end of your data: "<1,1,1,1,1,512>\n"


text:
Is it possible to program an ESP8266 12F using an Arduino Nano?
I just got my ESP8266, but I am unable to program it. Since it can't be connected to via USB, I was wondering if I can program it using an Arduino or perhaps use it as a shield for an Arduino Nano. I haven't been able to find a good guide online. Any help is greatly appreciated.

Why can't connect via usb?

Yes, you can program it with Arduino but its a bit complex that way. You will need a separate Linear Regulator with Adjustable Output to get it hooked up with the Arduino.
 Its way better to have an FTDI adapter to program it.
But if you still want to know, there is a tutorial below,
Upload Bareminimum sketch so that no program is running on the Arduino.

Is it possible to program an ESP8266 12F using an Arduino Nano?

Yes, but it is much easier to use a FTDI for USB-to-Serial adaptation. Two buttons are also needed to activate the ESP8266 programming mode.
Cheers!

Actually that tutorial has some fairly serious problems.  It claims the regulator is an "LM1117" but neglects to mention that this part comes in various voltage ratings, and it neglects to mention capacitors required by the regulator data sheet.  The author might have gotten away with it using the part they had on hand, but it is not good guidance.

Could you suggest a link to a better tutorial? Please feel free to update.

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
How to check 8266 module
I am using an Arduino board with an ESP8266 module to connect to a WiFi device.
How do I check if the device is connected?

Which Arduino board? Check the associated stations on your router to see if the device is associated (connected) to your router

You can use:
AT+ CWJAP?

or
AT+ CIPSTATUS

to see if you're connected to wifi. (The first will tell you access point status, the second will tell you IP address.)

This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. - From Review

Revised to be the form of an answer :-)

Firstly,If your ESP8266 module is coded then AT commands won't be responding directly, In that case You can check in Serial monitor(if u already wrote print in the existing code on module) else u have to flash a new code.
If didn't flash any code then use AT commands(AT+CWJAP?) for checking SSID.
(AT+ CIPSTATUS) for IP adress.

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
How to filter out "jumpy" readings sent using Bluetooth
I'm using App Inventor to continuously send orientation values (as strings) to my Arduino, which are read using Serial.parseInt(). Using simple IF statements (if value > threshold), I'm trying to turn on an LED and otherwise turn it off.
What I'm getting however, is an LED that goes on and off along with these values, which alternate between the actual and desired values and extreme unwanted values as shown in the picture:

Given that my orientation values, as they are, alternate between -180 to 180, I'm using a simple IF statement that seems to work reasonably well, except when the unwanted readings give inaccurate values that are within my range.

My Arduino code:
#include <SoftwareSerial.h>

const int TXD = 3;
const int RXD = 4;
SoftwareSerial mrBlue(TXD, RXD);

void setup() {
  // put your setup code here, to run once:

  Serial.begin(9600);

  mrBlue.begin(9600);
  Serial.setTimeout(20);
  mrBlue.setTimeout(20);
}

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

  if (mrBlue.available() > 0) {

    int data = mrBlue.parseInt();
    if (data > 180 || data < -180) {

    }
    else {
      Serial.println(data);
    }
  }
}

Not sure if this works for your needs, but I usually smooth noisy data by keeping a small buffer of the last 3-5 values and averaging them. A larger buffer gives more stable values at the cost of latency after a legit change.

This data is terribly noisy. My first approach would be to understand why, and then decide whether I could fix it, or have to live with it. It's easy to filter out the out of range data, but why is it there? Is it the sensor? If the sensor is analog, is the noise to due electrical pickup in its leads? Until you know, how can you trust even the apparently "good" data?

@JamesMcManus: With this kind of “wide tail” noise, a running median filter is way more efficient than a running average.

authors: Дмитрий Печуркин


text:
Serial monitor isn't updating in while loop
I'm trying to make a lamp that fades when it reacts with surrounding light. I've installed a library from github  that doesn't require the delay (). The serial monitor doesn't refresh.
The lamp is supposed to fade from 0-255 when in the dark and fade 255-0 when in light. It's supposed to happen only once so I can't put it in loop().
The LED is connected to PWM pin 10. The LDR sensor is connected to A0.
#include <LEDFader.h>
int sensorvalue = analogRead(A0);
LEDFader led = LEDFader(10);

void setup(){

  if(sensorvalue<=380){
    led.set_value(0);
    led.fade(255, 3000);
  }
  if(sensorvalue>=555){
    led.set_value(255);
    led.fade(0,3000);
  }
}

void loop() {
  Serial.begin(9600);
  Serial.println(sensorvalue);
  led.update();

}

Please post the code as something other than a screen shot. You have some fairly big mistakes in that code but I'm not going to sit here re-typing it from a picture when you can't be bothered to copy and paste it.

@Andrew  sorry was typing this question on a mobile phone. Code will be up in few minutes

@Visual Micro  i can't put the fade code at while loop as it will repeat it's process of turning on and off. I only want it to do it once

I have edited the example to show how to only change fade when the analog value changes. If you only want it once then do it in the setup() but if it needs an analog reading that does not make sense. My example shows how the fade can respond to a valid analog reading at any single moment.

Maybe you were still struggling so the answer has been updated to a complete working example.

@VisualMicro but will the fading keep repeating itself? Cause I'm trying to find a way that only runs once.

You need to be clear about what you want to happen once? If you put all the code in the setup() it will happen only once with the analog reading found when the cpu starts. If you put the led.update() in the loop then the loop will keep fading the led using the values read once in the setup(). So put the code in the setup that needs to run once. I will try to update with a few variations.

Arduino does not work that way. You only try to read a sensor value outside of a function, so will happen once only, if it works at all. You need to read the sensor more often and always read from within a function.
Serial.begin() is used once when the code starts, so that will be in the setup()
Your LED fade values are only set one time, when the cpu starts because you have the fade in the setup().
In the following example we do all fade code in the loop() but change the fade values only when the sensor reading changes.
#include <LEDFader.h>
LEDFader led = LEDFader(10);

int sensorValue = 0;
int sensorValueLast = 0;

void setup()
{
   Serial.begin(9600);
}

void loop()
{
  sensorValue = analogRead(A0);
  Serial.println(sensorValue);

        if (sensorValueLast!=sensorValue)
        {
          sensorValueLast = sensorValue;
          if(sensorvalue<=380)
          {
             led.set_value(0);
             led.fade(255, 3000);
          }
          if(sensorvalue>=555)
          {
            led.set_value(255);
            led.fade(0,3000);
          }
        }

  led.update();
}

This example only calls led.fade() when the sensor value changes but uses the same sensor reading that was found during startup. The sensor is read just once time and the fade values are set just one time.
#include <LEDFader.h>
LEDFader led = LEDFader(10);

int sensorValue = 0;
int sensorValueLast = 0;

void setup()
{
   Serial.begin(9600);
}

void loop()
{
  sensorValue = analogRead(A0);
  Serial.println(sensorValue);

        if (sensorValueLast!=sensorValue)
        {
          sensorValueLast = sensorValue;
          if(sensorvalue<=380)
          {
             led.set_value(0);
             led.fade(255, 3000);
          }
          if(sensorvalue>=555)
          {
            led.set_value(255);
            led.fade(0,3000);
          }

          led.update();
        }
}

This example does everything just one time, when the cpu starts
#include <LEDFader.h>
LEDFader led = LEDFader(10);

int sensorValue = 0;

void setup()
{
   Serial.begin(9600);

   sensorValue = analogRead(A0);
   Serial.println(sensorValue);

          if(sensorvalue<=380)
          {
             led.set_value(0);
             led.fade(255, 3000);
          }
          if(sensorvalue>=555)
          {
            led.set_value(255);
            led.fade(0,3000);
          }

          led.update();

}

void loop()
{
   //we will always see the same value
   Serial.println(sensorValue);
}


text:
Timer Interrupt Collision
I am working with a MEGA2560 trying to implement velocity ramps for three steppers at the same time. The goal is to move to different positions applying accelerations and decelerations while finishing all of them at the same time.
In order to do so, from the distances to move of each of the motors, I calculate the amount of steps to do and the velocities for each of those steps in order to ensure that all the motors finish at the same time. For so, I use timers 3, 4 and 5 in compare mode. This way, at each interruption, I make the motors do one step and, after that, I set the new compare value for the timer in order to reach the new velocity to move at.
My problem is that, at some point, my interruptions crash and one of the motors stops working. This only happens under one condition: when motor 1 has to do 18 steps and motor 2, 34. In this case, both motors 1 and 3 finish but motor 2 gets stuck and does not move any more. Although, if its motor 1 who has to do 34 steps and motor 2, 18, everything works. Motor 1 is related to timer 3 and motor 2 to timer 4. This makes me think this must be related to the priorities of the interruptions.
In the following code you can see my interruptions:
ISR(TIMER3_COMPA_vect) {
    m1_step();
    m1_steps_done++;
    m1_configure_vel();
}
ISR(TIMER4_COMPA_vect) {
    m2_step();
    m2_steps_done++;
    m2_configure_vel();
}
ISR(TIMER5_COMPA_vect) {
    m3_step();
    m3_steps_done++;
    m3_configure_vel();
}

While, in the velocity configuration I have:

void m1_configure_vel() {

  if (m1_steps_done < m1_acceleration_steps) {
    m1_temp_vel = m1_temp_vel + acceleration;
  }
  else if (m1_steps_done <= (m1_steps - m1_acceleration_steps)) {
    m1_temp_vel = m1_temp_vel;
  }
  else if (m1_steps_done < m1_steps) {
    m1_temp_vel = m1_temp_vel - acceleration;
  }
  else {
    m1_temp_vel = 0;
    m1_finished = true;
  }
  if (m1_temp_vel <=0){
    m1_temp_vel = 0;
  }

  OCR3A = frequency_to_compare_value(m1_temp_vel);
}

As you can see, all I do here is, depending on the steps done by the motor and the amount of steps to do, I increase, maintain or decrease the motor's velocity and set the compare value for the timer.
The whole thing is that this code works fine, the ramps are calculated properly and motors move correctly. The problem is that, under the condition I explained before, interruptions may collide due to their priorities and one of them just stops to happen.
I was wondering if anyone had any idea or have faced something like this before.

Thats a weird problem. As I know, there is no interrupt priority on AVR chips. If an interrupt happens, while another ISR is currently running, the corresponding flag is set and the ISR execution will happen after the first ISR finishes. Do you have access to an oscilloscope or a logic analyzer? It might be good to check, if the expected signal is getting outputted on the motor2 pin. Maybe there is a hardware problem. Or are you having any code, that might use one of the timers?

Thanks for your response @chrisl . I discard hardware problems since the whole system does work in all other situations. I have now tried to change the prescaler of the timers. They were set to 1 but now I have configured them to 8, so timers how a frequency of 2MHz now. Surprisingly, the system does not fail now, the whole sequence is done with no errors and none of the interruptions freeze. I suppose that by reducing the timers' frequency, they may now be working under less "pressure" so that they may not be hitting each other.

@chrisl There is what is called "natural priority" - each intrerupt has a number, and they are checked in sequence - interrupts with lower numbers happen before those with higher numbers. If a lower numbered interrupt re-occurs before the higher numbered one has a chance to run it will be responded to in preference to that higher numbered one. Which is why ISRs need to be as short as possible.

@Majenko I have implemented these timer interruptions at a frequency way higher than the one the crash I mentioned before happens. When this situation happens and my interruptions stop, none of them have a frequency higher than 500Hz, while, with the same code, they can make simultaneous movements at 4kHz. With this I mean that my code inside interruptions doesn't last enough for not letting other interruptions to happen. In my critical case, the ISR frequencies are low enough to run all the code inside but, with no sense, one of them simply gets stuck.

@Majenko Oh, interessting. Didn't know that, thanks :)

I'm surprised no one asked for you to post compilable code.  We don't even have the data types involved.

I think the problem is being caused by the size of your ISR's.
When using ISR's, it's important to make the code as short as possible and you should certainly avoid using any functions!
I would change each of your ISRs to:
ISR(TIMER3_COMPA_vect) {
    m1_steps_done++;
}
ISR(TIMER4_COMPA_vect) {
    m2_steps_done++;
}
ISR(TIMER5_COMPA_vect) {
    m3_steps_done++;
}

then, in the main loop of your code, you can change it so that if m1_steps_done, or m2_steps_done or m3_steps_done has increased, execute the step and configure functions

Another approach might be to use a single timer instead of 3 separate ones.  Maintain 3 software counters and increment all of them on each interrupt, with separate limit tests and resets.  This will be slightly slower, but there will be no possibility of collisions.


text:
Difficulties acquiring angle values from MPU6050
I'm attempting to acquire angle values from an MPU6050 IMU sensor using an ESP32-DevKitM-1 microcontroller.
My setup contains the ESP32 board, the MPU6050 board, and an SD card reader to save the readings from the sensor:

I'm using the Arduino IDE v2.3.0.
I adapted the following testing code excerpt from another post about sensor, using the newer Adafruit_MPU6050 library and the SD functions:
#include <Wire.h>
#include "SPI.h"

#include <Adafruit_Sensor.h>
#include <Adafruit_MPU6050.h>

#include "SD.h"

const int PIN_IMU_SCL = 22;
const int PIN_IMU_SDA = 21;
const int PIN_SD_CS = 23;
const int PIN_SD_MISO = 10;
const int PIN_SD_MOSI = 18;
const int PIN_SD_CLK = 5;

const int IMU_GyroScale = 131;

Adafruit_MPU6050 IMU;
double IMU_Time;
double IMU_TimePrev = -1;
double IMU_GyroRotX;
double IMU_GyroRotY;
double IMU_GyroRotZ;

File DataFile;

void IMU_GetData(double& angleX, double& angleY, double& angleZ, double& temp)
{
  bool firstTime = false;

  if (IMU_TimePrev == -1)
    firstTime = true;

  // Calculating the elapsed time...
  IMU_TimePrev = IMU_Time;
  IMU_Time = millis();
  double timeDelta = (IMU_Time - IMU_TimePrev) / 1000;

  // Acquiring the readings from the accelerometer & gyroscope...
  sensors_event_t accelData;
  sensors_event_t gyroData;
  sensors_event_t tempData;
  IMU.getEvent(&accelData, &gyroData, &tempData);

  // Calculating the accelerometer angle...
  double accelRotX = (180 / PI) * atan(accelData.acceleration.x / sqrt(pow(accelData.acceleration.y, 2) + pow(accelData.acceleration.z, 2)));
  double accelRotY = (180 / PI) * atan(accelData.acceleration.y / sqrt(pow(accelData.acceleration.x, 2) + pow(accelData.acceleration.z, 2)));
  double accelRotZ = (180 / PI) * atan(sqrt(pow(accelData.acceleration.x, 2) + pow(accelData.acceleration.y, 2)) / accelData.acceleration.z);

  // Calculating the gyroscope angle...
  double gyroRotX = (gyroData.gyro.x / IMU_GyroScale);
  double gyroRotY = (gyroData.gyro.y / IMU_GyroScale);
  double gyroRotZ = (gyroData.gyro.z / IMU_GyroScale);

  // Combining the two (complementary filter)...
  if (firstTime)
  {
    IMU_GyroRotX = accelRotX;
    IMU_GyroRotY = accelRotY;
    IMU_GyroRotZ = accelRotZ;
  }
  else
  {
    IMU_GyroRotX += timeDelta * gyroRotX;
    IMU_GyroRotY += timeDelta * gyroRotY;
    IMU_GyroRotZ += timeDelta * gyroRotZ;
  }

  angleX = (0.96 * accelRotX) + (0.04 * IMU_GyroRotX);
  angleY = (0.96 * accelRotY) + (0.04 * IMU_GyroRotY);
  angleZ = (0.96 * accelRotZ) + (0.04 * IMU_GyroRotZ);

  temp = tempData.temperature;
}

bool IMU_Init()
{
  bool status = IMU.begin();

  if (status)
  {
    IMU.setAccelerometerRange(MPU6050_RANGE_8_G);
    IMU.setGyroRange(MPU6050_RANGE_500_DEG);
    IMU.setFilterBandwidth(MPU6050_BAND_21_HZ);
  }

  IMU_Time = millis();

  delay(100);

  return status;
}

void setup()
{
  Serial.begin(9600);
  Serial.println("Initializing...");

  Wire.begin(PIN_IMU_SDA, PIN_IMU_SCL);
  IMU_Init();

  SPI.begin(PIN_SD_CLK, PIN_SD_MISO, PIN_SD_MOSI, PIN_SD_CS);

  while (!SD.begin(PIN_SD_CS))
  {
    Serial.println("Unable to open SD!");
    delay(500);
  }

  DataFile = SD.open("/angles.txt", FILE_WRITE);
  DataFile.close();

  delay(100);
  Serial.println("Initialized!");
}

void loop()
{
  double angleX;
  double angleY;
  double angleZ;
  double temp;
  IMU_GetData(angleX, angleY, angleZ, temp);
  String anglesStr = String(angleX) + ":" + String(angleY) + ":" + String(angleZ);

  DataFile = SD.open("/angles.txt", FILE_APPEND);
  DataFile.println(anglesStr);
  DataFile.close();

  Serial.println(anglesStr);

  delay(200);
}

Where IMU_GetData is the function responsible for acquiring the angle data from the gyroscope and the accelerator sensors on the MPU6050 board, and implementing a filter to attain a set of filtered angle values.
I then simply save the filtered angle values to the SD card. I communicate with the sensor using the Wire I2C library, and with the SD card using the SPI library.
The main issue I'm running into is the fact that the resultant angle values do not appear to accurately represent the rotation of the sensor.
As a test, I rotated the sensor 360° slowly around each one of the 3 axes, and saved the continuous angle readings during each rotation:

The time interval between each reading in the plots above is ~0.2 s.
The first issue is that a rotation about the Z-axis visible in the last graph above appears to not cause any appreciable change in any of the angle readings.
I initally assumed that could be caused by the value of the IMU_GyroScale constant that the gyroscope angle values get multiplied by during the calculations carried out in the IMU_GetData function. I assumed that all MPU6050 chips will use that same scaling factor, but then I tried several of the other listed scaling factors listed in the datasheet, with no appreciable difference.
Is there something visibly wrong in my code with the angle calculations for the Z-axis? Could this be a sign of a defective sensor board?
The second thing I was curious about was the format of the filtered angle values.
I initially assumed that the filtered angle values I would be getting from the sensor would be the Euler angles; Roll, Pitch & Yaw. However, these appear to not represent those.
In fact, one of the main sources listed in the original posting that describes in detail the process of calculating the filtered angle values, also provides a visualization of the angle values acquired from the sensor:

Are these "tilt" values related to Euler angles? Is it possible to convert between the two?

The formulas you are using look plain wrong. There are a few issues that
stick out:

Rotating along z has no effect on the accelerometers. Any formula
that pretends to give you the three Euler angles out of accelerometer
data can only be wrong. You need a magnetic compass to get the yaw
angle, otherwise you would have to rely solely on the gyros, which are
prone to long-term drift.

The formulas for updating angles from gyro data are awfully complex.
You don't want to do that. You want to instead keep track of you
attitude using quaternions, which give much nicer maths.

If you look at the formulas that update IMU_GyroRot*, you should
notice that they are prone to unbounded drift, which is then inherited
by angle*. Obviously, the author of these formulas completely missed
the point of a complementary filter.

I suggest you look at this old answer to a very similar question.

Thanks for your comment;
Since gyroscopes drift their Yaw measurement, does that mean I'd strichtly need to use a magnetometer to measure the Yaw?
As for the angle formulas, it does indeed appear that the author of the original article from 2013 may have missed a couple of things. I didn't actually know this, but the MPU6050 contains a Digital Motion Processor (DMP), that apparently handles a lot of the calculations for you. Using the i2cdev library from jrowberg, I was able to get some readings. Unfortunately, the Yaw still appears to drift, both in Euler and Quaternions...

@Runsva: Good that you found a way to get the DMP-computed rotation! Yes, you need a magnetometer to measure yaw, I do not know of any other easy way to get it. If you only have accelerometers and gyros, your only option is to calibrate the gyros as accurately as you can, and hope it is good enough to get an acceptable drift rate.

Make sure that the sensor is correctly orientated and calibrated, verify gyro scaling and range settings, and consider the application requirements when choosing between tilt angles and Euler angles. If Euler angles are necessary, you'll need to implement a different algorithm to calculate them accurately.


text:
Problem converting a sketch from SPIFFS to LittleFS - no matching function for call error
I'm playing with a tutorial from this DroneBot Workshop YouTube (excellent video presentation by the way on WiFi manager for newbies). I am working with a NodeMCU ESP8266.
The example code was written for SPIFFS. If I use the LittleFS library instead, and whether I define SPIFFS to LittleFS at the start or manually replace all references to SPIFFS with LittleFS, this line will not compile:
if (LittleFS.begin(false) || LittleFS.begin(true))

It gives this error message:
no matching function for call to 'fs::FS::begin(bool)'

Any suggestions as to what I'm missing or need to change?
His original example code which won't compile is below. I'm guessing I'm missing something simple but I'mnot sure what.
I probably should have added that I have commented out the include SPIFFS, added include LittleFS.H
I still have FS.h included in libraries and not sure if that is contributing to the issue. Is there an equivalent replacement for FS.h that comes about with LitteFS that I should be including?
/*
  WiFiManager with saved textboxes Demo
  wfm-text-save-demo.ino
  Saves data in JSON file on ESP32
  Uses SPIFFS

  DroneBot Workshop 2022
  https://dronebotworkshop.com

  Functions based upon sketch by Brian Lough
  https://github.com/witnessmenow/ESP32-WiFi-Manager-Examples
*/

#define ESP_DRD_USE_SPIFFS true

// Include Libraries

// WiFi Library
#include <WiFi.h>
// File System Library
#include <FS.h>
// SPI Flash Syetem Library
#include <SPIFFS.h>
// WiFiManager Library
#include <WiFiManager.h>
// Arduino JSON library
#include <ArduinoJson.h>

// JSON configuration file
#define JSON_CONFIG_FILE "/test_config.json"

// Flag for saving data
bool shouldSaveConfig = false;

// Variables to hold data from custom textboxes
char testString[50] = "test value";
int testNumber = 1234;

// Define WiFiManager Object
WiFiManager wm;

void saveConfigFile()
// Save Config in JSON format
{
  Serial.println(F("Saving configuration..."));

  // Create a JSON document
  StaticJsonDocument<512> json;
  json["testString"] = testString;
  json["testNumber"] = testNumber;

  // Open config file
  File configFile = SPIFFS.open(JSON_CONFIG_FILE, "w");
  if (!configFile)
  {
    // Error, file did not open
    Serial.println("failed to open config file for writing");
  }

  // Serialize JSON data to write to file
  serializeJsonPretty(json, Serial);
  if (serializeJson(json, configFile) == 0)
  {
    // Error writing file
    Serial.println(F("Failed to write to file"));
  }
  // Close file
  configFile.close();
}

bool loadConfigFile()
// Load existing configuration file
{
  // Uncomment if we need to format filesystem
  // SPIFFS.format();

  // Read configuration from FS json
  Serial.println("Mounting File System...");

  // May need to make it begin(true) first time you are using SPIFFS
  if (SPIFFS.begin(false) || SPIFFS.begin(true))
  {
    Serial.println("mounted file system");
    if (SPIFFS.exists(JSON_CONFIG_FILE))
    {
      // The file exists, reading and loading
      Serial.println("reading config file");
      File configFile = SPIFFS.open(JSON_CONFIG_FILE, "r");
      if (configFile)
      {
        Serial.println("Opened configuration file");
        StaticJsonDocument<512> json;
        DeserializationError error = deserializeJson(json, configFile);
        serializeJsonPretty(json, Serial);
        if (!error)
        {
          Serial.println("Parsing JSON");

          strcpy(testString, json["testString"]);
          testNumber = json["testNumber"].as<int>();

          return true;
        }
        else
        {
          // Error loading JSON data
          Serial.println("Failed to load json config");
        }
      }
    }
  }
  else
  {
    // Error mounting file system
    Serial.println("Failed to mount FS");
  }

  return false;
}

void saveConfigCallback()
// Callback notifying us of the need to save configuration
{
  Serial.println("Should save config");
  shouldSaveConfig = true;
}

void configModeCallback(WiFiManager *myWiFiManager)
// Called when config mode launched
{
  Serial.println("Entered Configuration Mode");

  Serial.print("Config SSID: ");
  Serial.println(myWiFiManager->getConfigPortalSSID());

  Serial.print("Config IP Address: ");
  Serial.println(WiFi.softAPIP());
}

void setup()
{
  // Change to true when testing to force configuration every time we run
  bool forceConfig = false;

  bool spiffsSetup = loadConfigFile();
  if (!spiffsSetup)
  {
    Serial.println(F("Forcing config mode as there is no saved config"));
    forceConfig = true;
  }

  // Explicitly set WiFi mode
  WiFi.mode(WIFI_STA);

  // Setup Serial monitor
  Serial.begin(115200);
  delay(10);

  // Reset settings (only for development)
  wm.resetSettings();

  // Set config save notify callback
  wm.setSaveConfigCallback(saveConfigCallback);

  // Set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode
  wm.setAPCallback(configModeCallback);

  // Custom elements

  // Text box (String) - 50 characters maximum
  WiFiManagerParameter custom_text_box("key_text", "Enter your string here", testString, 50);

  // Need to convert numerical input to string to display the default value.
  char convertedValue[6];
  sprintf(convertedValue, "%d", testNumber);

  // Text box (Number) - 7 characters maximum
  WiFiManagerParameter custom_text_box_num("key_num", "Enter your number here", convertedValue, 7);

  // Add all defined parameters
  wm.addParameter(&custom_text_box);
  wm.addParameter(&custom_text_box_num);

  if (forceConfig)
    // Run if we need a configuration
  {
    if (!wm.startConfigPortal("NEWTEST_AP", "password"))
    {
      Serial.println("failed to connect and hit timeout");
      delay(3000);
      //reset and try again, or maybe put it to deep sleep
      ESP.restart();
      delay(5000);
    }
  }
  else
  {
    if (!wm.autoConnect("NEWTEST_AP", "password"))
    {
      Serial.println("failed to connect and hit timeout");
      delay(3000);
      // if we still have not connected restart and try all over again
      ESP.restart();
      delay(5000);
    }
  }

  // If we get here, we are connected to the WiFi

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  // Lets deal with the user config values

  // Copy the string value
  strncpy(testString, custom_text_box.getValue(), sizeof(testString));
  Serial.print("testString: ");
  Serial.println(testString);

  //Convert the number value
  testNumber = atoi(custom_text_box_num.getValue());
  Serial.print("testNumber: ");
  Serial.println(testNumber);

  // Save the custom parameters to FS
  if (shouldSaveConfig)
  {
    saveConfigFile();
  }
}

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

have you looked at LittleFS example code?

The LittleFS library shows the begin function with some other parameters. That is probably, why the compiler complains about not knowing that function. There is no begin method in LittleFS with just one boolean as parameter. Please try calling the begin function like in the libraries examples

I encountered the same issue. I made the following changes to the code.

Commented out this line:

  //x  if (SPIFFS.begin(false) || SPIFFS.begin(true))

Replaced the commented out line with this line:

  SPIFFS.begin();

Then commented out the "else" portion of the code in that block:

  //x  else
  //x  {
  //x    // Error mounting file system
  //x    Serial.println("Failed to mount FS");
  //x  }

So basically you eliminate the true/false test and always execute the code, not really sure why you would not want execute the code anyway.
Note:
I also used LittleFS to make it simple so I used the following include and define:
#include "LittleFS"
#define SPIFFS LittleFS

One final thing, I ran this on an ESP8266 mini D1 clone so I also changed the
#include <WiFi.h>

To
#include <ESP8266WiFi.h>


text:
Unable to connect to SHT4x sensor probe through I2C bus
Error trying to execute serialNumber(): ReceK on transmit of address
Error trying to execute serialNumber(): Received NACK on transmit of address
Error trying to execute measureHighPrecision(): Received NACz��trnsmit of ad���Error trying to execute serialNumber(): Received NACK on transmit of address
Error trying to execute measureHighPrecision(): Received NACK on transmit of address
Error trying to execute measureHighPrecision(): Received NACK on transmit of address

This is the error I receive when I try to connect my probe to my Arduino Uno.
I have soldered jumper wires to my probe to use with my microcontroller. The humidity probe is an SHT40 Sensirion probe. The code is the example usage code you find when you install the Sensirion SHT4x library.
 /*
 * Copyright (c) 2021, Sensirion AG
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * * Neither the name of Sensirion AG nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <Arduino.h>
#include <SensirionI2CSht4x.h>
#include <Wire.h>

SensirionI2CSht4x sht4x;

void setup() {

    Serial.begin(115200);
    while (!Serial) {
        delay(100);
    }

    Wire.begin();

    uint16_t error;
    char errorMessage[256];

    sht4x.begin(Wire);

    uint32_t serialNumber;
    error = sht4x.serialNumber(serialNumber);
    if (error) {
        Serial.print("Error trying to execute serialNumber(): ");
        errorToString(error, errorMessage, 256);
        Serial.println(errorMessage);
    } else {
        Serial.print("Serial Number: ");
        Serial.println(serialNumber);
    }
}

void loop() {
    uint16_t error;
    char errorMessage[256];

    delay(1000);

    float temperature;
    float humidity;
    error = sht4x.measureHighPrecision(temperature, humidity);
    if (error) {
        Serial.print("Error trying to execute measureHighPrecision(): ");
        errorToString(error, errorMessage, 256);
        Serial.println(errorMessage);
    } else {
        Serial.print("Temperature:");
        Serial.print(temperature);
        Serial.print("\t");
        Serial.print("Humidity:");
        Serial.println(humidity);
    }
}

The soldered wires move a bit, but they are all still in contact and strongly intact.

Have you tried the I2C Scanner sketch? That can show, if there is at least a device found on the bus (and its address)

Do you have the requisite pull-up resistors for your I2C bus?  The Arduinos internal pull-ups aren't strong enough.


text:
Increase in power consumption after brown-out detection (BOD)
I'm working on a low-power energy harvesting project, where I'm considering using an ATtiny85 to perform some minor tasks. The ATtiny is put in Power Down mode most of the time and does not consume much power in this mode.
Since the power source is unstable, and/or could be absent from time to time, I've been enabling the internal brown-out detection (BOD) by setting the fuses. In this way, the ATtiny is reset when the voltage gets too low. This is to ensure that the microcontroller starts working properly again when sufficient power returns. This also seems to work, so that the chip starts running again when the voltage is above a certain threshold.
However, when the voltage drops below the BOD level, I notice a considerably larger power surge through the ATtiny, even when all peripherals are disconnected. It seems to me that some sort of gate is opened inside the chip when the BOD fires, and the current is limited by some sort of internal resistance. When the voltage increases somewhat above the BOD level, the large power surge stops.
I've been searching through the documentation/datasheet and forums online to find out why this happens but can't seem to find some sort of explanation or ways to prevent this from happening. Since this is a low-power energy harvesting project, it is important that the internal protection from low voltages does not contribute to the problem it detects.
Any useful input would be appreciated.

When the Vcc level is below the BOD activation voltage, the chip is held in a reset state...

...which uses significantly more current than the chip does in sleep state...

You are probably better off disabling the BOD and instead using an external Voltage Supervisor chip to turn the power on to the ATTINY when there is sufficient voltage and turn it off when there is not. There are many of these chips and they can use less than a microwatt when quiescent.

Thank you for replying. The graph seems to offer some explanation to the matter. However, I'm observing ten times the current consumption, running at 1 MHz and BOD level at 4.3 V. According to the graph that should give a current consumption starting at ~0.1 mA? I'm observing >1 mA.
As you write, I might be better off disabeling the BOD and using an external supervisor, but I'm stil wondering if there is anything I could do to reach the 0.1 mA level.

Are you testing the ATTINY in isolation or in your circuit? If you are testing in circuit, I'd bet the additional drain is coming from other components and possibly the way they are reacting to the floating outputs on the ATTINY. Better to test the ATTINY alone, connected only to a variable power supply. Start at a voltage above the BOD threshold and slowly lower the voltage to below the threshold and watch what happens to the current. My guess is that it will match the chart above.

I've been testing in isolation, as you described. I found some useful information in section 10.2.6 "Unconnected Pins" in the datasheet: "... the [internal] pull-up will be disabled during reset. If low power consumption during reset is important, it is recommended to use an external pull-up or pull-down."
I've tested only a little with 1 MΩ external pull-up resistors, which seemed to bring the current consumption further down. Still not quite matching the chart yet. I haven't progressed further with testing, but it seems this might be at least part of the issue."

The chart in section 22.11 also states that it's "Excluding Current Through The Reset Pull-up". So there's also that. :)

Did some more testing now. External pull-up resistors on all floating pins. Current consumption down to ~0.22 mA right after BOD. Still a lot compared to ~26 µA in Power Down mode, but I guess that's more what is to be expected with BOD level at 2.7 V and taking into account an internal Reset Pull-up Resistor rated at 30-60 kΩ (according to "21.2 DC Characteristics" in the datasheet). Worst case that should give a current leak of ~90 µA + ~60 µA ≈ 0.15 mA. I guess this is as far as I get without an external Voltage Supervisor. :)


text:
Code review for timer using RTC and OLED screen
I am building a small art project to display my current age with an accuracy of 1/100th of a second. I am using a XIAO SAMD21, a DS3231 RTC, and a 128x32 OLED screen. Here is what it looks like right now without the battery:

My aim is to fit this and a battery into a locket / necklace. I want to make as low-power as possible so that it can last at least an hour or two on a 75 mAh Li-po. I can't use a bigger battery since it wouldn't fit in the necklace.
I wrote the code to the best of my ability and it looks like it works really well. I just want a sanity check to make sure there isn't a simpler way of doing things. In particular I feel like the calculation of the age in the main loop, the syncing with RTC, and maybe the display updates, could be done in a better way. Maybe there are some things I do with interrupts and the 'alarms' in the RTC? Just power on the display every other second maybe. I am also considering using an epaper display and removing the power LED.
The code is attached here. I use the Adafruit libraries to drive the SSD1306 on the OLED screen, and one of the DS3231 libraries to interface with the RTC. Parts of it are adapted from examples, so there may be some extraneous imports or declarations I don't need.
// TUNIO 2024
// Age Pendant

// TO DO:
// current loop is 17 to 18 milliseconds long - need less than 5 for accurate centi-second counting

// Libraries
#include <SPI.h>
#include <Wire.h>
#include <DS3231.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// OLED Setup ~ copied from example
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C // See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// RTC Setup
RTClib myRTC;

// Initializations for periodic sync with RTC
uint32_t remote_time = 0;
uint32_t sync_interval_ms = 1800000; // sync with RTC every sync_interval_ms milliseconds // about an hour is good
uint32_t last_millis_synced = 0; // the last time we synced with RTC
uint32_t system_time = 0; // the local system time

// Initializations for age calcs
// QUESTION us 32 bit enough to store the age of someone? What if they live to 100?
uint32_t born_utime = 788888888; // date of birth in unixtime // 788888888
uint32_t total_age_secs = 0;
uint32_t sec_remainder = 0;
uint8_t age_years = 0;
uint8_t age_months = 0;
uint8_t age_days = 0;
uint8_t age_hours = 0;
uint8_t age_mins = 0;
uint8_t age_secs = 0;

// initializations for centi-second counting
uint8_t oldsec = -1;
uint8_t newsec = -1;
uint32_t offset = 0;
uint8_t age_cs = 0;

// screen saving vars
bool invert = false;

//// debug
//uint32_t start_millis=0;
//uint32_t end_millis=0;

void setup() {
  Serial.begin(57600);
  Wire.begin();
  delay(250);

  // display setup
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }
  display.dim(true);
  display.setTextColor(SSD1306_WHITE);
  display.clearDisplay();
  display.setTextSize(2); // 1 default
  display.setRotation(3); //0 default, 1, 2, 3

  // turn off built in LED
  pinMode(LED_BUILTIN , OUTPUT);
  digitalWrite(LED_BUILTIN , HIGH);

  // do first sync
  sync_time_with_rtc();
}

void loop() {
//  //debug
//  start_millis = millis();

  // sync every sync_interval_ms with RTC
  if (millis() - last_millis_synced >= sync_interval_ms) {
    sync_time_with_rtc();
  }

  // Calculate time elapsed since birth in years, months, etc.
  system_time = local_time_now();
  total_age_secs = system_time - born_utime; // age in seconds
  age_years = num_time_units(total_age_secs, 31558149.756); // second arg is num of: secs in a year
  age_months = num_time_units(sec_remainder, 2629745.568); // ... secs in a month
  age_days = num_time_units(sec_remainder, 86401.505); // ... secs in day
  age_hours = num_time_units(sec_remainder, 3600); // ... in an hour
  age_mins = num_time_units(sec_remainder, 60); // ... in an minute
  age_secs = sec_remainder;

  // display the age calculated
  show_age_on_display(5, 3); // input top left coordinates of where the age will be displayed

//  //debug
//  end_millis = millis();
//  Serial.println(end_millis - start_millis,DEC);
}

// Prints the provided age to the LCD with the correct formatting
void show_age_on_display(int col, int line) {
  newsec = age_secs;
  if (newsec != oldsec) {
    offset = -1 * (millis() % 1000);
    if (age_secs % 11 == 0) {invert = ! invert;} // invert display to save pixels burning every 11 secs
    oldsec = age_secs;
  }

  display.clearDisplay();
  display_at_location(age_years, col, line);
  display_at_location(age_months, col, line + (13 + 5) * 1);
  display_at_location(age_days, col, line + (13 + 5) * 2);
  display_at_location(age_hours, col, line + (13 + 5) * 3);
  display_at_location(age_mins, col, line + (13 + 5) * 4);
  display_at_location(age_secs, col, line + (13 + 5) * 5);
  age_cs = floor(((millis() + offset) % 1000) / 10);
  display_at_location(age_cs, col, line + (13 + 5) * 6);

  display.fillRect(0, display.height() - 18, display.width(), 18 - ((18 * age_cs) / 100), SSD1306_INVERSE); // progress bar completes every second

  display.invertDisplay(invert);
  display.display();
}

// display integer value <100 at given location with "0" padding
void display_at_location(uint8_t value, uint8_t this_col, uint8_t this_line){
  display.setCursor(this_col, this_line);
  if (value < 10) display.print(F("0"));
  display.print(value, DEC);
}

// input seconds and returns number of whole time unit, sets remainder variable
uint32_t num_time_units( uint32_t secs, float time_unit) {
  int num_units = floor(secs / time_unit);
  sec_remainder = secs - round(num_units * time_unit);
  return num_units;
}

// syncs time with the RTC: call on sync_interval, power ons, AND when wake from sleep
void sync_time_with_rtc() {
  digitalWrite(LED_BUILTIN , LOW); // briefly flash the LED every sync with the RTC
  remote_time = myRTC.now().unixtime();
  last_millis_synced = millis();
  system_time = local_time_now();
  digitalWrite(LED_BUILTIN , HIGH);
}

// fetches the unixtime according to Arduino
uint32_t local_time_now() {
  return remote_time + floor((millis() - last_millis_synced) / 1000);
}

use a function to replace repeating code

One thing I discovered: millis() will roll over every ~49 days if for some reason the Arduino doesn't have a power cycle. So I follow this and update the code https://arduino.stackexchange.com/questions/12587/how-can-i-handle-the-millis-rollover

I see quite a bit of floating point computations here. Since the SAMD21
doesn't have a floating point unit, all float operations are implemented
in software, which can be quite expensive. As an optimization, I suggest
to stay as much as possible in the integer realm. For example:
uint32_t total_minutes = total_age_secs / 60;
age_secs = total_seconds - total_minutes * 60;
uint32_t total_hours = total_minutes / 60;
age_mins = total_minutes - total_hours * 60;
uint16_t total_days = total_hours / 24;
age_hours = total_hours - total_days * 24;
age_years = total_days / 365;
uint16_t remaining_days = total_days - age_years * 365;
age_months = remaining_days * 12 / 365;
age_days = remaining_days - age_months * 365 / 12;

Note that there is some rounding here: a day is assumed to be exactly
86400 seconds instead of 86399.9999 (I don't know where you found the
number 86401.505), a year is assumed to be 365 days, and all months are
assumed to be equal. If you found this approximations too rough (mostly
the year), you may use 365.25 = 1461 / 4 days per year and
1461 / 48 days per month. You can do this by replacing the last four
lines with:
age_years = total_days * 4 / 1461;
uint16_t remaining_days = total_days - age_years * 1461 / 4;
age_months = remaining_days * 48 / 1461;
age_days = remaining_days - age_months * 1461 / 48;

I'm almost done updating the code, you may be interested to see it. I am removing all floating point operations and attempting to max out the resolution using only 32 bit integers and a few correction factors.
I think I got the "86401.505" by naively dividing the length of sidereal year in seconds by 365.25 days, I fix that in the next version. I got a bit confused with the several different definitions of a year I guess.


text:
Why do I get different times when using analogRead() inside while loop?
I have the following code which checks the latency of another board.
    int triggerPin = 13;
    int dataPin = 9;
    int ejectorPin = A0;
    unsigned long t_start = 0;
    unsigned long t_end = 0;
    unsigned long t_total = 0;
    int value = 0;

    void setup() {
      // put your setup code here, to run once:
      pinMode(triggerPin, OUTPUT);
      pinMode(dataPin, OUTPUT);
      pinMode(ejectorPin, INPUT);
      Serial.begin(9600);
    }

    void loop() {
      t_start = micros();
      while (value < 10 ) {
        digitalWrite(triggerPin, HIGH);
        digitalWrite(dataPin, HIGH);
        delay(5.0);
        digitalWrite(dataPin, LOW);
        digitalWrite(triggerPin, LOW);
        delay(1.0);
        value = analogRead(ejectorPin);
      }
      t_end = micros();

      t_total = (t_end - t_start);
      Serial.println(double(t_total) / 1000);

Note that I'm using analogRead() inside the while loop. With this method I get 18.3 msec. However, if I use the analogRead() in the while condition:
    void loop() {
      t_start = micros();
      while (analogRead() < 10 ) {
        .
        .
        .

then I get 30.2 msec. I thought assigning value of analogRead() to a variable would take longer but here it's the opposite.
Can someone please explain the reason behind this behaviour?

What voltage are you supplying to A0? Is it consistent between runs of the program? How consistent are the printed values across loop iterations?

Your delays will be completely hiding any variance in the analog read timing. Your supposed results are meaningless to us.

@EdgarBonet As far I can tell the both the input voltage and the printed values are pretty consistent.

@Majenko I just had an experience colleague tell me the same thing. We're now using a two channel oscilloscope to visually check the time difference.

@Majenko But nonetheless, just moving analogRead() shouldn't introduce 12 msec difference.

@Farahi It won't be the analogRead. It'll be whatever is "triggering" the analogRead. The analogRead is insignificant in the scale of things.

@Majenko But the same thing which is triggering the analogRead inside the loop is also triggering the analogRead when its in the while condition.

And is the timing of that "same thing" absolutely precisely the same, or could your delays be affecting how your sampling happens? Remember: you will only ever be taking a single sample every 6 milliseconds or so whichever method you're using. Does that slow sample frequency even make sense for what you're sampling?

@Majenko I let both methods run for over 40 mins. The results were pretty much as I mentioned in the post.

@Farahi So? With a 6ms granularity of sampling you have an accuracy of ±6ms, or "within 12 ms of reality". Oh look...  30-18 is 12...  What a surprise...

@Majenko There's no need for passive aggressiveness. I'm new to all this so my questions may come across as dumb.

Both of your examples use a while loop, so the while loop is not the issue.
An analogue read, with the prescalers unchanged, takes 104 µs. So, what you are really measuring is your 6 ms delays, plus a slight amount extra for the other code.
Since your first while loop necessarily takes 6+ ms, then you will naturally get a result which is a multiple of 6 ms. This appears to be happening, so you are getting two loops (18 ms). This doesn't prove a huge amount.

You need to read up on the Nyquist frequency
To get accurate sampling results you need to sample at twice the rate at which things change. Your first results may merely be the results of aliasing. Your 6 ms delays may cause you to take one sample on one transition, and another sample (maybe) a couple of transitions later. Thus your results are meaningless.


text:
Arduino stopped working: avrdude: ser_open(): can't set com-state
I'm playing with my first Arduino device (Arduino Leonardo). It worked fine but at some point it failed. I'm getting this error:

avrdude: ser_open(): can't set com-state for "\.\COM6"
An error occurred while uploading the sketch

The error came out of nowhere because I didn't change the port or cable or anything. Everything seems to be in order: the port, the driver, the IDE, the cable. And everything worked just an hour ago.
1) I've tried to change the port
2) I've reinstalled IDE
3) I've tried different cable
What else can I do?
And another thing: after manual reset of Arduino (with button) device disappears.

The thing to remember with the Leonardo and other ATMega32U4 based boards is that there is no actual serial connection.
What there is, is a USB connection which is controlled by the sketch (and independently by the bootloader) to provide a "CDC/ACM" connection over USB.  This emulates a serial connection, but it's not a real serial connection.
This actually has a huge number of benefits, because you can be other things besides a serial port, such as a keyboard or a mouse. However, it comes at a cost:  the serial port is at the mercy of the sketch that's running at the time.
If your sketch crashes for any reason then the serial port can no longer be used. That's bad. It can cripple your Arduino. Since it's the sketch that is providing the driving force for the CDC/ACM serial emulation, if that sketch dies, so does the control of the USB and thus the CDC/ACM.
So while the port may be created initially by the sketch, if it then subsequently crashes the port is still there, but unresponsive.  Or the port can vanish completely.
So how do you fix it?  Well, there's a couple of strategies:

Some people have had success by pressing the RESET button twice in quick succession. This depends on the version of the bootloader in use though, and it's not something I have ever tried.
Pressing RESET at just the right moment to get the bootloader to run just before avrdude runs and catch it at the right time to accept a new sketch, or
Using a hardware programmer (e.g., USBASP) or another Arduino to wipe the chip and reinstall the bootloader

My preferred method is 3, since it is certain to always work - however it requires either a hardware programmer or another Arduino. However you can pick up a USBASP on eBay / AliExpress / Amazon etc for next to nothing, and when you're working with AVR chips they're always good to have to get you out of tight spots like this.

thanks a lot. That make total sense.


text:
How to compose an HTTP GET request URL with key/value parameters
I am experimenting with some code running on an ESP8266 board to retrieve data using a web API. I would like to store the host address and key/value parameters (API key etc.) of the GET request as constants/variables (I'm not sure which is better) and then use them to compose the full GET URL.
How can I compose the full URL from separate strings/char arrays including the correct syntax for the key/values pairs?
EDIT: Just adding that I am using the ESP8266HTTPClient library.
The example I have been following uses a basic API URL with no parameters and stores the host URL as follows:
const char* host = "http://somehost.com/dir/1";

(Side question: please explain the difference between const char* host and const char *host if there is one)
Using this simple URL I can successfully retrieve the JSON data using this method:
HTTPClient http;
http.begin(host);
int httpCode = http.GET();
Serial.print("HTTP RESPONSE: ");
Serial.println(httpCode);
if (httpCode > 0) {
  String payload = http.getString();
  Serial.println("PAYLOAD:");
  Serial.println(payload);
}
http.end()

I am looking into using the "ArduinoJson" library to manage the json data instead of String, but am more interested in figuring out how to compose the URL at the moment.
What I would like to achieve is adding key/value parameters stored as variables to the host URL e.g.:
const char* host = "http://somehost.com/dir/1";
char* app = "123";
char* user = "123456"
char* api_key = "XXXXXXXXXXXXX";

And then join them with strings or char arrays to create the full URL, or simply pass the host address plus the parameter values to a function that composes the URL or sends the full GET request(with the parameter "key=var", question mark, and ampersands etc.):
http://somehost.com/dir/1/?appid=123&userid=123456&key=XXXXXXXXXXXXX

This was very easy to achieve in python using the "requests" HTTP library. I was able to store the key/value parameters as a dict and then pass the host address and the parameter dict to the requests.get function and it would compose the URL automatically.
I guess there is more than one question buried in there, but the main one is "what is the best way to compose the full URL without hard coding the whole thing?" An example would be so I could change some parameters such as appid by user input before making the GET request.
I am unsure if I am using the right approach using the character arrays, constants or variables, whether I am using the right approach by trying to compose it manually, and in general what the best practices are for doing this efficiently and avoiding memory fragmentation (which is a problem when using string variables?). This device will be required to run constantly and periodically make these GET requests.

Side question: please explain the difference between const char* host and const char *host if there is one

There is no difference; n.b. the arduino IDE uses C++! If you don't know C or C++ you should learn that first.

"what is the best way to compose the full URL without hard coding the whole thing?"

This is basically the same question as how do you manipulate, i.e. compose, composite, concatenate, C strings. c string functions
here is a quick example, without error checking, etc.:
const char* host = "http://somehost.com/dir/1";
char* app = "123";
char* user = "123456"
char* api_key = "XXXXXXXXXXXXX";

char urlout[255];

// we are going to start here
strcpy(urlout, host);
strcat(urlout, "/?appid=");
strcat(urlout, app);
strcat(urlout, "&userid=");
strcat(urlout, user);
strcat(urlout, "&key=");
strcat(urlout, api_key);

// urlout == "http://somehost.com/dir/1/?appid=123&userid=123456&key=XXXXXXXXXXXXX"

Thank you, your solution is what I was looking for. However I don't know if "learn c++ first" was very constructive. Arduino is meant to be standalone, for education, and is many people's first intro into programming. I also just thought I would add in a link to an article that explained in depth and helped me understand about strings, character arrays, and managing memory usage effectively. The Evils of Arduino Strings

@justincs I think the idea that Arduino is meant to be standalone is problematic; the language used is C++, one needs to know enough C++ to use the Arduino, hiding that fact or pretending it doesn't matter/exist does a disservice to the users. It just makes things more confusing; there is simplification, and there is oversimplification! Users now have two problems: their original problem, and learning to program at the same time; this does more harm than good IMHO.


text:
Stepper Motors Strange Behaviour
I am working in a project in which I need to control at the same time three NEMA17 stepper motors. In order to do so, I am using three DRV8825 drivers working at 12V connected to an Arduino MEGA.
This Arduino is generating the pulses in velocity ramps so that we have an accelerated movement to reach the goal.
The schematic I am using for connecting the drivers is the one that the manufacturer recommends:

With a digital analyzer, I can see that my velocity ramp is being generated properly:

In this picture below you can see how steps (ST) are generated once the direction (DR) is set for each of the motors. The time waiting after the direction change is bigger than the necessary established by the manufacturer and also does the duration of the step pulses.
Following this, the motors are supposed to make an accelerated movement until reaching a certain position and then, decelerate and stop.
Although, I am facing the problem that, in some cases, one of the motors (not always the same one) makes a few steps in the opposite direction of the movement and, after that, it executes the expected movement. This leads to, even of making the three motors perform the same movement, one of them finishes differently.
I tried to change the drivers but the same happens. Also, as I said before, I have checked that the pulses are correctly generated.
I would like to know if anyone has faced a similar problem or knows any reason that could lead to this strange behavior.
Thanks.

/fault is an active low output

So, apparently the motors I am using have a optimal work range that doesn't start at 0 but 200PPS. Though, even generating properly the velocity ramps, when using a low acceleration, my motors would be running for some steps outside this optimal range, causing strange movements at the beginning of the movement.
In order to solve it, these non-optimal low velocities are avoided while accelerating so that motors enter directly to the optimal work area.


text:
LED series Resistor- Noob question
Can someone please explain to me, like I'm 5, why this circuit does not work?

Every resistance calculator I use says that there is not enough voltage to calculate a resistance. If I understand correctly, wouldn't the LEDs light but just at a lower brightness?
Using R = V/I, The source voltage is 5v, the LED voltage is 6 divided by the current of 20mA equals -50ohms. All of the charge is used up by the time it reaches the arduino right?

The simple reason is that LEDs are not light bulbs. An LED is not a passive device and does not follow Ohms law.
To a first approximation if the voltage across an LED is below the forward voltage then no current will flow. In that situation the voltage across the LED pins is whatever the supply voltage is.
If the voltage across an LED is over the forward voltage then an unlimited current can flow and the voltage between the pins is fixed at the forward voltage.
This approximation isn't perfect but 90% of the time it's good enough.
So with 1 LED and no resistor you get 3V over the LED and then 2V left over with zero resistance, I=V/R = 2/0 = infinite current flow. The LED is dissipating 3*infinity watts of energy and instantly vaporizes. Clearly this isn't exactly what happens in the real world but the result is enough to tell you that bad things will happen.
With 1 LED and a 200 ohm resistor you get 3V over the LED and then 2V extra with 200 ohms resistance, I=V/R = 2/200 = 10mA. The LED is within its operating current and will light up.
With 2 LEDs and no resistor you get 3V on one LED and 2 V on the second (or 2.5 on both if you prefer). Either one or both LEDs are below their forward voltage and so no current flows. The LEDs remain off.

The two LEDs in series have a forward voltage of 6v which is more than the Arduino's supply voltage.
Forward voltage is the bare minimum amount of voltage required for the LEDs to start conducting electricity (ie: to allow the current to pass through)
Read this: https://www.baldengineer.com/led-basics.html :

Forward Voltage
The Forward Voltage defines the amount of voltage
required in order to conduct electricity. Any voltages below this
amount will cause the LED to remain “Open” and non-conductive. This
also means any components in-series with the LED will not have current
flowing through them either! Once the voltage dropped across the LED
reaches the Forward Voltage, it will begin to conduct electricity. Not
only that, but the LED will only drop its Forward Voltage at any given
time.
For example, consider a LED with a Forward Voltage rated at 3.0V. Now
what happens if you attach the Anode to the Positive (+) Terminal of a
AA (LR-6) Battery and the Cathode to the Negative (-) Terminal? Will
the LED do anything? No! The AA (LR-6) Battery only has a nominal
voltage of 1.5V. Until you add a second battery, the LED will not
light up.

LEDs won't necessarily light at lower brightness (or conform to Ohm's law at all), it's explained here. If an appliance apparently does provide a "dim" LED mode, it's usually using a clocked signal (and blinking rapidly).

I understand, thank you for the link. If i run on this configuration, would it damage my LEDs or Arduino?

Probably not, as the other Andrew noted above, no current will flow.

Can someone please explain to

With the right leds, the circuit can work.
Where it may fail:

Two less with combined forward voltage greater than the one applied to them. The meds wouldnt light up or wouldn't light up brightly, depending on the leds used.
The two leds with combined forward voltage much less than the supply which has low output resistance. The two leds may light up very brightly, or so briefly ending up in led heaven permanently. If you can capture them in high frame rate code on the glow before their death is quite pretty.