text:
Faster output of Serial.print() data coming from TSL1402R sensor
I am reading a TSL1402R with an Arduino Mega2560.  The code is based on the sketch from the arduino playground here:http://playground.arduino.cc/Main/TSL1402R
The application is a digital caliper for moving strands of filament.  I would like to have the scan rate as fast as possible.  I am making my own filament and need some means of quality control.
I am reading the analog values of each photodiode (256) of the sensor to an array.  I find an average value of 25 reads for each of the diodes and place that in another array.  I then I compare the averaged values for each of the 256 diodes and assign them into 3 groups: dark1, dark2 and dark3 I then count the assigned values and get a total. +1/4 for dark1, 1/2 for dark2 and 1 for dark3.  This figure represents the width of a piece of filament casting the shadow on the sensor.(dark1 is partially blocked photodiode, dark2 is 1/2 blocked, dark3 is fully blocked)
I am looking at the clock pin on the sensor with a scope.  When I output data with serialprint at (any speed) 115200  The program speed slows down considerably.  When I change the program to serialprint only if the previous value changes, it gets even slower.  If I serialprint every time through the loop, the buffer fills and the values are not accurate.
I get accurate data from my program.  What is the most efficient way to get it out and into a usable form? By way of form I mean to have the data saved so I can see the size deviation of the filament I am producing.  It would also be great if I could visualize the data in real time and make adjustments during the extrusion process.
I have been researching this for weeks, tweaking the program and trying different ideas based on responses to questions similar to mine.
My background is industrial electrical systems, not programming.  This is my first attempt at something like this.  Any advice would be greatly appreciated.
Thanks to all in advance,
Dave Stewart, aka bigstew123
#include <EEPROM.h>
#include <TimerOne.h>
#define NPIXELS 255  // No. of pixels in array

// Define various ADC prescaler:
const unsigned char PS_32 = (1 << ADPS2) | (1 << ADPS0);
const unsigned char PS_128 = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);

const byte PWMDAC1pin = 11; // PWM DAC, only pins 9 and 10 are allowed
const byte period = 128; // for 10 bit DAC

const int LEDpin = 8;
const int CLKpin = 3;    // <-- Arduino pin delivering the clock pulses to      pin 3 (CLK) of the TSL1401
const int SIpin = 4;     // <-- Arduino pin delivering the SI (serial-input) pulse to pin 2 of the TSL1401
const int AOpin = 1;    // <-- Arduino pin connected to pin 4 (analog output 1)of the TSL1401

unsigned int intArray[NPIXELS]; // <-- the array where the readout of the photodiodes is stored, as integers

int nAggr = 5;        // image averaging count per one scan. should not exceed 10
int timer = 5;        // value output averaging counter
int sensor_value = 0;
int sensor_value_1 = 0;
int sensor_value_2 = 0;
int sensor_value_3 = 0;
float sensor_value_mapped = 0;
float dark_pixels_1 = 0;
float dark_pixels_2 = 0;
float dark_pixels_3 = 0;
float dark_pixels_total = 0;
float dark_pixels_avg = 0;
float width_mm = 0;
float width_mm_old = 0;

// default filament width
double lowpassValue = 1.75;
double lowpassFactor = 0.5;

double calibFactor =  15.75; // (default pixel per mm = 15.748 for 400dpi     sensor

boolean debugMessage = false;
boolean doCalibration = false;

int timerCounter = 0;
double timerValue = 0;

void setup() {
// To set up the ADC, first remove bits set by Arduino library, then choose
// a prescaler: PS_16, PS_32, PS_64 or PS_128:
    ADCSRA &= ~PS_128;
    ADCSRA |= PS_32; // <-- Using PS_32 makes a single ADC conversion take ~30 us
    pinMode(PWMDAC1pin, OUTPUT);
// Timer1.initialize(period);
    Timer1.initialize(40);
// Next, assert default setting:
    analogReference(DEFAULT);

// Set all IO pins low:
    for (int i = 0; i < 14; i++) {
        digitalWrite(i, LOW);
    }

    pinMode(LEDpin, OUTPUT);
    initSensor();
    Serial.begin(115200);
//Serial.begin(9600);
}

void loop() {
    Timer1.pwm(PWMDAC1pin, (dark_pixels_avg));
    sensor_value = 750; //this is the 0-1023 value for the light/dark threshold
    sensor_value_mapped = sensor_value;
    sensor_value_1 = sensor_value_mapped;
    sensor_value_2 = sensor_value_mapped * 75 / 100;//this is 3/4/
    sensor_value_3 = sensor_value_mapped * 65 / 100; //this is 1/2
    delay(50);
    scanSensor();
    MATH();
    delay(50);
    /*
     *   testing code here: if the value is different, serial print with 100 delay, if the value is unchanged, update at 1000
     *   this is code I used to try to plot the values to a python script running on a raspberry pi 2b
     *   with this setup, the program slows and the scan rate is so slow I miss deviations in the filament.
     *
     if
     (width_mm != width_mm_old)
     {
     Serial.println (width_mm, 4);
     delay(100);

     }
     else
     {Serial.println (width_mm_old, 4);
     delay(1000);

     }
     */
// every scan, print the width
    Serial.println(width_mm, 4);

// Command processor
    if (Serial.available() > 0) {
        char incomingByte = Serial.read();

        switch (incomingByte) {
            case 'd':    // Debugging message toggle
                debugMessage = !debugMessage;
                break;

            case 'c':    // Calibration
                doCalibration = true;
                break;

            case 'h':
                //helpMessage();
                array_value();
                break;
        }
    }

    if (debugMessage) {
        //   Serial.print("Number of dark pixels       ");
        //   Serial.println(dark_pixels);
        // delay(300);
        Serial.print("Dark pixel average          ");
        Serial.println(dark_pixels_avg, 4);
        Serial.print("Dark pixel 1                ");
        Serial.println(dark_pixels_1);
        Serial.print("Dark pixel 2                ");
        Serial.println(dark_pixels_2);
        Serial.print("Dark pixel 3                ");
        Serial.println(dark_pixels_3);
        Serial.print("dark_pixels_total             ");
        Serial.println(dark_pixels_total);
        Serial.print("filament width in mm       ");
        Serial.println(width_mm, 4);
        //  Serial.print ("sensor pot value          ");
        // Serial.println (sensor_value);
        //  Serial.print ("sensor value mapped        ");
        //   Serial.println (sensor_value_mapped);
        delay(200);
        //  Serial.print("Raw:\t");
//    printDouble(lowpassValue, 4);
//   Serial.print("\t(mm)=\t");
//    printDouble(mmValue, 3);
//   Serial.println();
//Serial.println(intArray[i]);//////////////////////////////////////////
//Serial.print(";");
    }

    width_mm_old = width_mm;
}

void initSensor() {
// Initialize two Arduino pins as digital output:
    pinMode(CLKpin, OUTPUT);
    pinMode(SIpin, OUTPUT);

// Clock out any existing SI pulse through the ccd register:
    for (int i = 0; i < NPIXELS + 4; i++) {
        ClockPulse();
    }

// Create a new SI pulse and clock out that same SI pulse through the sensor register:
    digitalWrite(SIpin, HIGH);
    delayMicroseconds(1);
    digitalWrite(CLKpin, HIGH);
    delayMicroseconds(1);
    digitalWrite(SIpin, LOW);
    delayMicroseconds(1);
    digitalWrite(CLKpin, LOW);

    for (int i = 0; i < NPIXELS + 4; i++) {
        ClockPulse();
    }
}

void scanSensor() {
    // Stop the ongoing integration of light quanta from each photodiode by  clocking in a
    // SI pulse:
    // Create a new SI pulse and clock out that same SI pulse through the sensor register:
    digitalWrite(SIpin, HIGH);
    delayMicroseconds(1);
    digitalWrite(CLKpin, HIGH);
    delayMicroseconds(1);
    digitalWrite(SIpin, LOW);
    delayMicroseconds(1);
    digitalWrite(CLKpin, LOW);

    // Next, a new measuring cycle is starting once 18 clock pulses have passed. At
    // that time, the photodiodes are once again active. We clock out the SI pulse through
    // the NPIXELS bit register in order to be ready to halt the ongoing measurement at our will
    // (by clocking in a new SI pulse):
    for (int i = 0; i < NPIXELS + 4; i++) {
        if (i == 18) {
            // Now the photodiodes goes active..
            // An external trigger can be placed here
        }

        ClockPulse();
    }

    // The integration time of the current program / measurement cycle is ~2ms. If a larger time
// of integration is wanted, uncomment the next line:
//delay(1);
// Stop the ongoing integration of light quanta from each photodiode by clocking in a SI pulse
// into the sensors register:
// Create a new SI pulse and clock out that same SI pulse through the sensor register:
    digitalWrite(SIpin, HIGH);
    delayMicroseconds(1);
    digitalWrite(CLKpin, HIGH);
    delayMicroseconds(1);
    digitalWrite(SIpin, LOW);
    delayMicroseconds(1);
    digitalWrite(CLKpin, LOW);

// Next, read all 256 pixels in parallell. Store the result in the array. Each clock pulse
// causes a new pixel to expose its value on the two outputs:
    for (int i = 0; i < NPIXELS; i++) {
        delayMicroseconds(2);// <-- We add a delay to stabilize the AO output from the sensor
        intArray[i] = analogRead(AOpin);    //(AOpin);
        ClockPulse();
    }
}
//here we have a sensor value that is an integer number between 0 and 1023 to represent the value of the pixels read in intArray[]
//  the number varies, so really dark pixels are set at 75, medium at 100, and light at 125....  of course, this will be a % and scaled
//so when the operator adjusts the sensitivity, each value will adjust accordingly.
// each function only counts the pixels in its range so there is no overlapp
//for a sensor value of 200, sensor value 1 will be 200, value 2 will be 150 and value 3 will be 100
////////////////////////////////////////really dark///////////////////

void MATH() {
    int x = 0;
    int y0 = 0;
    int y1 = 0;
    int y2 = 0;
    int y3 = 0;
    float dpa = 0;

    for (int i = 0; i < NPIXELS; i++) {
        x = intArray[i];

        if (x <= sensor_value_1 && x >= sensor_value_2 && x >=  sensor_value_3) { //less than 200, but greater than 150 and 100
            y1 = y1 + 1;   //////////////////////////////////////not very dark/////////////////////////
        }

        if (x <= sensor_value_1 && x <= sensor_value_2 && x >= sensor_value_3) { //less than 200, less than 150, but more than 100
            y2 = y2 + 1;   //////////////////////////////////////medium dark////////////////////////
        }

        if (x <= sensor_value_1 && x <= sensor_value_2 && x <= sensor_value_3) { //less than 200 or 150 or 100 (really dark pixel(low intArray value)
            y3 = y3 + 1;   //////////////////////////////////////very dark/////////////////////////
        }
    }

    dark_pixels_1 = y1 * 25 / 100; ///1/4 of a count for each pixel
    dark_pixels_2 = y2 * 50 / 100; // half a count for each pixel
    dark_pixels_3 = y3; // full count for each pixel
/////////////////////////add up the totals///////////////////////////////
    dark_pixels_total = dark_pixels_3 + dark_pixels_2 + dark_pixels_1;

    for (int q = 0; q < 25; q++) {
        dpa  += dark_pixels_total;
    }

    dark_pixels_avg = dpa / 25;
    float k = 0;
    k =  map(dark_pixels_avg, 50, 97, 157, 313); //map the values to a known     width and convert to mm
    width_mm = k / 100;
    //
    //   Serial.print("Number of dark pixels       ");
    //   Serial.println(dark_pixels);
    // delay(300);
    //Serial.print("Dark pixel average          ");
    // Serial.println(dark_pixels_avg);
    // Serial.print("Dark pixel 1                ");
    // Serial.println(dark_pixels_1);
    // Serial.print("Dark pixel 2                ");
    //  Serial.println(dark_pixels_2);
    //  Serial.print("Dark pixel 3                ");
    //  Serial.println(dark_pixels_3);
    //  Serial.print("dark_pixels_avg             ");
    //  Serial.println(dark_pixels_avg);
    //  Serial.print ("filament width in mm       ");
    //  Serial.println (width_mm, 4);
    //   Serial.print ("sensor pot value          ");
    //   Serial.println (sensor_value);
    //   Serial.print ("sensor value mapped        ");
//    Serial.println (sensor_value_mapped);
//    delay(200);
}

// This function generates an outgoing clock pulse from the Arduino digital pin 'CLKpin'. This clock
// pulse is fed into pin 3 of the linear sensor:
void ClockPulse() {
    delayMicroseconds(1);
    digitalWrite(CLKpin, HIGH);
    digitalWrite(CLKpin, LOW);
}

void array_value() {
    for (int i = 0; i < NPIXELS; i++) {
        Serial.print("ARRAY VALUE");
        Serial.print(i);
        Serial.print("\t");
        Serial.println(intArray[i]);
    }
}

Unfortunately this is not answerable without details of the program.  Either you are keeping the serial port busy, and that is the limitation, or you have another part of the program which is necessarily time consuming, or you have a program mistake which makes something take far longer than it should.

I posted the code.  Not pretty, I see now there are remnants of things I have tried and since removed.  I hope you can make some sense of it.  Thanks for your efforts.

How often do you need this loop to run? At a quick and dirty count of the output (230 characters or so), at 115200 baud (11520 char/sec), the output needs 20 ms, meaning the loop can't run any faster than 50 hz or it will be held up waiting for the the output buffer to clear. You could gain some speed by formatting your (currently 6) output values into a single line, comma-separated, and without the text labels. But ultimately you need to calculate what rate you need and adjust the output quantity and speed to be compatible.

I am trying to check filament diameter as it is wound from a master spool onto a standard 2.2kg spool.  I have the sensor enclosed in a box with a line laser diode aimed at it.  When the filament blocks the laser, the photodiodes on the sensor drop their analog output value to about 20% of the fully illuminated value.  It takes 256 analog reads to complete a full scan of the diodes on the sensor.  Sometimes there are defects in my filament that are about an inch long.  I would like to capture the defect while winding the filament as fast as possible.

My previous best guess was that I was reading about 5 complete scans per second.  At 50 feet per minute spool rate, that is 600 inches per minute or 10 inches per second going past the sensor.  If I only read 5 scans per second, that is one scan for every two inches of filament.  A deviation caused a blob about 1.75 inches long at 4mm diameter (target is 2.85mm filament diameter).   My setup missed the blob, and that is what has prompted me to post here and try and sort it out.     The Serial.print lines are for debugging, I only output the width_mm value.

From what you are describing, your delay calls would be the cause. Or are they just part of the debugging and it runs slow even without them?

After spending some more time doing research, I have come to realize that the arduino platform is not capable of the performance I was hoping for with regard to the rate of ADC sampling.  I have purchased a BeagleBone Black and plan to use it in place of the arduino.  Thank you to everyone who commented.


text:
After restoring the BNO055 offsets to the sensor the calibration values are all 0
Board: ESP32
Script: restore_offsets.ino from Adafruit's BNO055 library
The only difference is I am storing the information in ESP's NVS using the Preferences Library
Code
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BNO055.h>
#include <utility/imumaths.h>
#include <Preferences.h>

/* Set the delay between fresh samples */
#define BNO055_SAMPLERATE_DELAY_MS (1000)

Adafruit_BNO055 bno = Adafruit_BNO055(1390);

Preferences Calibration;

/**************************************************************************/
/*
    Display some basic info about the sensor status
    */
/**************************************************************************/
void displaySensorStatus(void)
{
    /* Get the system status values (mostly for debugging purposes) */
    uint8_t system_status, self_test_results, system_error;
    system_status = self_test_results = system_error = 0;
    bno.getSystemStatus(&system_status, &self_test_results, &system_error);

    /* Display the results in the Serial Monitor */
    Serial.println("");
    Serial.print("System Status: 0x");
    Serial.println(system_status, HEX);
    Serial.print("Self Test:     0x");
    Serial.println(self_test_results, HEX);
    Serial.print("System Error:  0x");
    Serial.println(system_error, HEX);
    Serial.println("");
    delay(500);
}

/**************************************************************************/
/*
    Display sensor calibration status
    */
/**************************************************************************/
void displayCalStatus(void)
{
    /* Get the four calibration values (0..3) */
    /* Any sensor data reporting 0 should be ignored, */
    /* 3 means 'fully calibrated" */
    uint8_t system, gyro, accel, mag;
    system = gyro = accel = mag = 0;
    bno.getCalibration(&system, &gyro, &accel, &mag);

    /* The data should be ignored until the system calibration is > 0 */
    Serial.print("\t");
    if (!system)
    {
        Serial.print("! ");
    }

    /* Display the individual values */
    Serial.print("Sys:");
    Serial.print(system, DEC);
    Serial.print(" G:");
    Serial.print(gyro, DEC);
    Serial.print(" A:");
    Serial.print(accel, DEC);
    Serial.print(" M:");
    Serial.print(mag, DEC);
}

/**************************************************************************/
/*
    Display the raw calibration offset and radius data
    */
/**************************************************************************/
void displaySensorOffsets(const adafruit_bno055_offsets_t &calibData)
{
    Serial.print("Accelerometer: ");
    Serial.print(calibData.accel_offset_x); Serial.print(" ");
    Serial.print(calibData.accel_offset_y); Serial.print(" ");
    Serial.print(calibData.accel_offset_z); Serial.print(" ");

    Serial.print("\nGyro: ");
    Serial.print(calibData.gyro_offset_x); Serial.print(" ");
    Serial.print(calibData.gyro_offset_y); Serial.print(" ");
    Serial.print(calibData.gyro_offset_z); Serial.print(" ");

    Serial.print("\nMag: ");
    Serial.print(calibData.mag_offset_x); Serial.print(" ");
    Serial.print(calibData.mag_offset_y); Serial.print(" ");
    Serial.print(calibData.mag_offset_z); Serial.print(" ");

    Serial.print("\nAccel Radius: ");
    Serial.print(calibData.accel_radius);

    Serial.print("\nMag Radius: ");
    Serial.print(calibData.mag_radius);
}

/**************************************************************************/
/*
    Arduino setup function (automatically called at startup)
    */
/**************************************************************************/
void setup(void)
{
    Wire.begin(13, 16, 400000);
    Serial.begin(115200);
    delay(1000);
    Serial.println("Orientation Sensor Test"); Serial.println("");

    /* Initialise the sensor */
    if (!bno.begin())
    {
        /* There was a problem detecting the BNO055 ... check your connections */
        Serial.print("Ooops, no BNO055 detected ... Check your wiring or I2C ADDR!");
        while (1);
    }

    Calibration.begin("offsets", false);
    adafruit_bno055_offsets_t calibrationData;
    sensor_t sensor;

    int32_t bnoID = Calibration.getInt("bnoID");
     bool foundCalib = false;
    /*
    *  Look for the sensor's unique ID at the beginning oF EEPROM.
    *  This isn't foolproof, but it's better than nothing.
    */
    bno.getSensor(&sensor);
    if (bnoID != sensor.sensor_id)
    {
        Serial.println("\nNo Calibration Data for this sensor exists in NVS");
        delay(500);
    }
    else
    {
        Serial.println("\nFound Calibration for this sensor in NVS.");

        // Accelerometer offsets
        calibrationData.accel_offset_x = Calibration.getInt("acc_off_x");
        calibrationData.accel_offset_y = Calibration.getInt("acc_off_y");
        calibrationData.accel_offset_z = Calibration.getInt("acc_off_z");

        // Gyroscrope offsets
        calibrationData.gyro_offset_x = Calibration.getInt("gyr_off_x");
        calibrationData.gyro_offset_y = Calibration.getInt("gyr_off_y");
        calibrationData.gyro_offset_z = Calibration.getInt("gyr_off_z");

        // Magnetometer offsets
        calibrationData.mag_offset_x = Calibration.getInt("mag_off_x");
        calibrationData.mag_offset_y = Calibration.getInt("mag_off_y");
        calibrationData.mag_offset_z = Calibration.getInt("mag_off_z");

        displaySensorOffsets(calibrationData);

        Serial.println("\n\nRestoring Calibration data to the BNO055...");
        bno.setSensorOffsets(calibrationData);

        Serial.println("\n\nCalibration data loaded into BNO055");
        foundCalib = true;
    }

    delay(1000);

    /* Display some basic information on this sensor */
//    displaySensorDetails();

    /* Optional: Display current status */
    displaySensorStatus();

   //Crystal must be configured AFTER loading calibration data into BNO055.
    bno.setExtCrystalUse(true);

    sensors_event_t event;
    bno.getEvent(&event);
    if (foundCalib){
        Serial.println("Move sensor slightly to calibrate magnetometers");
        while (!bno.isFullyCalibrated())
        {
            bno.getEvent(&event);
            displayCalStatus();
            Serial.println("");
            delay(BNO055_SAMPLERATE_DELAY_MS);
        }
    }
    else
    {
        Serial.println("Please Calibrate Sensor: ");
        while (!bno.isFullyCalibrated())
        {
            bno.getEvent(&event);

            Serial.print("X: ");
            Serial.print(event.orientation.x, 4);
            Serial.print("\tY: ");
            Serial.print(event.orientation.y, 4);
            Serial.print("\tZ: ");
            Serial.print(event.orientation.z, 4);

            /* Optional: Display calibration status */
            displayCalStatus();

            /* New line for the next sample */
            Serial.println("");

            /* Wait the specified delay before requesting new data */
            delay(BNO055_SAMPLERATE_DELAY_MS);
        }
    }

    Serial.println("\nFully calibrated!");
    Serial.println("--------------------------------");
    Serial.println("Calibration Results: ");
    adafruit_bno055_offsets_t newCalib;
    bno.getSensorOffsets(newCalib);
    displaySensorOffsets(newCalib);

    Serial.println("\n\nStoring calibration data to NVS...");

    bno.getSensor(&sensor);
    bnoID = sensor.sensor_id;
    // enter the Sensor ID
    Calibration.putInt("bnoID", bnoID);

    // store new Accelerometer offsets
    Calibration.putInt("acc_off_x", newCalib.accel_offset_x);
    Calibration.putInt("acc_off_y", newCalib.accel_offset_y);
    Calibration.putInt("acc_off_z", newCalib.accel_offset_z);

    // store new Gyroscope offsets
    Calibration.putInt("gyr_off_x", newCalib.gyro_offset_x);
    Calibration.putInt("gyr_off_y", newCalib.gyro_offset_y);
    Calibration.putInt("gyr_off_z", newCalib.gyro_offset_z);

    // store new Magnetometer offsets
    Calibration.putInt("mag_off_x", newCalib.mag_offset_x);
    Calibration.putInt("mag_off_y", newCalib.mag_offset_y);
    Calibration.putInt("mag_off_z", newCalib.mag_offset_z);
    Serial.println("Data stored to NVS..");

    Serial.println("\n--------------------------------\n");
    delay(500);
}

void loop() {
    /* Get a new sensor event */
    sensors_event_t event;
    bno.getEvent(&event);

    /* Display the floating point data */
    Serial.print("X: ");
    Serial.print(event.orientation.x, 4);
    Serial.print("\tY: ");
    Serial.print(event.orientation.y, 4);
    Serial.print("\tZ: ");
    Serial.print(event.orientation.z, 4);

    /* Optional: Display calibration status */
    displayCalStatus();

    /* Optional: Display sensor status (debug only) */
    displaySensorStatus();

    /* New line for the next sample */
    Serial.println("");

    /* Wait the specified delay before requesting new data */
    delay(BNO055_SAMPLERATE_DELAY_MS);
}

The only difference in the code is instead of passing the offset struct I save information individually using putInt method
steps

I calibrate the sensor connected via I2C
Once the calibration is done store it into NVS
Observe values for a bit
Restart the node and retreive the offsets from NVS

Problem
The calibration offsets are stored into the BNO and it takes hella time in the following block:
   if (foundCalib){
        Serial.println("Move sensor slightly to calibrate magnetometers");
        while (!bno.isFullyCalibrated())
        {
            bno.getEvent(&event);
            displayCalStatus();
            Serial.println("");
            delay(BNO055_SAMPLERATE_DELAY_MS);
        }
    }

I added the displayCalStatus to see the values of the accelerometer, gyroscope and magnetometer and all values within the block are Zero.
Doesn't this defy the whole idea of storing offsets in the first place if the values are all zero?
Output from board
Found Calibration for this sensor in NVS.
Accelerometer: 19 -10 4
Gyro: -3 -4 9
Mag: 589 986 1473
Accel Radius: 0
Mag Radius: 0

Restoring Calibration data to the BNO055...

Calibration data loaded into BNO055

System Status: 0x0
Self Test:     0xF
System Error:  0x0

Move sensor slightly to calibrate magnetometers
    ! Sys:0 G:0 A:0 M:0
    ! Sys:0 G:0 A:0 M:0
    ! Sys:0 G:0 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0

As you can observe the calibration are all set to 0 and I have to do the whole thing again. why ?

Should we assume that there are non-zero calibration offsets that are returned, that they are correctly saved in NVS, and that they are correctly retrieved from NVS? Have you verified all of that, so that the only issue is that you are certain that you "saved" non-zero offests to the sensor and it's still returning zero offsets when read back?

I can assure you that the values are non-zero. I am pretty sure the values retreived are also non-zero from NVS. However I can perform tests again and edit the question with more concrete values to support the assumption.

I only ask because concrete values are the only way members of the community have to evaluate the problem.

I will get back at reproducing the query and edit the question with all relevant outputs from the node and bno055

@josecanuc I have added the log from my board

The displayCalStatus() function shows the status of the calibration, not the offsets or current sensor values. With calibration in progress the status is zero. Once the calibration of a sensor is complete, the status is 3. The sensor starts the calibration itself with first movements after power up.
The set offsets are used after power-up only until the initial automatic calibration finished.
from datasheet:

Once  the  device  is  calibrated,  the  calibration  profile  can  be  reused  to  get  the
  correct  orientation  data  immediately  after  ‘Power  of  Reset’.  However,  once  the  sensor  enters  the  internal
  calibration  routine,  the  calibration  profile  is  overwritten
  with  the  newly  obtained  sensor  offsets  and  sensor radius.

Is there way to avoid entering the internal calibration routine of the BNO055?

no. why is it a problem for you? it happens in the background. the sensors work all the time. the remembered offsets are good to have better values for first readings

The problem is that once the offsets are restored, I calibrate the magnetometer because it is very easy, but the while loop doesn't come out easily. I have to do all the calibration techniques all together.

but in your sketch you can do what you want. the offsets sketch is an example. I would ignore the calibration. The sensor handles it. After power-up make same movements and the sensor calibrates itself.

I think I will give give your stuff a try.

source: Stack Exchange

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

sort: votes


text:
How do I know if GY-521 MPU6050 has been calibrated properly?
I am planning to use the accelerometer of MPU6050 for a project.
I know that before using module (I am using GY-521 MPU6050), one needs to calibrate it.
I am using code by Luis Rodenas for calibration: https://sites.google.com/view/autoaero/code/auto-calibration-mpu6050
This code returns following offsets for my module:
-1123 -4100 1562 111 8 -1

Offsets are in Ax,Ay,Az,Gx,Gy,Gz format.
I am using these offsets in MPU6050_raw.ino example of i2cdevlib after making necessary adjustments. Here is the sketch
    // I2C device class (I2Cdev) demonstration Arduino sketch for MPU6050 class
// 10/7/2011 by Jeff Rowberg <jeff@rowberg.net>
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
//

// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"
#include "MPU6050.h"

// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif

// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 accelgyro;
//MPU6050 accelgyro(0x69); // <-- use for AD0 high

int16_t ax, ay, az;
int16_t gx, gy, gz;

// uncomment "OUTPUT_READABLE_ACCELGYRO" if you want to see a tab-separated
// list of the accel X/Y/Z and then gyro X/Y/Z values in decimal. Easy to read,
// not so easy to parse, and slow(er) over UART.
#define OUTPUT_READABLE_ACCELGYRO

// uncomment "OUTPUT_BINARY_ACCELGYRO" to send all 6 axes of data as 16-bit
// binary, one right after the other. This is very fast (as fast as possible
// without compression or data loss), and easy to parse, but impossible to read
// for a human.
//#define OUTPUT_BINARY_ACCELGYRO

#define LED_PIN 13
bool blinkState = false;

void setup() {
    // join I2C bus (I2Cdev library doesn't do this automatically)
    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
    #endif

    // initialize serial communication
    // (38400 chosen because it works as well at 8MHz as it does at 16MHz, but
    // it's really up to you depending on your project)
    Serial.begin(115200);

    // initialize device
    Serial.println("Initializing I2C devices...");
    accelgyro.initialize();
    accelgyro.setFullScaleAccelRange(3);
    // verify connection
    Serial.println("Testing device connections...");
    Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");

    // use the code below to change accel/gyro offset values

    Serial.println("Updating internal sensor offsets...");
    // -76 -2359 1688 0 0 0
    Serial.print(accelgyro.getXAccelOffset()); Serial.print("\t"); // -76
    Serial.print(accelgyro.getYAccelOffset()); Serial.print("\t"); // -2359
    Serial.print(accelgyro.getZAccelOffset()); Serial.print("\t"); // 1688
    Serial.print(accelgyro.getXGyroOffset()); Serial.print("\t"); // 0
    Serial.print(accelgyro.getYGyroOffset()); Serial.print("\t"); // 0
    Serial.print(accelgyro.getZGyroOffset()); Serial.print("\t"); // 0
    Serial.print("\n");
    accelgyro.setXGyroOffset(111);
    accelgyro.setYGyroOffset(8);
    accelgyro.setZGyroOffset(-1);
    accelgyro.setZAccelOffset(1562);
    accelgyro.setXAccelOffset(-1123);
    accelgyro.setYAccelOffset(-4100);
    Serial.print(accelgyro.getXAccelOffset()); Serial.print("\t"); // -76
    Serial.print(accelgyro.getYAccelOffset()); Serial.print("\t"); // -2359
    Serial.print(accelgyro.getZAccelOffset()); Serial.print("\t"); // 1688
    Serial.print(accelgyro.getXGyroOffset()); Serial.print("\t"); // 0
    Serial.print(accelgyro.getYGyroOffset()); Serial.print("\t"); // 0
    Serial.print(accelgyro.getZGyroOffset()); Serial.print("\t"); // 0
    Serial.print("\n");

    // configure Arduino LED pin for output
    pinMode(LED_PIN, OUTPUT);
}

void loop() {
    // read raw accel/gyro measurements from device
    accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

    // these methods (and a few others) are also available
    //accelgyro.getAcceleration(&ax, &ay, &az);
    //accelgyro.getRotation(&gx, &gy, &gz);

    #ifdef OUTPUT_READABLE_ACCELGYRO
        // display tab-separated accel/gyro x/y/z values
        Serial.print("a/g:\t");
        Serial.print(ax); Serial.print("\t");
        Serial.print(ay); Serial.print("\t");
        Serial.print(az); Serial.print("\t");
        Serial.print(gx); Serial.print("\t");
        Serial.print(gy); Serial.print("\t");
        Serial.println(gz);
    #endif

    #ifdef OUTPUT_BINARY_ACCELGYRO
        Serial.write((uint8_t)(ax >> 8)); Serial.write((uint8_t)(ax & 0xFF));
        Serial.write((uint8_t)(ay >> 8)); Serial.write((uint8_t)(ay & 0xFF));
        Serial.write((uint8_t)(az >> 8)); Serial.write((uint8_t)(az & 0xFF));
        Serial.write((uint8_t)(gx >> 8)); Serial.write((uint8_t)(gx & 0xFF));
        Serial.write((uint8_t)(gy >> 8)); Serial.write((uint8_t)(gy & 0xFF));
        Serial.write((uint8_t)(gz >> 8)); Serial.write((uint8_t)(gz & 0xFF));
    #endif

    // blink LED to indicate activity
    blinkState = !blinkState;
    digitalWrite(LED_PIN, blinkState);
}

This is the output at serial monitor when module is horizontal with package letters facing up.
So have I calibrated the accelerometer properly? Please help if you can see any anomaly.
Thanks.

consider looking at your acceleration and gyroscope data. if you have the device perfectly flat on the table you will find the gravitational force in some axis. tilt the whole setup and check if the g force now shows up in a different axis (hopefully the one you expect) then rotate the setup by 90 degrees around any axis. (always one at a time please!) if your gyro tells you that your rotational velocity per some measure of time roughly equals pi you know that everything works as expected. this actually works for every accelerometer and gyro so also these that you find on say the sparkfun 9dof board if you should ever come across those.
your cal can be tested by comparing a non cal-ed measurement with a cal-ed one. the differences between the expected value and the measured one should get smaller then.

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


text:
ADXL345 becomes 0g when plugin MicroSD Adapter using SPI
Try SD SPI code and ADXL345 SPI code separately and both are fine. When merge the codes, ADXL345 reading okay (not plug in MicroSD Adapter). Pin should bo okay.
Every time MicroSD is plugged (the same pin working with above code), ADXL345 reading suddenly becomes 0g, 0g, 0g. Pull it out then reading is good.
See https://forum.arduino.cc/index.php?topic=360718.0 and not sure if this is due to a hardware defect on MicroSD Adapter.
Already read many post like https://forum.sparkfun.com/viewtopic.php?f=14&t=38072 and the code produce 0g result, too.
Is it purely a hardware problem? Anyone suggest another one?
Is there any way to fix in software?
More details: I am using Nodemcu v1. and arduino library. The connected pins for SD and ADXL345 both at HSPI pins. I understand Nodemcu has another SPI (or even for SD card (SD0, SD1, ...etc), but I did not see any example by using those two and integrate with ADXL345 on HSPI.

You may have the same problem as my answer in Multiple SPI device answer ... not all devices supports another SPI device on the same port
That is (one of the) reasons I use STM32 instead of Arduino, since the Arduinos have 'only' one SPI port.

And one of the many reasons I use PIC32 instead of Arduino ;)

I actually use Nodemcu, but coding on Arduino library, not lua. And YES, I did use the MicroSD card adapter mentioned your link. It does not work with other SPI device. I will try the other SD Recorder (the bigger one) and I can take a look at STM32 and PIC32.

I found some other posts stating about this type of micro sd card adapter has a design flaw.

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


text:
MAX7219 with Arduino UNO - LED control doesn't work
I'm very new to Arduino and this is my first project, so I may misunderstand something simple.
As a hardware I'm using 4 MAX7219 connected to Arduino UNO and a single diod for tests.
As a software I have Waoyda's LedControl 1.06 for MAX72XX.
It seems, I'm completely missing something, because with the code below, the diod is never lit, regardless on matrix position it is connected to.
#include "LedControl.h"

LedControl lc=LedControl(12,11,10,4);

void setup() {
  int devices=lc.getDeviceCount();
  for(int address=0;address<devices;address++) {
    lc.shutdown(address,false);
    lc.setIntensity(address,8)
    lc.clearDisplay(address);
  }
}

void loop() {
  int devices=lc.getDeviceCount();

  for(int row=0;row<8;row++) {
    for(int col=0;col<8;col++) {
      for(int address=0;address<devices;address++) {
        lc.setLed(address,row,col,true);
      }
    }
  }
}

Some high res photos: 1, 2, 3
UPD: scheme added.

OK, I'll ask the stupid question first.  No offence intended but have you plugged the LED in the right way around?  Secondly can you by pass the chip and provide power to the row and columns and see the LED light?  Are you connecting this to a separate power supply (I doubt the Arduino will run it) and if you are using a separate PSU have you connected the grounds?

@CodeGorilla If I use one of the default examples, "07.Display > RowColumnScanning", then the diod is being lit on every position. So, it seems, everything is fine with the diod, board and power.

Could you show us your wiring?

Add some debugging to the code. The way to do it is using the serial port and print out result like "int devices=lc.getDeviceCount();" so you can verify that it find the MAX chip(s). A god tutorial on serial: http://www.oxgadgets.com/2011/07/arduino-serial-communication.html

@tuskiomi added scheme

@MatsK lc.getDeviceCount(); shows 4.

OMG, the only problem was a typo in LedController initialisation! I used LedControl lc=LedControl(12,11,10,4); instead for LedControl lc=LedControl(11,12,10,4);. It seems the library has no error detection if passed data pin isn't really a data pin. Now everything works fine.

please give credit to those that supported you to find a solution.

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


text:
Wifi with ESP8266 and Arduino sketches
I have a NodeMcu Lua ESP8266 ESP-12E which i want to use to control to a relais via Wifi network.
The first step was to write an Arduino Sketch which scans networks and connects to the network. However, even the standard example from the examples menu didn't work (c.f.,https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/examples/WiFiScan/WiFiScan.ino) .
To rule out hardware problems I tried the LUA version from the list API doc (see below), which worked.
 -- print ap list
function listap(t)
      for k,v in pairs(t) do
        print(k.." : "..v)
      end
end

wifi.sta.getap(listap)

Using a firmware build from http://nodemcu.com/index_en.html
I gave the INO version another try and it seemed to work as well. However, it turned out it only works if the previous firmware has been the firmware from http://nodemcu.com/index_en.html
To I need to include a library or something ?
Thanks in advance,
Cafebabe

What is this "std example" you speak of? Also, you're asking us to help you for free but you won't even take the time to type out the full word "standard"? What is this "LUA version" you speak of?

you need to play with arduino esp8266's wifi.disconnect() to make sure the internal wifi settings are correctly initialized, the lua stuff  likely set them in a way that happened to work when you later re-uploaded your C++.

How can I check whether they are correctly initialised? A simple disconnect doesn't change anything. :(

(By googling) I figured out the problem and a work-around. But not an executable solution. The problem seems to be that the RF module is not properly initialised when the device is powered on or awakes from reset.
Sadly there seems to be no manual mode to switch on the RF module.
However, I found a workaround. First I made the connection to enable deep sleep, for that, we need to tie the RST pin to D0/GPIO 16 on the ESP8266.
Then I added the following code to setup
extern "C" {
  #include "user_interface.h"
}

void setup(){
  if (resetInfo->reason != REASON_DEEP_SLEEP_AWAKE) {

      ESP.deepSleep(10, WAKE_RF_DEFAULT)
  }

Basically whenever the system comes into setup from something else than deep sleep, the system goes to deep sleep and when powering back on the RF module is enabled.


text:
Reading states of multiple toggle switches
I'm working on modifying this example from the Arduino website to read the state of 3 toggle (SPDT) switches. If I have one toggle switch hooked up, my sketch works as expected...the sketch will log the state of the switch in the serial debugger every-time the state changes, and only when the state changes.
However, if I add in two more switches, the serial debugger will continuously output my log messages, without detecting if the state has changed.
Here's the code from my sketch:
const int  switchOnePin = 2;    // digital in 2 (pin the switch one is attached to)
const int  switchTwoPin = 3;    // digital in 3 (pin the switch two is attached to)
const int  switchThreePin = 4;  // digital in 4 (pin the switch three is attached to)

int switchOneState = 0;         // current state of the switch
int lastSwitchOneState = 0;     // previous state of the switch

int switchTwoState = 0;
int lastSwitchTwoState = 0;

int switchThreeState = 0;
int lastSwitchThreeState = 0;

void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);

  int switchOneState = 0;         // current state of the switch
  int lastSwitchOneState = 0;     // previous state of the switch switch pins as an input
  pinMode(switchOnePin, INPUT);
  pinMode(switchTwoPin, INPUT);
  pinMode(switchThreePin, INPUT);
}

void loop() {

  // read the switch input pins:
  switchOneState   = digitalRead(switchOnePin);
  delay(50);
  switchTwoState   = digitalRead(switchTwoPin);
  delay(50);
  switchThreeState = digitalRead(switchThreePin);

  // compare the switchState to its previous state
  if (switchOneState != lastSwitchOneState) {
  // if the state has changed, increment the counter
    if (switchOneState == HIGH) {
    // if the current state is HIGH then the button
    // went from off to on:
    Serial.println("Switch one is on");
  }
  else {
    // if the current state is LOW then the button
    // went from on to off:
    Serial.println("Switch one is off");
  }

  if (switchTwoState != lastSwitchTwoState) {
    if (switchTwoState == HIGH) {
    Serial.println("Switch two is on");
  }
  else {
    Serial.println("Switch two is off");
  }

  if (switchThreeState != lastSwitchThreeState) {
    if (switchThreeState == HIGH) {
    Serial.println("Switch three is on");
  }
  else {
    Serial.println("Switch thre is off");
  }
 }
}
  // Delay a little bit to avoid bouncing
  delay(50);
}
// save the current state as the last state,
//for next time through the loop
lastSwitchOneState   = switchOnePin;
lastSwitchTwoState   = switchTwoPin;
lastSwitchThreeState = switchThreePin;
}

And here's what my circuit looks like:

Does anyone have any insight into what I may be doing wrong? I'm not quite sure if it's a circuit or a sketch issue (or both).
EDIT I tried adding a delay of 50ms between each digital input read, but that still did not seem to help the problem.

Not sure this is the entirety of the problem, or if it's just a "transcription" error when you made your circuit diagram, but you've got both sides of your switches connected to +5V. One side should be connected to ground, and the other to +5V.

@AndrewMadsen, yes, that is just a transcription error...thank you for catching that!

A bit off topic: why aren't you using the internal pullup resistors? You could simply connect the input to GND (for logical zero) or leave them open (for logical one, courtesy of the pullup resistor).

@IgorStoppa, I just wasn't aware they could work that way to be honest (still a beginner with Arduino)

I think your {} bracketing got a bit messed up, do you intend to only check the state of switch two if switch one changed?

Sort out the formatting of your program and you should immediately see your error.  This is a good example where proper indenting is vitally important.  Don't get lazy right from the beginning and force yourself to lay your programs out properly. It'll become a good habit to get into.

@BrettAM, that seems like it could be right...I had wanted to check the states of all the switches while the sketch is running.

@BrettAM That said, I'm not quite seeing where my bracketing has broken down.

The problem was two pronged---both the copy/paste error that @Gerben pointed out, as well as the incorrect if-else statements that @BrettAM pointed out. Below is the working code:
const int  switchOnePin = 2;    // digital in 2 (pin the switch one is attached to)
const int  switchTwoPin = 3;    // digital in 3 (pin the switch two is attached to)
const int  switchThreePin = 4;  // digital in 4 (pin the switch three is attached to)

int switchOneState = 0;         // current state of the switch
int lastSwitchOneState = 0;     // previous state of the switch

int switchTwoState = 0;
int lastSwitchTwoState = 0;

int switchThreeState = 0;
int lastSwitchThreeState = 0;

void setup() {
    //initialize serial communication at 9600 bits per second:
    Serial.begin(9600);

    int switchOneState = 0;         // current state of the switch
    int lastSwitchOneState = 0;     // previous state of the switch switch pins as an input
    pinMode(switchOnePin, INPUT);
    pinMode(switchTwoPin, INPUT);
    pinMode(switchThreePin, INPUT);
}

void loop() {
    // read the switch input pins:
    switchOneState   = digitalRead(switchOnePin);
    switchTwoState   = digitalRead(switchTwoPin);
    switchThreeState = digitalRead(switchThreePin);

    // compare the switchState to its previous state
    if (switchOneState != lastSwitchOneState) {
        // if the state has changed, increment the counter
        if (switchOneState == HIGH) {
        // if the current state is HIGH then the button
        // went from off to on:
            Serial.println("Switch one is on");
        } else {
            // if the current state is LOW then the button
            // went from on to off:
            Serial.println("Switch one is off");
        }
    }

    if (switchTwoState != lastSwitchTwoState) {
        if (switchTwoState == HIGH) {
            Serial.println("Switch two is on");
        } else {
            Serial.println("Switch two is off");
        }
    }

    if (switchThreeState != lastSwitchThreeState) {
        if (switchThreeState == HIGH) {
            Serial.println("Switch three is on");
        } else {
            Serial.println("Switch thre is off");
        }
    }

    // Delay a little bit to avoid bouncing
    delay(50);

    // save the current state as the last state,
    //for next time through the loop
    lastSwitchOneState   = switchOneState;
    lastSwitchTwoState   = switchTwoState;
    lastSwitchThreeState = switchThreeState;
}

lastSwitchOneState   = switchOnePin;
lastSwitchTwoState   = switchTwoPin;
lastSwitchThreeState = switchThreePin;

should be
lastSwitchOneState   = switchOneState;
lastSwitchTwoState   = switchTwoState;
lastSwitchThreeState = switchThreeState;

That's definitely part of the problem; so I did mark it up. Thank you! Still only able to read the result of switch one though.


text:
Arduino Ethernet Client crashes after obtaining values from string
My Ethernet server keeps crashing after pulling the RGB values from the string. It remains connected if I'm just toggling a pin, but whenever the string has the rgb values in it, the RGB values are pulled, the LED changes but then the server crashes and won't take any more requests. Do I need to restart the server after it plucks the RGB values for another read? If so, how would I go about doing this?
Thanks, James :)
Example HTTP request that causes the crash: /?LED=B233+G011+R133&t=T HTTP/1.1
    #include <SPI.h>
    #include <Ethernet.h>
    #include <string.h>

    byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
    byte ip[] = {192, 168, 0, 102 };
    byte gateway[] = {192, 168, 0, 1 };
    byte subnet[] = {255, 255, 255, 0 };
    EthernetServer server(84);
    ;

    char* redstring={0};
    String blue1;
    String green1;
    String red1;
    String testString = "0123456789";

    int blue;
    int green;
    int red;
    int been=0;
    int b=0;
    int g=0;
    int r=0;
    //////////////////////

    void setup(){

    pinMode(11, OUTPUT);
    pinMode(9, OUTPUT);
    pinMode(7, OUTPUT);
    pinMode(6, OUTPUT);

    //start Ethernet
    Ethernet.begin(mac, ip, gateway, subnet);
    server.begin();

    //enable serial data print
    Serial.begin(9600);
    Serial.println("SERVER RUNNING HTTP / GET");
    }

    void loop(){
     ////////////////////////////////////////
     EthernetClient client = server.available();
if (client) {
while (client.connected()) {
  if (client.available()) {
    char c = client.read();

    //read char by char HTTP request
    if (sizeof(redstring) < 100) {

      //store characters to string
      redstring += c;
      //Serial.print(c);
    }

    //if HTTP request has ended
    if (c == '\n') {

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

      Serial.println(redstring);

      client.println("HTTP/1.1 200 OK");
      client.println("Content-Type: text/html");
      client.println();
      client.println("");
      client.println("<link rel=\"shortcut icon\" href=\"data:image/x-icon;,\" type=\"image/x-icon\">");
      client.println("");
      client.println("<TITLE>Arduino GET</TITLE>");
      client.println("");
      client.println("");

      client.println("
HTML GET
");
      //change ip back if not local
      client.println("<FORM ACTION=\"http://192.168.0.102:84\" method=get >");

      client.println("JQUERY: <INPUT TYPE=TEXT NAME=\"LED\" VALUE=\"\" SIZE=\"25\" MAXLENGTH=\"50\">
");

      client.println("<INPUT TYPE=SUBMIT NAME=\"t\" VALUE=\"T\">");

      client.println("</FORM>");

      client.println("
");

      client.println("");
      client.println("");

      delay(1);
      //stopping client
      client.stop();
      /////////////////////
      //readString = Character.toUpperCase(readString);
      for (int i = 1; i < sizeof(redstring); i++) {
        if (strchr(redstring, 'B') && && redstring[i+1] > -1) {
          blue=redstring[i+1, i+4];
          analogWrite(11, blue);
          delay(1000);
                      }

        if (strchr(redstring, 'G') && redstring[i+1] > -1) {
          green=redstring[i+1, i+4];
          analogWrite(9, green);
          delay(1000);
                      }

        if (strchr(redstring, 'R')&& redstring[i+1] > -1) {
          red=redstring[i+1, i+4];
          analogWrite(7, red);
          delay(1000);
                      }

      }

      //clearing string for next read
           redstring="";
          (redstring, "0", sizeof(redstring));
        }
      }
    }
  }
}

When you compile this program with Arduino IDE, what does it tell you about the amount of memeory used? It looks your program uses a lot of SRAM and it may quickly happen that memory gets exhausted during runtime.

It complies fine and just says the typical: Binary sketch size: 16,688 bytes (of a 258,048 byte maximum). It only appears to crash when I use RED, blue and green are fine and I can execute it as many times as I want, as soon as it finds red it crashes.

It seems you have an Arduino Mega, right? When I was talking about memory, I was referring to SRAM (data), not Flash (code). This is where you can have an issue (8KB limit on Mega). But more improtant: avoid using String as it is a source of this kind of crashes, due to memory heap fragmentation.

Yeah, I'm using the Mega.
How would I check the SRAM usage?
Hmm, what would you suggest using except string? Or would you suggest doing this another way?

Arduino IDE shows the amount od SRAM used for data after compilation. I got it on 1.5.7; I'm not sure this also works on 1.0.5 though.

I have tried compiling your program on my own Aduino IDE 1.5.7 for Arduino MEGA; it claims 946 bytes are used for SRAM (11% of 8K available on Mega). Normally that should be enough, but I think those String variable definitely make the difference (they use dynamic memory allocation / deallocation, which can quickly lead to heap fragmentation). In general it is preferrable to use C string style, i.e. char* or char xxx[SIZE], and stick with standard C string functions like strchr, strstr or strtok for what you do.

Ah, okay! Thank you so much for your help! I'll give that a go! :)

It's still crashing even when using char instead of string. As soon as it reads and sets the 3 colours, it crashes. This also happens if it reads and sets two numbers, the first is fine and the second causes it to crash.

Could you edit your question and add the following info: example HTTP request that makes the program crash. Also you say chaging String to C string style still has issues, could you please add the updated program with C-strings to your post? I ask because using C string style is not as straightforward as String and if not done properly can lead to crashes (but here, those are due to programming errors, not memory exhaustion).

Changing String into char* won't do the trick, there is much more rework required than that; sicne we start to have many comments I think I will post that as an answer.

As a first order approximation, redstring += c; does not do anything you want it to.

Using String, which uses dynamic allocation/deallocation on the heap is not advised in embedded platforms, as this can quickly lead to heap fragmentation, eventually leading to memory exhaustion, heap/stack collision...
First off, you should try to replace all String usage, everywhere in your program, with C-tyle strings, i.e. char* or char xxx[...] along with dedicated C functions to deal with them: strchr, strstr, strcpy, strcat, strtok, atoi...
Second, you can avoid using global variables and use the stack for many of them.
void loop() {
    ...
    if (client) {
        char readString[101];
        const int READ_STRING_SIZE = sizeof(readString) - 1;
        int readIndex = 0;
        while (client.connected()) {
            if (client.available()) {
                char c = client.read();
                if (readIndex < READ_STRING_SIZE) {
                    readString[readIndex++] = c;
                }

                if (c == '\n') {
                    // Terminate the read string
                    readString[readIndex] = 0;
                    Serial.println(readString);

                    // Prepare for next reeading
                    readIndex = 0;

                    client.println("HTTP/1.1 200 OK");
                    ...
                    client.stop();

                    // convert readString to all uppercase
                    for (i = 0; i < strlen(readString); i++)
                        readString[i] = toupper(readString[i]);

                    bool b = false;
                    bool r = false;
                    bool g = false;
                    int blue, red, green;

                    // Look for 'B' value
                    char* bb = strchr(readString, 'B');
                    if (bb != 0 && isdigit(bb[1]) {
                        blue = atoi(&bb[1]);
                        analogWrite(11, blue);
                        delay(500);
                        b = true;
                    }
                    // Same for 'G' and 'R' value
                    ...
                    if (b && r && g) {
                        Serial.print("CHANGING RED TO: ");
                        Serial.println(red);
                        Serial.print("CHANGING GREEN TO: ");
                        Serial.println(green);
                        Serial.print("CHANGING BLUE TO: ");
                        Serial.println(blue);
                    }
                }

                if (strstr(readString, "PIN6") != 0) {
                    digitalWrite(6, !digitalRead(6));
                    ...
                }
            }
        }
    }
}

In this sample code, we have completely removed dynamic memory allocation.

Thank you so much for all your help!
How would I clear the C-String? It keeps looping and doesn't toggle the pin, rather just makes it flash.

See my edit: I had forgotten to reset readIndex once a whole string has been read. Now it should work properly.

ah okay, thanks!
Another issue I found is that the code breaks the string when it hit's a 'B' but doesn't get the next 3 numbers, but instead copys the http request from the string and tries to make it an int and set the LED, but it just returns a 0. How would I replicate the blue = redstring[i + 1, i + 4]; (to get the 3 numbers after the 'B' like mine?)

Oops, my mistake, see my edit: atoi(&bb[1]) instead of atoi(bb).

Ah okay, thank you!
The same issue is occuring, as soon as I pass three colours, the server disconnects and won't take any more requests. Could this be a problem with the way I have set my server up?

I checked my code and realised it wasn't exactly like your example, with the help of your example I can now do multiple colours but as soon as I switch on PIN6 after setting the RGB LED, it crashes again.

Before we go further, could you clarify the "it crashes" statement. It would be useful to know if the MCU really crashes (eg memory problems) or if the program is in an infinite loop, in the latter case it would be useful to know exactly where this loop is.

I'm not exactly sure what the issue is, the webpage will become unresponsive and the lights indicating the Ethernet connection turn off. From what I have tested from the serial monitor, it appears the program is not looping but unexpectedly quitting. Furthermore, each statement (PIN6 & RGB) can be repeated infinitely as long as I don't mix the two statements and only execute one or the other.

I would suggest to ask another question with the latest code you have, and detail the observed problem, otherwise it will become very difficult to follow this Q&A thread. You can refer to this question from the new one just so that people can get some context about previous discussions if they want to.


text:
Native function name w/o parens -- expected behavior?
I wrote a sketch that used the millis() function in several places. I got odd behavior because I inadvertently used the plain millis in one line, without the parens. It evaluated to zero when running.
Why didn't the compiler flag this as an undeclared variable? I suspect it's because the name was already in the symbol table, but I still would have thought it'd be caught. Is this a quirk, or expected? If expected, what is the benefit?
C/C++ is not my main language so be gentle. (-:
Edit as requested to show some code. This is an incomplete sample, but shows the usage:
const unsigned long GATE_OPEN_TIMER = 7000;
const unsigned long GATE_CLOSE_TIMER = 12000;
...
unsigned long gateStopTime = 0;
...

  if (isGateCycling) {                 // if open/close cycle is running
    if (isGatePassive) {               // if we're not applying power
      if (millis() >= gateStopTime) {  // if current delay expired
        digitalWrite(GateCloseRelay, ACTIVE);
        gateStopTime = millis() + GATE_CLOSE_TIMER;
        isGatePassive = false;

... followed by similar logic for the reverse direction. If any use of millis() is replaced by millis, the code falls over but the compiler sees nothing wrong.

When you say you "used" millis - can you post the code? A line like this generates a compiler error: int foo = millis; The error is invalid conversion from 'long unsigned int (*)()' to 'long unsigned int'

Not sure how to format code in a comment, but.. basically the use is future = millis() + delay followed later by if millis >= future

Edit the question and put the code there, please using the code formatting markdown (four leading spaces). For help see Markdown help. You should be able to do this by selecting the code and pressing Ctrl+K to have your browser do this for you. That if statement doesn't look valid anyway.

Don't just post the line, post enough code to reproduce it (ie. that compiles without errors). For example, what type is future?

Many compilers will actually produce a warning for this.

I can't reproduce what you say is happening. For example on your posted line (removing the brackets) gateStopTime = millis + GATE_CLOSE_TIMER; I get the error: error: invalid conversion from 'long unsigned int (*)()' to 'long unsigned int'

And on if (millis >= gateStopTime) I get the error: error: ISO C++ forbids comparison between pointer and integer

@NickGammon  What can I say? Are we using different versions of the IDE (1.6.12 here)? Are there compile options I'm not seeing? I guarantee that it acts exactly as I describe it and not at all as you describe it, in my setup, which is stock out of the box. The program is short enough that I can post the entire thing if you think that will help.

Yes it will. And I can try that exact IDE. I compiled under 1.6.9 but I expect 1.6.12 will be the same. Wait, that's odd! Under 1.6.12 I only get one warning and no errors!  Hmmm - turn warnings up a bit in the preferences. Mine are at "default"

I've made up a test case:
const unsigned long GATE_OPEN_TIMER = 7000;
const unsigned long GATE_CLOSE_TIMER = 12000;
unsigned long gateStopTime = 0;

void setup()
{
  if (millis >= gateStopTime) {  // if current delay expired
    gateStopTime = millis + GATE_CLOSE_TIMER;
  }
}
void loop()
{
}

Under IDE 1.6.9 I get these errors:
/tmp/arduino_modified_sketch_345879/sketch_oct27a.ino: In function 'void setup()':
sketch_oct27a:7: error: ISO C++ forbids comparison between pointer and integer [-fpermissive]
   if (millis >= gateStopTime) {  // if current delay expired
                 ^
/tmp/arduino_modified_sketch_345879/sketch_oct27a.ino:8:29: warning: pointer to a function used in arithmetic [-Wpointer-arith]
     gateStopTime = millis + GATE_CLOSE_TIMER;
                             ^
sketch_oct27a:8: error: invalid conversion from 'long unsigned int (*)()' to 'long unsigned int' [-fpermissive]
     gateStopTime = millis + GATE_CLOSE_TIMER;
                           ^
exit status 1
ISO C++ forbids comparison between pointer and integer [-fpermissive]

Under IDE 1.6.12 they are downgraded to warnings:
/tmp/untitled109152362.tmp/sketch_oct25b/sketch_oct25b.ino: In function 'void setup()':
/tmp/untitled109152362.tmp/sketch_oct25b/sketch_oct25b.ino:9:21: warning: ISO C++ forbids comparison between pointer and integer [-fpermissive]
       if (millis >= gateStopTime) {  // if current delay expired
                     ^
/tmp/untitled109152362.tmp/sketch_oct25b/sketch_oct25b.ino:10:33: warning: pointer to a function used in arithmetic [-Wpointer-arith]
         gateStopTime = millis + GATE_CLOSE_TIMER;
                                 ^
/tmp/untitled109152362.tmp/sketch_oct25b/sketch_oct25b.ino:10:31: warning: invalid conversion from 'long unsigned int (*)()' to 'long unsigned int' [-fpermissive]
         gateStopTime = millis + GATE_CLOSE_TIMER;
                                   ^

Sketch uses 512 bytes (1%) of program storage space. Maximum is 32,256 bytes.
Global variables use 13 bytes (0%) of dynamic memory, leaving 2,035 bytes for local variables. Maximum is 2,048 bytes.

So, the compiler isn't totally letting you get away with it. You should check the warnings. But why are the warnings only warnings?
Checking the generated compile command (using verbose compiling) I see that 1.6.12 has an extra option: -fpermissive.
From the documentation:

Downgrade some diagnostics about nonconformant code from errors to warnings.  Thus, using -fpermissive allows some nonconforming code to compile.

So you have "nonconformant code" but you are getting away with it.
I don't know why the Arduino devs did that. The whole point of making things like that errors is so you fix them at compile time, rather than scratching your head about why things don't work at run time.
Clearly the symbol millis exists. But it is a function (or perhaps a pointer to a function) and thus shouldn't be just compared to a number or have a number added to it. That's what those errors were about in 1.6.9.

Just remember, in C, C++ and the ilk, to call a function you always use parentheses, even if you are passing no arguments.

This is shocking! Why on Earth would they add -fpermissive? Maybe the core wouldn't compile without that?

Maybe. But you would think they have had time to fix that sort of stuff. I can't see an easy way of turning it off either. For newbies they are going to get code that compiles, but fails at runtime in obscure ways. Better to fail at compile time.

Seems that this kind of errors where reported as warnings by old versions of gcc, and the -fpermissive flag was added in order to avoid build errors on old libraries, effective since Arduino 1.6.10. This has already been reported as an issue.

@NickGammon  Thanks for the detective work. I knew I wasn't crazy . I had warnings turned up all the way and I still saw nothing at all. If you'd like my sketch I can post it somewhere, but at 3K bytes stripped it's probably too big to include here...? (And fwiw I'm not trying to "get away" with something, I made a typo that I still feel should have been flagged.) One puzzle to me is still why this isn't seen as an undeclared variable, or as a failure to call with (). Is it the case that in C++ a function name without () is a useful thing, seen as a pointer?

@JimMack: Exactly. A function identifier without () decays into a pointer to the function.

I'm surprised you got no warnings. I did, as I posted above. I didn't mean "get away with" in the sense that you were trying to get away with things - you made a simple error, and the compiler let you. :) As for functions as pointers, see Function pointers / function callbacks / function variables

In short, a function in an Arduino program that gets called without () will be considered as a plain variable. Try writing a small function in your program and call it without (). Nothing will happen.
The reason the compiler didn't flag it as an undeclared variable was because millis is a variable that is declared in a kind of pre-loaded library. Think of it as a library that is always there even if you didn't include it. That is why the compiler only saw it as a regular variable.

Is there really a variable named millis in the arduino core, or is it referring to the function pointer?

It's reffered to the function pointer but a function called without () will be seen as a previously declared variable even though it was declared as a function.

@canadiancyborg  So the situation is what I surmised -- it's not seen as undeclared because its name is already in the symbol table for another reason? Still, the question remains: what's the benefit of this compiler behavior-- when would it be useful? Shouldn't it be flagged?

It is flagged as an error when I try to reproduce it. The compiler isn't stupid.

millis is a variable that is declared in a kind of pre-loaded library - you are making this stuff up. It isn't a variable, it is a function. You might more accurately call it a symbol. Whether or not it is in a library is not relevant.

@NickGammon I tried to compile a program with something like int x = millis, worked fine.

'millis', without parens, is the address of the function of that name. It is properly declared; it was merely improperly used. Without parens, millis on the right hand side of an '=' evaluates to the memory address of the millis() function. Either use of the symbol (with or without parens) is valid. What was invalid was the context of use - note that the error messages were about illegal conversions or comparisons of different data-types (function pointer to long int), not about undefined symbols (which it isn't).

I tried to compile a program with something like int x = millis, worked fine. - what is the warnings level in your IDE preferences?

@NickGammon, default.

Which version of the IDE?

@NickGammon, 1.6.12 (downloaded from Arduino.cc)

I tried to compile a program with something like ... - I would be interested to see the actual code, not a vague description of it.


text:
Not able to convert String to Integer when receiving data from pubnub?
I did managed to upload mpu9250 sensor data on PubNub and nodeMcu but not able to use the received data to control servo
Look at the Port reading and see that servo angle is still showing '0'

Code:-
IMU.readSensor();
char buf[500] = {};
int imu = IMU.getAccelX_mss() * 10;

sprintf(buf, "\"%d\"", imu);

Serial.print(buf);

PubNonSubClient *pclient = PubNub.publish(pubchannel, buf);
if (!pclient) return;
PublishCracker cheez;
cheez.read_and_parse(pclient);

/** You're mostly interested in `outcome()`, and,
    if it's "failed", then `description()`.
*/

Serial.print("Outcome: "); Serial.print(cheez.outcome());
Serial.print(' '); Serial.println(cheez.to_str(cheez.outcome()));
Serial.print("description: "); Serial.println(cheez.description());
Serial.print("timestamp: "); Serial.println(cheez.timestamp());
Serial.print("state: "); Serial.print(cheez.state());
Serial.print(' '); Serial.println(cheez.to_str(cheez.state()));
Serial.print("IMU Reading: "); Serial.println(IMU.getAccelX_mss());

pclient->stop();

/* Wait for news. */
PubSubClient *sclient = PubNub.subscribe(subchannel);
if (!sclient) return; // error
String msg;
SubscribeCracker ritz(sclient);
while (!ritz.finished()) {
    ritz.get(msg);
    if (msg.length() > 0) {
        Serial.print("Received: "); Serial.println(msg);
        pos = msg.toInt();
        Serial.print("value of servo angle: "); Serial.println(pos);
        myservo.write(pos);
    }

}
sclient->stop();

delay(1000);

How do I convert a string to integer so that it can be used in servo?

Hint: Might need to remove the extra characters ("..") before converting from a string to an integer.

oh yes, let me try it

This is the code which worked for me:-
        msg.remove(0,1); msg.remove(msg.length());
        pos = msg.toInt();
        Serial.print("value of servo angle: "); Serial.println(pos);
        myservo.write(pos);

I had to remove this character (" ") by using msg.remove(0,1) & msg.remove(msg.length()) that removes starting and ending string.

cleaner: msg.trim(); Serial.println("value of servo angle:" + String(msg.toInt());

nice, much better

but msg.trim() didn't work

it's a void mutative method in ardunio, not a transformer like in other languages.


text:
How to control segway motor with arduino uno?
I salvaged segway motor with 8 wires. I did completed basic connection of 5 hall sensors and power from 36V lipo battery in the image  below. When I connect self-learning wires then motor starts rotating so connecting must be right. So now how do I control the motor with arduino?
Controller is kkmoon motor regulator 350W - link
didn't find datasheet about motor but here are some Information:-
Type: BLDC Motor
Voltage: 36V
no of wires:- 8 (3 wires  for 3 phase, 5 for hall sensor)
Power:- 300W

please provide a link to the motor datasheet

didn't find datasheet but posted some basic information above.


text:
can't interface SIM900 GSM Module with Arduino Mega
I am trying to interface SIM900 GSM Module with Arduino Mega. When I send AT command on COM port in carriage mode then its not sending 'ok' back so I think the interface is not successful. Here is the resource which I referred to - Link.
Have a look below:-
Code:-
#include <SoftwareSerial.h>     //please put less than and greater than sign respectively in place of  =

SoftwareSerial SIM900(10, 11); // (RX, TX). please zoom image above to see exactly what is going where.

void setup()
{
  SIM900.begin(19200);               // the SIM900 baud rate
  Serial.begin(19200);

}

void loop()
{

  if (SIM900.available())              // if date is comming from softwareserial port ==> data is comming from gprs shield
  Serial.write(SIM900.read());
  if (Serial.available())                // if data is available on hardwareserial port ==> data is comming from PC or notebook
  SIM900.write(Serial.read());

}

Electric Connection:-

How to interface it correctly?
Update:- I added a 5v 2A power supply and changed Arduino Rx/Tx pin to 10/11. Added micro sim at the back but still the same result

You can not power it over the Arduino. The module need up to 2A. The Arduino will never be able to give you all this power. Probably also your USB is not able to do it if connected to a PC.

I suspected so. Thanks, will try it. I thought without sim it will draw less power.

I added a 5v 2A power supply and changed arduino Rx/Tx pin to 10/11. Added micro sim at the back but still the same result

Are the jumpers on the right position? Are you using CR as end line? Is 19200 the right baud rate? Is GND connected correctly? Check this tutorial: https://randomnerdtutorials.com/sim900-gsm-gprs-shield-arduino/

did all other, what is CR as end line?

Carriage Return. Some times only LF (Line Feed) is sent.


text:
Arduino Nano ESP8266 software serial problems
I have a problem with my Arduino Nano ATmega328 and my ESP8266 01 module. I have connected the ESP8266 on my Arduino board without FTDI.
I have made the following connection:
I an using a 5V Arduino Nano which of course is 5V. The ESP8266 is a 3.3V device and so I am using a voltage divider to bring the Arduino's 5V down to 3.3V. If you are using a 3.3V Arduino then you do not need the voltage divider.

The wiring is very similar to the FTDI.
Arduino pin 3 to voltage divider and then to ESP8266 RX
Arduino pin 2 to ESP8266 TX
Arduino GND to ESP8266 GND
Pull CH_PD HIGH with a 10K resistor to +3.3V
+3.3V to Vcc

You only need the voltage divider on the Arduino TX pin. The 5V Arduino will read 3.3V as HIGH so you can connect the ESP8266 TX pin directly to the Arduino RX pin.
The problem I had and I can't handle is that when I start up the Arduino Tx and Rx LEDs work continuously so I can't have access to my serial monitor of the Arduino IDE. So with that problem I can't send or receive any command to/from the IDE. Also when I try to upload my program to the Arduino board, I have to disconnect the ESP. If I don't I can't upload it.
Any ideas guys? I would be grateful

I also try to implement code with AltSoftSerial but I have library issues - my laptop does not recognize it (I downloaded it and I put it in the same folder with my code).
  #include <SoftwareSerial.h>

    SoftwareSerial ESPserial(2, 3); // RX | TX
    void setup()
    {    Serial.begin(9600);     // communication with the host         computer

     // Start the software serial for communication with the ESP8266
     ESPserial.begin(9600);

     Serial.println("");
     Serial.println("Remember to to set Both NL & CR in the serial monitor.");
     Serial.println("Ready");
     Serial.println("");}

     void loop()
      {
      // listen for communication from the ESP8266 and then write it to the serial monitor
       if ( ESPserial.available() )   {  Serial.write( ESPserial.read();}  / / listen for user input and send it to the ESP8266
      if ( Serial.available() )       {  ESPserial.write( Serial.read()  );  }}

Well, what did you expect? It seems you're using the same serial port for the PC and the ESP-01. Isnt SoftwareSerial a built-in library?

Yes. Is there anyway to resovle this? I was able to found some solutions using an extra software serial but nothing happened. I am still unable to resolve this.

Post your code.

i have tried different codes but the basic one is the one below :

You say the TX and RX leds onboard blink whenever you send stuff from the serial monitor? Did u set the monitor to "Both NL & CR"? How are u powering the ESP?

Please use the Post answer button only for actual answers. You should modify your original question to add additional information.

I am powering the ESP directly from arduino as i shown above. As i mentioned i am can t send any commands. I have written the reactions i see on arduino and esp ( i also see the blue led of esp blinking --> so the esp try to  send/receive ) . I also put my code above to see what exactly i am trying to do .

Arduino Nano has its tx-rx serial port shared with the FTDI chip used by downloading and serial console. See https://www.arduino.cc/en/uploads/Main/ArduinoNano30Schematic.pdf
This means that if you drive these pins from ESP, it will flash leds, and all communication on these pins will interfere with serial monitor and board programming as well.
You may:

disconnect ESP during program downloading
pick a different board, which has a separate hardware serial port, such as Arduino Micro, Leonardo, or any Pololu A-star 32u4 boards, this way you have a dedicated serial port to control your ESP
wire the tx-rx of ESP to two other pins of your Arduino micro, and use a software serial library to bit-bang serial communication. (Note that serial receiving in software mode may require clever programming - since while your code does something else it can not receive anything).

Basically I ve connected my esp8266 to an ftdi 3.3V logic and it helped my resolve my problems i had. I also use a command to change my esp baudrate to 9600 from 115200. Then i connect my esp back to arduino nano and everything works fine :) ( I think ftdi is the most easy way to get started with an esp module. )

authors: Μάριος Μιχαήλ


text:
Fastest way to test if two integers differ by 4 or equal to each other
I'm searching for the fastest way to test if two integers are equal or differ by 4. The integers can be positive, negative and equal to zero. They are between -1000 and 1000 and are exclusively multiples of 4.
The simplest approach to test this should be this:
if(x == y || x - y == 4 || x - y == -4)
{
     //do something...
}

But since I want to do this 4 times inside of a interrupt sub routine I wanted to know if there is a faster way to do this.

The fastest way could depend on the frequencies of the cases.  You could try using some bit operations to take the absolute value, divide it by 4 (>>2) and then branch on it being one or less.

A search to "the fastest way" would never give you a solid result. You could use a faster microcontroller almost endlessly attempt to optimalize. Check the requirements you need rather than searching for "the best"

Maybe you can do something fancy with the bit patterns. If you XOR them, it might give the difference between your value and the other. It can then be 0b00000000 or 0b00000100 but why steps of 4 if 4 more or less doesn't matter?

If you need to do the same comparison 4 times you can just put the result into a boolean variable.
boolean b = (x == y || x - y == 4 || x - y == -4)

if( b )
{
     //do something...
}

If you are talking about optimizing the actual code, I shouldn't worry about it. The compiler is already pretty good at this. Here is the assembler code for it.
void test(int x, int y)
{
    if(x == y || x - y == 4 || x - y == -4)
  a8:   86 17           cp  r24, r22
  aa:   97 07           cpc r25, r23
  ac:   39 f0           breq    .+14        ; 0xbc <_Z4testii+0x14>
  ae:   86 1b           sub r24, r22
  b0:   97 0b           sbc r25, r23
  b2:   84 30           cpi r24, 0x04   ; 4
  b4:   91 05           cpc r25, r1
  b6:   11 f0           breq    .+4         ; 0xbc <_Z4testii+0x14>
  b8:   04 96           adiw    r24, 0x04   ; 4
  ba:   09 f4           brne    .+2         ; 0xbe <_Z4testii+0x16>
    {
        asm ("wdr");
  bc:   a8 95           wdr
  be:   08 95           ret

first it compare the two values x and y. Then is subtract y from x and compares it with 4. After that it gets the subtracted value from the previous step; adds 4; and check if it is 0.
EDIT
As to Dave X's suggestion; using if(abs(x-y)<=4)
void test(int x, int y)
{
    if(abs(x-y)<=4)
  a8:   86 1b           sub r24, r22
  aa:   97 0b           sbc r25, r23
  ac:   04 96           adiw    r24, 0x04   ; 4
  ae:   09 97           sbiw    r24, 0x09   ; 9
  b0:   08 f4           brcc    .+2         ; 0xb4 <_Z4testii+0xc>
    {
         asm("wdr");
  b2:   a8 95           wdr
  b4:   08 95           ret

So half the number of instructions needed. But as Paul said, this might not the fastest. This code always takes 5 instructions, while the previous code will only take 3 instructions if x==y. So if 90% of the time x==y, the previous code will be faster 90% of the time.
As to the assembler code, you can see how clever the compiler is. It first subtracts y from x. Then it adds 4. If -4 <= x-y < 0 the carry bit is set. Then it subtracts 9 (so it's like (x-y)-5 because of the previous +4). If 0<= x-y <= 4 the carry bit is set. It then check if the carry bits is set by either of the last to instructions. Pretty clever.

(I just learned how to view the assembly code with an avrdump -S on the .elf file).   Maybe if(abs(x-y)<=4) would be a quicker, equivalent test.  It is interesting to see how the compiler optimizes that.

@DaveX We have a winner. I did't think that one would be faster.

avr-objdump has the -C option to demangle C++ symbols. It makes nicer looking assembly listings.

test if two integers are equal or differ by 4

And

are exclusively multiples of 4.

That would mean that when a=20, b should be 16, 20 or 24. (But can't be 17, 18, 19, 21, 22 or 23)
But you should check the most unlikely statement first. If it's likely to be well above x+4, check that first, if it's false, it'll just stop.
Ultimately you only have to check if it's less than x=y+4 or higher as x=y-4, this automatically includes x=y.
So checking if it's the same (which might be unlikely, might be redundant. Unless there is a very high chance of that being true.

"Checking if its less than x = y + 4 or higher as x= y-4"? You might want to clarify

If it can be either 24, 28 or 32 (with steps of 4) you only have to check <33 and higher as 23> that will automatically include the check if it's 28. But is only valid with the steps of 4 rule


text:
Running both sensor and addressable LED strips at a same time?

I'm trying to obtain the sensors' readings as well as making the LED strips to light up at this particular pattern, if the sensor readings reaches certain values. But since both of these codes are inside the void loop(), there will be a problem. How can I do this correctly?
void loop()
{
    currentSensorReading = analogRead(sensorPin);
    Serial.println(currentSensorReading );

    if(currentSensorReading is in range of certain values){
        rainbowCycle(20);
    } else { turn LEDs off }
}

void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

Cross-posted on Arduino Forum

Rewrite without using delay(). Or alternatively, do the test inside the for loop as well, eg.
void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
    delay(wait);

    // ----------- ADD THESE THREE LINES ---------------
    currentSensorReading = analogRead(sensorPin);
    if(currentSensorReading is NOT in range of certain values)
        return;

  }
}


text:
how to solve Varing duty cycle value while using Pulsein()
Well im new to coding, but i do have the basic knowledge.
I'm using an UNO to measure a duty cycle.
The source of pulse is a Tektronic signal generator (Duty cycle set to 50.000 with frequency of 2khz).
my code is as follows,
byte PWM_PIN = 3;
float pwm_value_H;
float pwm_value_L;
float D;

void setup() {
    pinMode(PWM_PIN, INPUT);
    Serial.begin(115200);
}

void loop() {
    pwm_value_H = pulseIn(PWM_PIN, HIGH);
    Serial.println(pwm_value_H);
    pwm_value_L = pulseIn(PWM_PIN, LOW);
    Serial.println(pwm_value_L);
    D = ((pwm_value_H) / (pwm_value_H + pwm_value_L)) * 100.0;
    Serial.print("D=");
    Serial.println(D);
    Serial.print("D=%");
}

but the problem is that my output value of "D" keeps on varying between 49.71, 49.90, 50.00 and 50.7
Is this because of PULSEIN() function ineffiency?
or can anyone suggest a better way to measure the duty cycle with +/- 0.01 accuracy.
Regards,
Cj

I would start by removing Serial interrupts from the pulseIn period.
void loop() {
    pwm_value_H = pulseIn(PWM_PIN, HIGH);
    pwm_value_L = pulseIn(PWM_PIN, LOW);
    Serial.println(pwm_value_H);
    Serial.println(pwm_value_L);
    D = ((pwm_value_H) / (pwm_value_H + pwm_value_L)) * 100.0;
    Serial.print("D=");
    Serial.println(D);
    Serial.print("D=%");
    Serial.flush();
}

For higher accuracy I would then look to the Timer based Input Capture.
Cheers!

This seems logical. I'll give it a shot and check if the accuracy is meeting my requirements. And by the way, thanks a loads for the reply Mikael

There's two basic things wrong with what you are doing there:

pulseIn() isn't good for very accurate measurements
The signal is still happening while you're doing other things, such as printing the high/low times.

You're not actually measuring the duty cycle of one single cycle, but the HIGH time of one cycle followed by the low cycle of a later one. If you want to do it properly you will have to ditch pulseIn() and instead get your head around interrupts and timestamps.
The basic method is to present the signal to one of the INT pins, and attach an interrupt to that pin with the trigger set to CHANGE.  The interrupt routine you specify will then be triggered every time the signal changes from HIGH to LOW or from LOW to HIGH.
Then the interrupt routine does very little.  It basically records the time the interrupt happened (that must be the very first thing you do), then looks to see if it's a HIGH or a LOW signal on the pin.  You then use the previous timestamp from the last time the interrupt was triggered to work out how long the previous phase lasted and set either a HIGH or a LOW variable depending on the current level of the state (if it's low set a high variable since that was the previous phase level, and if it's high set a low variable) with the time that phase lasted.
Then in your main loop you interrogate those variables periodically to display the duty cycle.
If that still isn't accurate enough then you should look at the hardware Input Capture module built into the MCU. That uses a hardware timer in much the same way as the interrupt but is able to capture a much more accurate time stamp for you since the time stamp is grabbed the moment the signal changes, rather than after a short delay once the interrupt routine has been called.  Details can be found in the datasheet for the MCU on your Arduino.

As i said, im new to coding. I understood what you said, but it is going to take me some time to implement it. And by the way, thanks a loads for the reply Majenko!!


text:
How do I solve the sensor’s abysmal abnormal output?
Problem description
When XIAO microcontroller is connected to the sensor signal output pin, keep printing unexpected values.
Sketch

I haven't sensor circuit diagram, you can machine translate and read the pagehttps://www.yuque.com/cs/products/rwe87o
Detailed description:
The sensor has been outputting a raw value of about 4000. That is to say, the transformation of the function outputs is around  1600000~400000. Not the 0 to 30 values I expected to output.(I tried to use other development board ESP32 to read the sensor value using ADC and its own power supply pin, and still output the original value of 4000(output 1600000~400000), as shown in the figure below.)
Abnormal output

Normal output:

This is the output I expect, but I can't reproduce the normal output (last month was very occasionally normal output, I don't know why it can't normal output now and the environment has not changed...Analog circuits are too much like witchcraft...)
I try to do:

Measured with a digital multimeter to ESP32 and XIAO, the power supply pin(to measure voltage between 3.3V and GND pin) is about 3.1V~3.3V(maybe my positive and negative probes are not accurate).

Check XIAO's ADC using ADC pin to GND pin for any problems with Analog pins read GND and VCC respectively, with 12bit resolution and output of 100 and 4000 + respectively.XIAO is fine.

The Sensor connects the TTL to USB power supply pin, but the output is still abnormal.(I used PWM pin by esp32 or xiao MCU to output analog 3.3V, results  same to abnormal output)

If the sensor signal output is connected to MCU, the high value of 4000 is output(The original value).  Seems to be the power problem, someone tell me how to minimize the power ripple effect and make the 3.3V stable output provided by the battery?
But when I unplug the sensor, the MCU outputs random values, and I don't want the sensor output to be affected by other factors.

DMM Checks the sensor output and GND pin separately, using only the DMM, sensor, 3.3V battery module, and breadboard：
(This is one 3P Dupont line and the colors are random.I didn't have a wiring error. If the wiring is wrong neither the MCU nor the sensor will work properly, let alone output signals)

The quality of my DMM is poor, I will measure it when my FLUKE17B+ arrives.

Use MCU to read the value, sure enough, the output value is not affected by the power on or off, because the output value is more than 100000(raw value is 4000,12 bit).
other
Asked the store, customer service said this is not normal, the sensor should output the value of 0~500, if the sensor monitors the current output of 200~400, not monitoring the general output of 0~30 range.
Equipment information
XIAO EMG sampled code: EMG.ino · GitHub
Sensor parameters: {ED0056}Sensor
Microcontrollers XIAO general description: Getting Started with Seeeduino XIAO - Seeed Wiki
Microcontrollers XIAO instruction manual: https://files.seeedstudio.com/wiki/Seeeduino-XIAO/res/ATSAMD21G18A-MU-Datasheet.pdf

How do I solve XIAO’s the sensor’s abnormal output?

Please add a schematic to your question. It's not at all clear how all the components are interconnected. Have you connected all of the grounds properly?

In your wiring diagram (fritzing) Vcc and ground of the sensor on the right are connected to the upper power rail. Though there is no other connection to that rail. Where does the power and groumd connection come from for the sensor?

Ten days ago, I connected the power supply pin of the USB to TTL module, and it could output normal signals. However, the 3.3V usB-to-TTL pin is only one.

My six sensors need six 3.3V pins, the battery module supplies power to the sensor, but the oscilloscope outputs the original value of the sensor above 4000.

on Leonardo you power it from 3.3 V pin? The analog pins of Leonardo read values from 0 to 5 V and the xiao analog input reads from 0 to 3.3 V

@Juraj The sensor manual indicates that the output analog range is 0 to 3.0V, which is within xiao's range of reception.

could it be that xiao registers only support msb side alignment while arduino defaults to lsb alignment?  could try to check arduino (or any other working setup's readings) vs xiao under same conditions to get to the bottom of it.  or better yet analogRead a pot.

@Abel I used analogread function readings provided by Arduino hardware library without experience in low-level debugging. If the resolution is set to 16bit, the output will be 1000-60000. I tested the analog pins on another development board(ESP32) with the same results. I am now contacting the sensor manufacturer to try to solve this problem. The manufacturer claims that the technicians use the power supply pins provided by the development board,  there is no such problem as mine.

First thing I notice in your photo is that you have your 3.3V and GND wires around the wrong way on the Xiao microcontroller board. This will indeed give you wrong results.
Please see the image below for the pinout.

Your Fritzing circuit diagram has the correct wiring for 3.3V and GND.
Please do a couple of tests to verify your setup once the wiring has been corrected. First, remove the sensor and use a potentiometer to provide an analog input into A0. Verify that the potentiometer gives you the correct response that you expect and cross check it with an oscilloscope or digital multi-meter (DMM).
Secondly, power up only the sensor and test the output of the sensor with an oscilloscope or DMM. This should how up as the clean analog signal that you expect.
If these two tests pass, then when you connect up the sensor to the Xiao microcontroller board it should work as expected.

Hello, not in the wrong direction.  It's just the color of the lines that misleads you. I was misled by its color, the reverse connection short-circuit MCU. (I'll re-upload the picture for you to see.) Yesterday I have tested XIAO with the potentiometer and everything is normal. I think there may be something wrong with the sensor itself. Multimeter to measure voltage between sensor's GND and sensor output is 0.15~0.20V.  Sensor states a reference voltage of 1.5 and then a range of 0 - 3 volts, which made me wonder if it will work correctly with analogRead();

Great to hear that it was wired correctly and that you had just wired it up with red for GND and black for 3.3V. However this is bound to cause confusion which could lead to mistakes. Please perform the tests in the bottom half of the answer to determine if the fault lies with the sensor or the microcontroller.

This is a 3P integrated line, the seller random gift of different colors of the line. There seems to be Abnormal output with the sensor as soon as it is connected any MCU. I am contacting the manufacturer to solve it.Besides, I didn't have a wiring error. If the wiring is wrong neither the MCU nor the sensor will work properly, let alone output signals(These tests were tested yesterday. Unfortunately, it cannot output the desired clean signal)

I don't have an oscilloscope, and the DMM I have is of poor quality. I have placed an order of FLUKE 17B+ online, and I will use it to check the output of the sensor in a few days.

You seem pretty sure it is the sensor, so perform the sensor test, where you only power the sensor and measure the output with a DMM. Even a poor quality DMM will give you enough information to tell if the sensor is fauty or not.

Now it solved. I was so stupid, because I didn't connect the MCU to the sensor power, so the MCU couldn't measure the sensor value with the reference power.