Problems with the library I have written myself, sensors won't read

I am new to Arduino, and I'm having problems with the library I've written myself.

I'm using a Mega 2560, and I'm making something like a floor piano. There are 11 buttons (capacitive sensors). When they are touched, the button will light up, there will be a Serial.println(message) to a computer, and a sound file will be played in Processing.

The light is a long LED strip (Luxorparts "Neopixels"). The first 38 LEDs belongs to the first button, the next 37 to the second button, the next 37 to the third, and so on. The light will stay on for the same duration as the sound file for that button.

I have written a sketch line by line, and it works as it should. However, I would like the code to be OOP, so I wrote my own library. I tried to follow this guide: https://www.arduino.cc/en/Hacking/libraryTutorial

My code compiles, and the sketch is uploaded to my Mega. The blue lights on the cabinet are turned on, and the message "Setup complete" is printed. I have added some printing to my read_sensor method. It prints the button it is currently reading, and it's value. But the value is always 0. When I run my "line by line" code, the value is always somewhere between 5 and 50 when I am not touching it, and 1000-2000 when I am touching it.

Why are my sensors not reading any value at all?

Circle.h

#ifndef Circle_h
#define Circle_h

#include <Arduino.h>
#include <Adafruit_NeoPixel.h>

class Circle{
    public:
        boolean _my_status;
        unsigned long _timer_start;
        int _my_delay;
        int _startLed;
        int _endLed;
	    long unsigned int _color;

        Circle(int my_delay, int startLed, int endLed, long unsigned int color);

        boolean get_status();

        void activate();

        void check_timer();

        int get_start();

        int get_end();

	    long unsigned int myColor();


};
#endif

Circle.cpp

// CLass file for Circle
#include "Arduino.h"
#include "Circle.h"
#include "Adafruit_NeoPixel.h"

    boolean _my_status = false;
    unsigned long _timer_start;
    int _my_delay;
    int _startLed;
    int _endLed;
    long unsigned int _color;

    Circle::Circle(int my_delay, int startLed, int endLed, long unsigned int color){         // constructor
        _my_delay = my_delay;
	    _startLed = startLed;
	    _endLed = endLed;
	    _color = color;
    }

    boolean Circle::get_status(void){
      return _my_status;
    }

    void Circle::activate(void){
        _my_status = true;
        _timer_start = millis();
    }

    void Circle::check_timer(void){
        unsigned long now = millis();
        if (now > (_timer_start + _my_delay)){
            _my_status = false;
     	}
	}

    int Circle::get_start(void){
        return _startLed;
        }

    int Circle::get_end(void){
        return _endLed;
        }

	long unsigned int Circle::myColor(void){
	return _color;
	}

Floor_piano

#include <Adafruit_NeoPixel.h>
#include <CapacitiveSensor.h>
#include <Circle.h>

// constants holding the colors
const auto red       = Adafruit_NeoPixel::Color(255,   0,   0);
const auto orange    = Adafruit_NeoPixel::Color(255, 120,   0);
const auto yellow    = Adafruit_NeoPixel::Color(255, 255,   0);
const auto green     = Adafruit_NeoPixel::Color(0,   255,   0);
const auto blue      = Adafruit_NeoPixel::Color(0,     0, 127);
const auto off       = Adafruit_NeoPixel::Color(0,     0,   0);


// Define data pin for LED strips
#define LED_PIN    45
// Define the length of the strip
#define LED_COUNT 408
// Create NeoPixel object
Adafruit_NeoPixel strip (LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

// Define data pin for LED strips for the cabinet
#define LED_PIN_2    44
// Define the length of the strip
#define LED_COUNT_2 47
// Create NeoPixel object
Adafruit_NeoPixel strip_2 (LED_COUNT_2, LED_PIN_2, NEO_GRB + NEO_KHZ800);

//There will be 11 "buttons" with their own capacitive sensor.
CapacitiveSensor sensor_1   =  CapacitiveSensor(22, 23);
CapacitiveSensor sensor_2   =  CapacitiveSensor(24, 25);
CapacitiveSensor sensor_3   =  CapacitiveSensor(26, 27);
CapacitiveSensor sensor_4   =  CapacitiveSensor(28, 29);
CapacitiveSensor sensor_5   =  CapacitiveSensor(30, 31);
CapacitiveSensor sensor_6   =  CapacitiveSensor(32, 33);
CapacitiveSensor sensor_7   =  CapacitiveSensor(34, 35);
CapacitiveSensor sensor_8   =  CapacitiveSensor(36, 37);
CapacitiveSensor sensor_9   =  CapacitiveSensor(38, 39);
CapacitiveSensor sensor_10  =  CapacitiveSensor(40, 41);
CapacitiveSensor sensor_11  =  CapacitiveSensor(42, 43);

// Each Circle holds information for status, timer, delay, in addition to
// methods to check timer and activate themselves
Circle circle_1    =   Circle(2000, 0, 37, yellow);
Circle circle_2    =   Circle(3000, 38, 74, red);
Circle circle_3    =   Circle(2000, 75, 111, orange);
Circle circle_4    =   Circle(2000, 112, 151, yellow);
Circle circle_5    =   Circle(2000, 152, 189, red);
Circle circle_6    =   Circle(2000, 190, 227, orange);
Circle circle_7    =   Circle(2000, 228, 265, red);
Circle circle_8    =   Circle(2000, 266, 303, yellow);
Circle circle_9    =   Circle(2000, 304, 341, orange);
Circle circle_10   =   Circle(2000, 341, 380, red);
Circle circle_11   =   Circle(2000, 380, 408, yellow);


// read a sensor, update the status of the Circle
void read_sensor(int i, CapacitiveSensor sensor, Circle circle) {
  int threshold = 1000;
  Serial.println("Reading sensor: ");
  Serial.println(i);
  long sensorValue = sensor.capacitiveSensor(30);      // read the sensor
  Serial.println("Sensor value: ");
  Serial.println(sensorValue);
  delay(500);
  if (sensorValue > threshold) {                       // touch detected
    if (circle.get_status() == false) {              // if the circle is passive
      circle.activate();                           // activate the circle
      Serial.print(i);                             // print the number of the sensor/ button
    }
  }
}
// Turn on the leds on the cabinet (from Neopixel example code)
void cabinet_leds(uint32_t color, int wait) {
  for (int i = 0; i < strip_2.numPixels(); i++) { // all the leds
    strip_2.setPixelColor(i, color);              // set color to blue
    strip_2.show();                               // update led
    delay(wait);                                  // pause for a moment between each pixel
  }
}

void display_leds(Circle circle) {
  int startLed = circle.get_start();
  int endLed = circle.get_end();
  for (int i = startLed; i < endLed + 1; i++) {          // the circle's LED number
    if (circle.get_status()) {                     // if the circle is active
      strip.setPixelColor(i, circle.myColor());  // set the leds to the correct color
    } else {                                       // else
      strip.setPixelColor(i, off);               // turn the leds off
    }
  }
}

// ----------- S E T U P ------------------
void setup() {
  Serial.begin(9600);
  strip.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();            // Turn OFF all pixels ASAP
  strip.setBrightness(50); // Set BRIGHTNESS to about 1/5 (max = 255)

  strip_2.begin();
  strip_2.show();
  strip_2.setBrightness(50);

  // turn on the LEDs on the cabinet
  cabinet_leds(strip_2.Color(  0,   0, 255), 50);   // Blue
  delay(500);

  Serial.print("Setup complete.");
}

// ----------- L O O P --------------------

void loop() {
  //  Serial.println("Checking the timers");
  circle_1.check_timer();
  circle_2.check_timer();
  circle_1.check_timer();
  circle_1.check_timer();
  circle_1.check_timer();
  circle_1.check_timer();
  circle_1.check_timer();
  circle_1.check_timer();
  circle_1.check_timer();
  circle_1.check_timer();
  circle_1.check_timer();

  //  Serial.println("Reading sensors");
  read_sensor(1,  sensor_1,  circle_1);
  read_sensor(2,  sensor_2,  circle_2);
  read_sensor(3,  sensor_3,  circle_3);
  read_sensor(4,  sensor_4,  circle_4);
  read_sensor(5,  sensor_5,  circle_5);
  read_sensor(6,  sensor_6,  circle_6);
  read_sensor(7,  sensor_7,  circle_7);
  read_sensor(8,  sensor_8,  circle_8);
  read_sensor(9,  sensor_9,  circle_9);
  read_sensor(10, sensor_10, circle_10);
  read_sensor(11, sensor_11, circle_11);

  //   Serial.print("Turning on leds.");
  display_leds(circle_1);
  display_leds(circle_2);
  display_leds(circle_3);
  display_leds(circle_4);
  display_leds(circle_5);
  display_leds(circle_6);
  display_leds(circle_7);
  display_leds(circle_8);
  display_leds(circle_9);
  display_leds(circle_10);
  display_leds(circle_11);

}

Try passing your instances by reference
instead of

declare the function as

void read_sensor(int i, CapacitiveSensor &sensor, Circle &circle) {

(I've not checked the whole code but you should likely do the same elsewhere too if you haven't)

Thank you! One step closer :grinning:

The lights will still not turn on, but at least I am able to get a proper value (2000-3000) from the sensor I am touching.

But the sensors I am NOT touching, are still reading 0. Well, sometimes, they read 1-10 immediately after I touch another sensor. But on the second loop, they are back to 0 again.

why do you have those in the .cpp file? you already have instance variables in your class definition.

I thought everything from the h-file had to be in the .cpp-file. I will give it a try with these removed!

I cleaned up a bit your code and moved to arrays to simplify things

Try this (Serial console @ 115200 bauds)

Circle.h

#ifndef Circle_h
#define Circle_h

#include <Arduino.h>

class Circle {
  public:
    boolean _status;
    uint32_t _timerStart;
    uint32_t _delay;
    int _startLed;
    int _endLed;
    uint32_t _color;

    Circle(uint32_t my_delay, int startLed, int endLed, uint32_t color);
    boolean getStatus();
    void activate();
    void checkTimer();
    int getStart();
    int getEnd();
    uint32_t getColor();
};
#endif

Circle.cpp

// CLass file for Circle
#include "Circle.h"

// constructor
Circle::Circle(uint32_t my_delay, int startLed, int endLed, uint32_t color) :
  _delay(my_delay), _startLed(startLed), _endLed(endLed), _color(color) {
  _timerStart = 0;
  _status = false;
}

void Circle::activate() {
  _status = true;
  _timerStart = millis();
}

void Circle::checkTimer() {
  _status = (millis() - _timerStart <= _delay);
}

boolean Circle::getStatus() {
  return _status;
}

int Circle::getStart() {
  return _startLed;
}

int Circle::getEnd() {
  return _endLed;
}

uint32_t Circle::getColor() {
  return _color;
}

piano.ino

#include <assert.h>

#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel mainStrip (408, 45, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel cabinetStrip (47, 44, NEO_GRB + NEO_KHZ800);

#include <CapacitiveSensor.h>
CapacitiveSensor sensors[] = {
  {22, 23}, {24, 25}, {26, 27}, {28, 29},
  {30, 31}, {32, 33}, {34, 35}, {36, 37},
  {38, 39}, {40, 41}, {42, 43}
};

const byte sensorCount = sizeof sensors / sizeof sensors[0];

#include "Circle.h"
const uint32_t red    = Adafruit_NeoPixel::Color(0xFF, 0x00, 0x00);
const uint32_t orange = Adafruit_NeoPixel::Color(0xFF, 0x78, 0x00);
const uint32_t yellow = Adafruit_NeoPixel::Color(0xFF, 0xFF, 0x00);
const uint32_t green  = Adafruit_NeoPixel::Color(0x00, 0xFF, 0x00);
const uint32_t blue   = Adafruit_NeoPixel::Color(0x00, 0x00, 0x7F);
const uint32_t off    = Adafruit_NeoPixel::Color(0x00, 0x00, 0x00);

Circle circles[] = {
  {2000, 0, 37, yellow}, {3000, 38, 74, red}, {2000, 75, 111, orange}, {2000, 112, 151, yellow},
  {2000, 152, 189, red}, {2000, 190, 227, orange}, {2000, 228, 265, red}, {2000, 266, 303, yellow},
  {2000, 304, 341, orange}, {2000, 341, 380, red}, {2000, 380, 408, yellow}
};

const byte circleCount = sizeof circles / sizeof circles[0];

// double check coherence
static_assert((sensorCount == circleCount), "Error: Number of Circles and Capacitive Sensors should match");

// read a sensor, update the status of the Circle
void readSensor(byte i, CapacitiveSensor& sensor, Circle& circle) {
  const int threshold = 1000;
  if (! circle.getStatus()) { // if passive, test sensor
    Serial.print(F("Reading sensor: ")); Serial.print(i + 1);
    long sensorValue = sensor.capacitiveSensor(30);      // read the sensor
    Serial.print(F("\tvalue: ")); Serial.println(sensorValue);

    if (sensorValue > threshold) {
      circle.activate();
      Serial.print(F("Activating Circle: ")); Serial.println(i);                             // print the number of the sensor/ button
    }
  }
}

// Turn on the leds on the cabinet (from Neopixel example code)
void cabinetLeds(uint32_t color, uint32_t wait) {
  for (int i = 0; i < cabinetStrip.numPixels(); i++) {
    cabinetStrip.setPixelColor(i, color);
    cabinetStrip.show();
    delay(wait); // pause for a moment between each pixel
  }
}

void displayLeds(Circle& circle) {
  for (int i = circle.getStart(); i <= circle.getEnd(); i++)
    if (circle.getStatus())  mainStrip.setPixelColor(i, circle.getColor());  // set the leds to the correct color
    else mainStrip.setPixelColor(i, off); // turn the leds off
  mainStrip.show(); // update led
}

void setup() {
  Serial.begin(115200);
  mainStrip.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
  mainStrip.setBrightness(50); // Set BRIGHTNESS to about 1/5 (max = 255)
  mainStrip.show();            // Turn OFF all pixels ASAP

  cabinetStrip.begin();
  cabinetStrip.show();
  cabinetStrip.setBrightness(50);
  cabinetLeds(blue, 50);
  Serial.println(F("Setup complete."));
}

void loop() {
  for (byte i = 0; i < circleCount; i++) {
    circles[i].checkTimer();
    readSensor(i,  sensors[i],  circles[i]);
    displayLeds(circles[i]);
  }
}

totally untested, typed here based on your code so to be tested and possibly debugged, but that could give you some ideas on how to play with this.

1 Like

I tried your version of my code. The printing was just random symbols, such as ???, but mirrored. No lights were turned on, and no sound played. I changed the baud rate to 9600, and removed the formatted printing, as I only really needed to know which sensor registered a touch. (The others were just for debugging.)

That worked! Thank you so much for helping me :star_struck:
I would never have guessed the need for "&". And as this was my first library, I had completely missed the part of not putting the intances in the .cpp file.

The serial monitor needed indeed to be at 115200 bauds, not 9600 as mentioned

glad you got it to work

You should read more about Classes so that you really understand instance variables