Loop delay using millis()+ using millis() for smoothing+ 2 ESP32s using ESP-Now

  1. I am successfully transmitting 2 smoothed analog values between 2 esp32s using
    the esp now protocol.

  2. There is a delay I've created in the smoothing loop using millis() which I believe
    is working correctly. The delay is for reading stability between readings. As mentioned in example below:
    https://www.arduino.cc/en/Tutorial/Smoothing

  3. I am trying to create a delay in the loop on the both the transmitter side and
    receiver side since the values are printing really fast.

arduino-tutorial-using-millis-instead-of-delay/
I am using the delay using millis() example on the website mentioned above (it' s a non-blocking code example), but the delay is still transmitting values rapidly rather than holding them back every 3 seconds.

if (millis() > previousMillis + loopDelay) {
    previousMillis = millis();
  }

I have this code above inside the void loop and it is independent of the millis() code mentioned the 1st time. I am emulating the same example in the website mentioned above but it is not working. Any advice would be helpful. Thanks.

Transmit:

/*  Free and open source, CC BY-SA 4.0
    https://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf
    https://docs.espressif.com/projects/esp-idf/en/stable/api-reference/wifi/esp_now.html
    Modified code based on:
    https://www.instructables.com/id/ESP32-With-ESP-Now-Protocol/
    http://www.arduino.cc/en/Tutorial/Smoothing
*/

//ESP-Now power saving protocol
#include <esp_now.h>

#include <WiFi.h>

//ESP32 adc conversion
#include <driver/adc.h>

// Channel used for connection
#define CHANNEL 1

// Structure with information about the next peer
esp_now_peer_info_t peer;

// Define the number of samples to keep track of. The higher the number, the
// more the readings will be smoothed, but the slower the output will respond to
// the input. Using a constant rather than a normal variable lets us use this
// data to determine the size of the readings array.
const int numReadings = 64;
const uint8_t numSensors = 2;

uint32_t readings[numSensors][numReadings];   //multi-dimensional readings from analog input
uint32_t total[numSensors] = {0};    // the running total
uint32_t readIndex = 0;              // the index of the current reading
uint32_t average = 0;                // the average
uint8_t EspNowAverage = 0;

// delay to process smoothing readings
uint16_t numReadingsInterval = 1;
uint32_t previousMillis = 0;

//Earth rotates .25 degrees/minute. In 4 minutes Earth rotates 1 degree.
//Add a delay time if necessary to conserve power for solar cell or battery.
uint16_t loopDelay = 3000;

// Mac Address of the peer to which we will send the data
uint8_t peerMacAddress[] = {0x30, 0xAE, 0xA4, 0xF0, 0x54, 0xA0};

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

  // initialize all the readings to 0:
  for (uint16_t thisReading = 0; thisReading < numReadings; thisReading++) {
    for ( int j = 0; j < numSensors; j++)  readings[j][thisReading] = 0;
  }

  // Call the function that initializes the station mode
  modeStation();

  // Call function that initializes ESPNow
  InitESPNow();

  // Add the peer
  addPeer(peerMacAddress);

  // Registers the callback that will inform us about the status of the submission.
  // The function that will be executed is onDataSent and is stated below
  esp_now_register_send_cb(OnDataSent);
}

//loop function being used to smooth analog input values
// void OnDataSent function sends values over and over again
void loop() {
  // Voltage divider analog in pins
  adc1_config_width(ADC_WIDTH_12Bit);
  adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_DB_11); //Pin34
  adc1_config_width(ADC_WIDTH_12Bit);
  adc1_config_channel_atten(ADC1_CHANNEL_7, ADC_ATTEN_DB_11); //Pin35

  // millis() -->Returns the number of milliseconds passed since the Arduino board began running the current program.
  // This number will overflow (go back to zero), after approximately 50 days.
  // timing resets to 0 when millis() - previousMillis becomes greater than or equal to numReadingsInterval * numReadings
  // then loop proceeds with remaining functions
  if (millis() > previousMillis + loopDelay) {
    previousMillis = millis();
  }

  if ( millis() - previousMillis >= numReadingsInterval * numReadings ) {
    previousMillis = millis();

    // Read the sensor
    uint16_t Azimuth = adc1_get_raw(ADC1_CHANNEL_6);
    uint16_t Elevation = adc1_get_raw(ADC1_CHANNEL_7);

    uint16_t  inputPin[ numSensors ] = {Azimuth, Elevation};

    uint16_t ai;

    for (ai = 0; ai < numSensors ; ai++) {
      // subtract the last reading:
      total[ ai ] = total[ ai ] - readings[ai][readIndex];
      // read from the sensor:
      readings[ai][readIndex] = inputPin[ai];
      // add the reading to the total:
      total[ai] = total[ai] + readings[ai][readIndex];
      // calculate the average:
      average = total[ai] / numReadings;
      // reduce results to 0-255
      EspNowAverage = average / 16; // send smoothed average of each sensor input to receiver
      readAndSend();
    }

    // advance to the next position in the array:
    readIndex = readIndex + 1;
    // if we're at the end of the array...
    if (readIndex >= numReadings) {
      // ...wrap around to the beginning:
      readIndex = 0;
    }
  }
}


// Function responsible for pin reading and sending of data to the peer
void readAndSend() {
  // Read the data of the pin
  uint8_t data = EspNowAverage;
  // Send the data to the peer
  send(&data, peerMacAddress);
}

// Function that serves as a callback to warn us about the sending situation we made
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Success" : "Fail");
}

// Function to initialize the station mode
void modeStation() {
  // We put the ESP in station mode
  WiFi.mode(WIFI_STA);
  // We show on Serial Monitor the Mac Address
  // of this ESP when in station mode
  Serial.print("Mac Address in Station: ");
  Serial.println(WiFi.macAddress());
}

// ESPNow startup function
void InitESPNow() {
  // If the initialization was successful
  if (esp_now_init() == ESP_OK) {
    Serial.println("ESPNow Init Success");
  }
  // If initialization failed
  else {
    Serial.println("ESPNow Init Failed");
    ESP.restart();
  }
}

// Function that adds a new peer through your MAC address
void addPeer(uint8_t *peerMacAddress) {
  // We inform the channel
  peer.channel = CHANNEL;
  // 0 not to use encryption or 1 to use
  peer.encrypt = 0;
  // Copy array address to structure
  memcpy(peer.peer_addr, peerMacAddress, 6);
  // Add slave
  esp_now_add_peer(&peer);
}

// Function that will send the data to the peer that has the specified mac address
void send(const uint8_t *data, uint8_t *peerMacAddress) {
  esp_err_t result = esp_now_send(peerMacAddress, data, sizeof(data));
}

The 9000 character limit was reached.
Here is code for receiver side.

I hope the instant transmission is not an issue due to OnDataSent function and espressif API.

/*  Free and open source, CC BY-SA 4.0
    https://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf
    https://docs.espressif.com/projects/esp-idf/en/stable/api-reference/wifi/esp_now.html
    Modified code based on:
    http://www.esploradores.com/practica-6-conexion-esp-now/
    http://www.arduino.cc/en/Tutorial/Smoothing
*/

//Libraries espnow and wifi
#include <esp_now.h>
#include <WiFi.h>

// Channel used for connection
#define CHANNEL 1

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

  // Call the function that initializes the station mode
  modeStation();

  // Call function that initializes ESPNow
  InitESPNow();

  // Registers the callback that will inform us that we receive data. The function to be executed is onDataRecv and is declared below
  esp_now_register_recv_cb(onDataRecv);

  // Registers the callback that will inform us
  // about the status of the submission.
  // The function to be executed
  // is onDataSent and is declared below
  esp_now_register_send_cb(onDataSent);
}

// We do not need to do anything in the loop. we send the data as soon as we get from the other esp by the callback
void loop() {
}

// Function that serves as a callback to warn us we received data
void onDataRecv(const uint8_t *mac_addr, const uint8_t *data, int len) {
  // Place the received data at the output of the pin
  Serial.println(*data);
}

// Function that serves as a callback to warn us about the sending situation we made
void onDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Success" : "Fail");
}


// Function to initialize the station mode
void modeStation() {
  // We put the ESP in station mode
  WiFi.mode(WIFI_STA);
  // We show on Serial Monitor the Mac Address
  // of this ESP when in station mode
  Serial.print("Mac Address in Station: ");
  Serial.println(WiFi.macAddress());
}

// ESPNow startup function
void InitESPNow() {
  // If the initialization was successful
  if (esp_now_init() == ESP_OK) {
    Serial.println("ESPNow Init Success");
  }
  // If initialization failed
  else {
    Serial.println("ESPNow Init Failed");
    ESP.restart();
  }
}

That only works if you actually do the task IN that if :wink:

Also, always use millis() like:

if(millis() - previousMillis >= Interval)

Not as:

if(millis() > previousMillis + Interval)

Although the logic seems the same, the first will work flawless when millis() overflows, the last does not.

Thanks, I'll take that approach next.
The person on the site did mention your solution:
https://www.norwegiancreations.com/2018/10/arduino-tutorial-avoiding-the-overflow-issue-when-using-millis-and-micros/

I did attempt to nest the the second if statement inside of this:

if (millis() > previousMillis + loopDelay) {
    previousMillis = millis();

The weird thing that happened was I didn't get a serial readout on both the transmit side and receive side.

My loopDelay time is 3000 milliseconds.

I read on the Arduino site that 1 analog input takes about 100 microseconds (.1 milliseconds) to read.

If I take 64 readings with a 1ms interval for stability that's 64 milliseconds.
For 2 sensors thats ~ 128 milliseconds.

So I should I have sufficient time for the loopDelay to work, but it's not.
Am I not allowing the first if statement to initiate it's time due to initiation of the 2nd if statement and is it restarting the time back to 0, and therefore preventing the first if statement from reaching a 3000 millisecond value?

That's because you have one variable 'previousMillis' you use for both "delays".

What is the purpose of the second if/delay?

Maybe my understanding of previousMillis is flawed.
previousMillis = millis() resets timing back to 0?

I thought my different variables are:

First if statement:

  1. loopDelay
    To delay overall loop results in serial print monitor so I can keep track of / observe results easily.

Second nested? if statement:
2. numReadingsInterval
Delay to stabilize analog input smoothing readings

knightridar:
previousMillis = millis() resets timing back to 0?

No, it just gives you a new reference. Compare it to remembering it's now half pasted 11. If you remember that, you know when you want to do something if that's 30 minutes from now.

knightridar:
First if statement:

  1. loopDelay
    To delay overall loop results in serial print monitor so I can keep track of / observe results easily.

First of all, you don't want to delay the loop() ever. That's the whole reason of not using delay(). You just don't want to do all the stuff every loop. Which makes 'loopDelay' a stupid name :wink: 'SerialInterval' is more appropriate.

knightridar:
Second nested? if statement:
2. numReadingsInterval
Delay to stabilize analog input smoothing readings

Then split it. Aka, do the serial printing in 1 and the reading in 2. But they become two separate tasks with separate intervals. And thus you need to remember two times! (which makes 'previousMillis' a stupid name :wink: )

Okay, I've created separate variables for the two different instances.
This kind of helped to clarify things:
https://forum.arduino.cc/index.php?topic=42495.0

 // millis() returns the number of milliseconds passed since the microprocessor was started and began running the current program.
  if(millis() - SerialPrintStart >= SerialPrintInterval)
  {
    SerialPrintStart = millis();
  
    if ( millis() - numReadingsStart >= numReadingsInterval * numReadings ) {
      numReadingsStart = millis();

The second timing interval and if statement are nested in the larger timing interval if statment. Will see what serial print results are later after uploading new code to ESP32.

/*  Free and open source, CC BY-SA 4.0
    https://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf
    https://docs.espressif.com/projects/esp-idf/en/stable/api-reference/wifi/esp_now.html
    Modified code based on:
    https://www.instructables.com/id/ESP32-With-ESP-Now-Protocol/
    http://www.arduino.cc/en/Tutorial/Smoothing
*/

//ESP-Now power saving protocol
#include <esp_now.h>

#include <WiFi.h>

// ESP32 adc conversion
#include <driver/adc.h>

// Channel used for connection
#define CHANNEL 1

// Structure with information about the next peer
esp_now_peer_info_t peer;

// Define the number of samples to keep track of. The higher the number, the
// more the readings will be smoothed, but the slower the output will respond to
// the input. Using a constant rather than a normal variable lets us use this
// data to determine the size of the readings array.
const int numReadings = 64;
const uint8_t numSensors = 2;

uint32_t readings[numSensors][numReadings];   // multi-dimensional readings from analog input
uint32_t total[numSensors] = {0};    // the running total
uint32_t readIndex = 0;              // the index of the current reading
uint32_t average = 0;                // the average
uint8_t EspNowAverage = 0;

// interval to stabilize analog input smoothing readings
uint8_t numReadingsInterval = 1;
uint32_t numReadingsStart = 0;

// Earth rotates .25 degrees/minute. In 4 minutes Earth rotates 1 degree.
// Add a delay time if necessary to conserve power for solar cell or battery.
uint16_t SerialPrintInterval = 3000;
uint32_t SerialPrintStart = 0;

// Mac Address of the peer to which we will send the data
uint8_t peerMacAddress[] = {0x30, 0xAE, 0xA4, 0xF0, 0x54, 0xA0};

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

  // initialize all the readings to 0
  // multidimensional array takes into account multiple sensors and multiple readings for each sensor
  for (uint16_t thisReading = 0; thisReading < numReadings; thisReading++) {
    for ( int j = 0; j < numSensors; j++)  readings[j][thisReading] = 0;
  }

  // Call the function that initializes the station mode
  modeStation();

  // Call function that initializes ESPNow
  InitESPNow();

  // Add the peer
  addPeer(peerMacAddress);

  // Registers the callback that will inform us about the status of the submission.
  // The function that will be executed is onDataSent and is stated below
  esp_now_register_send_cb(OnDataSent);
}

//loop function being used to smooth analog input values
// void OnDataSent function sends values over and over again
void loop() {
  // Voltage divider analog in pins
  adc1_config_width(ADC_WIDTH_12Bit);
  adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_DB_11); //Pin34
  adc1_config_width(ADC_WIDTH_12Bit);
  adc1_config_channel_atten(ADC1_CHANNEL_7, ADC_ATTEN_DB_11); //Pin35

  // millis() returns the number of milliseconds passed since the microprocessor was started and began running the current program.
  if(millis() - SerialPrintStart >= SerialPrintInterval)
  {
    SerialPrintStart = millis();
  
    if ( millis() - numReadingsStart >= numReadingsInterval * numReadings ) {
      numReadingsStart = millis();

    // Read the sensor
    uint16_t Azimuth = adc1_get_raw(ADC1_CHANNEL_6);
    uint16_t Elevation = adc1_get_raw(ADC1_CHANNEL_7);

    uint16_t  inputPin[ numSensors ] = {Azimuth, Elevation};

    uint16_t ai;

    for (ai = 0; ai < numSensors ; ai++) {
      // subtract the last reading:
      total[ ai ] = total[ ai ] - readings[ai][readIndex];
      // read from the sensor:
      readings[ai][readIndex] = inputPin[ai];
      // add the reading to the total:
      total[ai] = total[ai] + readings[ai][readIndex];
      // calculate the average:
      average = total[ai] / numReadings;
      // reduce results to 0-255
      EspNowAverage = average / 16; // send smoothed average of each sensor input to receiver
      readAndSend();
    }

    // advance to the next position in the array:
    readIndex = readIndex + 1;
    // if we're at the end of the array...
    if (readIndex >= numReadings) {
      // ...wrap around to the beginning:
      readIndex = 0;
    }
  }
}
}

// Function responsible for pin reading and sending of data to the peer
void readAndSend() {
  // Read the data of the pin
  uint8_t data = EspNowAverage;
  // Send the data to the peer
  send(&data, peerMacAddress);
}

// Function that serves as a callback to warn us about the sending situation we made
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Success" : "Fail");
}

// Function to initialize the station mode
void modeStation() {
  // We put the ESP in station mode
  WiFi.mode(WIFI_STA);
  // We show on Serial Monitor the Mac Address
  // of this ESP when in station mode
  Serial.print("Mac Address in Station: ");
  Serial.println(WiFi.macAddress());
}

// ESPNow startup function
void InitESPNow() {
  // If the initialization was successful
  if (esp_now_init() == ESP_OK) {
    Serial.println("ESPNow Init Success");
  }
  // If initialization failed
  else {
    Serial.println("ESPNow Init Failed");
    ESP.restart();
  }
}

// Function that adds a new peer through your MAC address
void addPeer(uint8_t *peerMacAddress) {
  // We inform the channel
  peer.channel = CHANNEL;
  // 0 not to use encryption or 1 to use
  peer.encrypt = 0;
  // Copy array address to structure
  memcpy(peer.peer_addr, peerMacAddress, 6);
  // Add slave
  esp_now_add_peer(&peer);
}

// Function that will send the data to the peer that has the specified mac address
void send(const uint8_t *data, uint8_t *peerMacAddress) {
  esp_err_t result = esp_now_send(peerMacAddress, data, sizeof(data));
}

I'm getting the desired 3 second interval serial printout now on both the receiver side and transmitter side.

Although I don't understand why my phototransistor values and analog input results aren't refreshing faster. It's a gradual climb up versus faster results from before. Do I still need to split the serial interval such that it shouldn't nest around the smoothing if statement?

Transmit:

Success
Success
Success
Success
Success
Success
Success
Success
Success
Success
Success
Success
Success
Success

Receive:

6
62
6
66
7
69
7
72
7
75
8
79
8
82
9
85
9
88
9
91
10
95
10
98
11
101
11
104
11
108
12
111
12
114
12
117
13
120
13
124
13
127
14
130
14
133
14
136
15
140
15
143
15
146
15
149
16
152
16
155
17
159
17
162
17
166
17
170
17
172
17
172
17
173
17
175
17
175

knightridar:
The second timing interval and if statement are nested in the larger timing interval if statment.

Why? Don't! You have two individual tasks! Reading the ADC / averaging and printing values to Serial.

Only if you want to "print every x readings to serial" the two are linked. But then you don't want to time the Serial print but simply count to x.

I thought so too that I should keep it separate.
I am having trouble though.

My full code in post #8 and its issues:
The

readAndSend();

function is sending out the smoothed analog array values to the receiver esp32. It makes sense to have it where it is because it sends out a value right before the array indexes to the next sensor and then the repeats the smoothing if statement.

I tried to put that function independently/separately of the smoothing if statement and the trouble I get is that my receiver side only gets one sensor value rather than both sets of analog sensor values if I do that. If anyone wanted to use the code they would only be able to send one analog value. My intent is to send it with mulitple smoothed analog values in an array.

Since my current array would take ~128ms it would be weird to embed an interval of 3000 ms inside of it.

I did try to put this near the end of the void loop function, but I run into the issue mentioned above where the receiver only gets one analog sensor value:

// millis() returns the number of milliseconds passed since the microprocessor was started and began running the current program.
  if(millis() - SerialPrintStart >= SerialPrintInterval)
  {
    SerialPrintStart = millis();

It seems rather than send the latest analog smoothed values, the code may be building a buffer of older values that are slowly ramping up and printing them on the receiver side due to the 3 second interval. I'm trying to avoid this but don't know what direction I should take to resolve the issue.

Note: These two functions are interelated

// Function responsible for pin reading and sending of data to the peer
void readAndSend() {
  // Read the data of the pin
  uint8_t data = EspNowAverage;
  // Send the data to the peer
  send(&data, peerMacAddress);
}

I believe this is part of the espressif API functions:

// Function that will send the data to the peer that has the specified mac address
void send(const uint8_t *data, uint8_t *peerMacAddress) {
  esp_err_t result = esp_now_send(peerMacAddress, data, sizeof(data));
}

knightridar:
It makes sense to have it where it is because it sends out a value right before the array indexes to the next sensor and then the repeats the smoothing if statement.

But apparently it then sends it faster then you want it. So it does not make sense to have it there :slight_smile:

But, if you don't need that average that often, simply don't read it that often :wink:

Or, really split the two. Aka, if you have two sensors and want to keep track of both, create two variables to store the average.

Aka, rethink the general flow of the program :slight_smile:

PS

void send(const uint8_t *data, uint8_t *peerMacAddress) {
  esp_err_t result = esp_now_send(peerMacAddress, data, sizeof(data));
}

Will give you trouble if. sizeof(data) does not return the size of the actual data which the pointer is pointing to but the size of the pointer.

Hopefully this will help others if they want to make this project or other similar projects. I'm making a dual axis solar tracker with wireless tranmission of data to drive azimuth and elevation motors. In past attempts I had a wired connection but the wires were interfering with my movement paths. I also ended up eliminating the need for long wires and simplified my installation.

Geo Bruce was the original creator and I wanted to modify his idea and make it better:

Or, really split the two. Aka, if you have two sensors and want to keep track of both, create two variables to store the average.

The intent of the array is so that people can use multiple analog sensors if they have them in their project and smooth out the values for more accurate results. Hopefully this will save them from having to write extra code and that's why I want to avoid creating more variables if an array can take care of smoothing the readings and giving me an average. I know I'm only using two analog inputs but I want to be able to make this code modular for other projects in the future.

This is a list of issues/challenges and improvements I've come across and implemented in the past few years.

Transmitter:

  1. ESP32 to be powered by smallest sized solar panel possible, or possibly battery.
    I've successfully done this with an Arduino pro mini and HC-12 wireless RF
    module. (Cloudy weather vs regular or sunny day forced me to use a larger
    solar panel or 18650 batteries)

Really want to do this so people in rural areas don't need to have access to
batteries.

  1. I've transitioned from using an HC-12 module (long range up to 1.8 km line of
    sight, 100 channels in the 433.4-473.0 MHz range)
    a. problems if multiple people are on the same channel
    b. chance of signal interference
    c. can control other peoples tracking motors if they are on the same channel
    d. no password control (none that I'm aware of).
    e. after 100 channels kind of limits it to how many people can use the tracker
    in the same area.
    f. loss of radio signal due to dipole antenna design issues and metal structure
    caused motors to keep spinning (guessing could have been improved with
    code)

  2. Decided to try bluetooth first
    a. for low power to use with small solar panel
    b. possible password control to allow more unique users and eliminate device
    interference
    c. had trouble finding bluetooth to bluetooth communication.

  3. Thought about wifi and it's password control abilities but still lots of power
    usage to deal with.

  4. Using ESP-Now for:
    a. low power usage
    b. unique mac addresses allow for multiple users
    c. can add password keys I believe, but unique addresses take care of
    interference issues.

  5. A recent idea Ken_F on the forum gave was to change the light divider
    orientation by 45 degrees. This simplified the code and allows me to go from
    using 4 analog inputs to 2 analog inputs. However, I can't calibrate my analog
    sensors individually via software now. I've used potentiometers again to fix the
    calibration issue since each sensor has different tolerances. I wanted to take
    care of this automatically with code, but I would have to go back to using 4
    analog inputs.

With regards to program flow. Here it is:

Transmitter:

  1. Using low power ESP-Now protocol, two analog values are smoothed after 64
    readings, .1 uF capacitors are used to reduce noise.

  2. Two potentiometers are being used to adjust factory tolerances of 2 pairs of
    TEMT6000 phototransistors that are in series.

  3. Why I wanted to use millis(), basically to do multiple things at once:
    a. To slow down serialprint readout for troubleshooting purposes

But, if you don't need that average that often, simply don't read it that often :wink:

I like this idea :). I can increase interval time for getting average, however is too long of an interval time bad for reducing noisy results? I thought I may
have read this somewhere. Since I'm following the sun I don't need results too often. However, in the beginning of my readings I can't have false results misguide the tracking motors in the wrong direction for a long interval. It throws off the tracking program. This has been my past experience.

b. Wanted to prevent continous fast data transmission with the intent of saving
power.
c. will implement deep sleep mode later, it may not be useful if I'm powering
the transmitter via solar panel, but may be useful if a solar panel / battery
power combination are used.

But apparently it then sends it faster then you want it. So it does not make sense to have it there :slight_smile:

Was confused by this. My smoothed readings are averaging really fast.
The way I'm slowing down the serial readout time though is not providing the latest results.
The way I can tell is that the values are ramping up really slowly on the readout despite me taking fingers on/off the sensor.
When I'm not using this:

// millis() returns the number of milliseconds passed since the microprocessor was started and began running the current program.
  if(millis() - SerialPrintStart >= SerialPrintInterval)
  {
    SerialPrintStart = millis();

The values ramp up fast and are printed out really fast on the serial monitor.
I will dwelve further into the program flow to figure out how the latest values are provided despite having a slow serialprint time interval.

Receiver:

  1. uint8_t analog values are received and parsed (1 set for azimuth, 1 set for
    elevation, don't know yet if parsing is the best solution)
    a. Sends success/fail command to transmitter (confirms data is being sent)
    b. If fail notice is sent motors stop moving

  2. parsed values drive azimuth and elevation motors
    (possible to use pointers to determine which values are for azimuth and
    elevation? I still need to familiarize my self with pointers and their uses ::slight_smile: )

  3. voltage divider difference under or above midpoint (~127) determine which
    way motors should move.

  4. analog values are a result of a voltage divider. once they read out (within a
    certain tolerance level) a value close to a midpoint value it means the tracker
    is aligned and motors stop moving

Here is updated code:
The results ramp up a little sooner now.

Transmitter:

/*  Free and open source, CC BY-SA 4.0
    https://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf
    https://docs.espressif.com/projects/esp-idf/en/stable/api-reference/wifi/esp_now.html
    Modified code based on:
    https://www.instructables.com/id/ESP32-With-ESP-Now-Protocol/
    http://www.arduino.cc/en/Tutorial/Smoothing
*/

//ESP-Now power saving protocol
#include <esp_now.h>

#include <WiFi.h>

// ESP32 adc conversion
#include <driver/adc.h>

// Channel used for connection
#define CHANNEL 1

// Structure with information about the next peer
esp_now_peer_info_t peer;

// Define the number of samples to keep track of. The higher the number, the
// more the readings will be smoothed, but the slower the output will respond to
// the input. Using a constant rather than a normal variable lets us use this
// data to determine the size of the readings array.
const uint8_t numReadings = 64;
const uint8_t numSensors = 2;

uint32_t readings[numSensors][numReadings];   // multi-dimensional readings from analog input
uint32_t total[numSensors] = {0};    // the running total
uint32_t readIndex = 0;              // the index of the current reading
uint32_t average = 0;                // the average
uint8_t EspNowAverage = 0;

// interval to stabilize analog input smoothing readings
uint8_t numReadingsInterval = 12;
uint32_t numReadingsStart = 0;

// Earth rotates .25 degrees/minute. In 4 minutes Earth rotates 1 degree.
// Add a delay time if necessary to conserve power for solar cell or battery.

// Mac Address of the peer to which we will send the data
uint8_t peerMacAddress[] = {0x30, 0xAE, 0xA4, 0xF0, 0x54, 0xA0};

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

  // initialize all the readings to 0
  // multidimensional array takes into account multiple sensors and multiple readings for each sensor
  for (uint8_t thisReading = 0; thisReading < numReadings; thisReading++) {
    for ( uint8_t j = 0; j < numSensors; j++)  readings[j][thisReading] = 0;
  }

  // Call the function that initializes the station mode
  modeStation();

  // Call function that initializes ESPNow
  InitESPNow();

  // Add the peer
  addPeer(peerMacAddress);

  // Registers the callback that will inform us about the status of the submission.
  // The function that will be executed is onDataSent and is stated below
  esp_now_register_send_cb(OnDataSent);
}

//loop function being used to smooth analog input values
// void OnDataSent function sends values over and over again
void loop() {
  // Voltage divider analog in pins
  adc1_config_width(ADC_WIDTH_12Bit);
  adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_DB_11); //Pin34
  adc1_config_width(ADC_WIDTH_12Bit);
  adc1_config_channel_atten(ADC1_CHANNEL_7, ADC_ATTEN_DB_11); //Pin35

  if ( millis() - numReadingsStart >= numReadingsInterval * numReadings ) {
    numReadingsStart = millis();

    // Read the sensor
    uint16_t Azimuth = adc1_get_raw(ADC1_CHANNEL_6);
    uint16_t Elevation = adc1_get_raw(ADC1_CHANNEL_7);

    uint16_t  inputPin[ numSensors ] = {Azimuth, Elevation};

    uint8_t ai;

    for (ai = 0; ai < numSensors ; ai++) {
      // subtract the last reading:
      total[ ai ] = total[ ai ] - readings[ai][readIndex];
      // read from the sensor:
      readings[ai][readIndex] = inputPin[ai];
      // add the reading to the total:
      total[ai] = total[ai] + readings[ai][readIndex];
      // calculate the average:
      average = total[ai] / numReadings;
      // reduce results to 0-255
      EspNowAverage = average / 16; // send smoothed average of each sensor input to receiver
      readAndSend();
    }

    // advance to the next position in the array:
    readIndex = readIndex + 1;
    // if we're at the end of the array...
    if (readIndex >= numReadings) {
      // ...wrap around to the beginning:
      readIndex = 0;
    }
  }
}


// Function responsible for pin reading and sending of data to the peer
void readAndSend() {
  // Read the data of the pin
  uint8_t data = EspNowAverage;
  // Send the data to the peer
  send(&data, peerMacAddress);
}

// Function that serves as a callback to warn us about the sending situation we made
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Success" : "Fail");
}

// Function to initialize the station mode
void modeStation() {
  // We put the ESP in station mode
  WiFi.mode(WIFI_STA);
  // We show on Serial Monitor the Mac Address
  // of this ESP when in station mode
  Serial.print("Mac Address in Station: ");
  Serial.println(WiFi.macAddress());
}

// ESPNow startup function
void InitESPNow() {
  // If the initialization was successful
  if (esp_now_init() == ESP_OK) {
    Serial.println("ESPNow Init Success");
  }
  // If initialization failed
  else {
    Serial.println("ESPNow Init Failed");
    ESP.restart();
  }
}

// Function that adds a new peer through your MAC address
void addPeer(uint8_t *peerMacAddress) {
  // We inform the channel
  peer.channel = CHANNEL;
  // 0 not to use encryption or 1 to use
  peer.encrypt = 0;
  // Copy array address to structure
  memcpy(peer.peer_addr, peerMacAddress, 6);
  // Add slave
  esp_now_add_peer(&peer);
}

// Function that will send the data to the peer that has the specified mac address
void send(const uint8_t *data, uint8_t *peerMacAddress) {
  esp_err_t result = esp_now_send(peerMacAddress, data, sizeof(data));
}

Receiver:

/*  Free and open source, CC BY-SA 4.0
    https://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf
    https://docs.espressif.com/projects/esp-idf/en/stable/api-reference/wifi/esp_now.html
    Modified code based on:
    http://www.esploradores.com/practica-6-conexion-esp-now/
    http://www.arduino.cc/en/Tutorial/Smoothing
*/

//Libraries espnow and wifi
#include <esp_now.h>
#include <WiFi.h>

// Channel used for connection
#define CHANNEL 1

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

  // Call the function that initializes the station mode
  modeStation();

  // Call function that initializes ESPNow
  InitESPNow();

  // Registers the callback that will inform us that we receive data. The function to be executed is onDataRecv and is declared below
  esp_now_register_recv_cb(onDataRecv);

  // Registers the callback that will inform us
  // about the status of the submission.
  // The function to be executed
  // is onDataSent and is declared below
  esp_now_register_send_cb(onDataSent);
}

// We do not need to do anything in the loop. we send the data as soon as we get from the other esp by the callback
void loop() {
}

// Function that serves as a callback to warn us we received data
void onDataRecv(const uint8_t *mac_addr, const uint8_t *data, int len) {
  // Place the received data at the output of the pin
  Serial.println(*data);
}

// Function that serves as a callback to warn us about the sending situation we made
void onDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Success" : "Fail");
}

// Function to initialize the station mode
void modeStation() {
  // We put the ESP in station mode
  WiFi.mode(WIFI_STA);
  // We show on Serial Monitor the Mac Address
  // of this ESP when in station mode
  Serial.print("Mac Address in Station: ");
  Serial.println(WiFi.macAddress());
}

// ESPNow startup function
void InitESPNow() {
  // If the initialization was successful
  if (esp_now_init() == ESP_OK) {
    Serial.println("ESPNow Init Success");
  }
  // If initialization failed
  else {
    Serial.println("ESPNow Init Failed");
    ESP.restart();
  }
}