Sketch does not compile when using PinChangeInt.h functionality in own custom library

My project, involving a Arduino UNO, requires multiple ultrasound sensors. For this I am in the process of writing my own custom library “Sonar_rk.h” that contains functions which are needed to control and read data from my ultrasound sensors. As I have more than one sensor, I would like to control these sensors in my main sketch by utilizing multiple instances of the same functions defined in my custom library (each sensor its own instance).
To read the pulse width from the PWM output from my sensors, I would like to use a simple function which is called when the PWM signal from the sensor triggers an interrupt. As I am using multiple sensors (eight of them), I would like to use the PinChangeInt.h library to be able to respond to interrupts on multiple (eight) pins. My preference is that the PinChangeInt.h functionality is imbedded in my custom library “Sonar_rk”. In my Sonar_rk.cpp file I use the following code: "PCintPort::attachInterrupt(_PIN_sonar, processSonar,CHANGE); ". “processSonar” is the function that is called when the interrupt is triggered on pin “PIN_sonar”. This function is also defined in my “Sonar_rk.cpp” file. My code is listed below. When I try to compile the code, I get a series of error messages back from the compiler. I also included those messages (at the bottom of this message). I have tried search for answers on the internet, quite extensively, and have tried numerous variations of the code. So far without success. If somebody could help me with this, it would be much appreciated.

It should be noted that some functionality is omitted from my code example for clarity reasons. This however should not impact the issue I currently have with compiling the code.

This is my custom “.h” file “Sonar_rk.h”

#ifndef PinChangeInt_h
#define LIBCALL_PINCHANGEINT
#include <../PinChangeInt/PinChangeInt.h>
#endif

#ifndef Sonar_rk_h
#define Sonar_rk_h
#include "Arduino.h"
#include <PinChangeInt.h>

class Sonar_rk
{
     public:
	    Sonar_rk(int PIN_sonar);
	    int pulseSonar_calcDistance();   
     private:
         int _PIN_sonar;
         volatile uint16_t _unsharedsonar; //unsigned int exchange between interups and main loop
         uint32_t _ulstartsonar; //unsigned long to reset the clock start counting
         int _distancesonar;
         static void processSonar();
};

#endif

This is the accompanying “.cpp” file

#include <Arduino.h>
#include <Sonar_rk.h>
#include <PinChangeInt.h>

Sonar_rk::Sonar_rk(int PIN_sonar)
{
  pinMode(PIN_sonar, OUTPUT);
  _PIN_sonar = PIN_sonar;
  PCintPort::attachInterrupt(_PIN_sonar, processSonar,CHANGE); 
}


int Sonar_rk::pulseSonar_calcDistance()
{
	//actual code omitted for clarity: 
	noInterrupts(); //turn of interrupt to allow the pulse to be send
	//code to allow the sonar sensor to send pulse
	delay(15); //placeholder, not actual code
	interrupts();
	/* turn interrupt on, 
	allow the interrupt routine to react to the event 
	and measure the pulse length coming back from the sensor
	during the delay 
	*/ 
	delay(15); 
	//The distance is being calculated
	return _distancesonar  = _unsharedsonar /74 /2;
	
}

void Sonar_rk::processSonar()
{
      // if the pin is high, its a rising edge of the signal pulse, so lets record its value
      if(digitalRead(_PIN_sonar) == HIGH)
      { 
        _ulstartsonar = micros();
      }
      else
      {
        // else it must be a falling edge, so lets get the time and subtract the time of the rising edge
        // this gives use the time between the rising and falling edges i.e. the pulse duration.
        _unsharedsonar = (uint16_t)(micros() - _ulstartsonar);
       }
}

This is my main sketch:

//Include libraries

#include <Sonar_rk.h>
#include <PinChangeInt.h>

// Assign PIN Sonar and Servo
 const int PIN_sonar1 = 2; //assign sonar1 to pin 2

//construct instance of sonar1 class of functions
Sonar_rk sonar1(PIN_sonar1);


void setup () 
{
   //innitiate serial communication
   Serial.begin(9600);
   //call class attachInterrupt in a pin change and run subroutine calcSonar1
     
}

void loop()
{
  Serial.println(sonar1.pulseSonar_calcDistance());
  delay(200); 
}

And finally, these are the compiler error messages I get:
/arduino/learning/libraries/Sonar_rk/Sonar_rk.h: In static member function ‘static void Sonar_rk::processSonar()’: /arduino/learning/libraries/Sonar_rk/Sonar_rk.h:17: error: invalid use of member ‘Sonar_rk::_PIN_sonar’ in static member function /arduino/learning/libraries/Sonar_rk/Sonar_rk.cpp:34: error: from this location /arduino/learning/libraries/Sonar_rk/Sonar_rk.h:19: error: invalid use of member ‘Sonar_rk::_ulstartsonar’ in static member function /arduino/learning/libraries/Sonar_rk/Sonar_rk.cpp:36: error: from this location /arduino/learning/libraries/Sonar_rk/Sonar_rk.h:18: error: invalid use of member ‘Sonar_rk::_unsharedsonar’ in static member function /arduino/learning/libraries/Sonar_rk/Sonar_rk.cpp:42: error: from this location /arduino/learning/libraries/Sonar_rk/Sonar_rk.h:19: error: invalid use of member ‘Sonar_rk::_ulstartsonar’ in static member function /arduino/learning/libraries/Sonar_rk/Sonar_rk.cpp:42: error: from this location

Is there some part of that message that you don't understand? The processSonar() function is static. That means that the function belongs to the class, not to an instance of the class. When the function is called, you are trying to use the data that belongs to an instance of the class. Which instance's data should be used?

Your class will need to keep track of the instances created (with a static function). Then, when processSonar() gets called, it needs to determine which pin triggered the call, and then determine which instance (using another static method) is associated with that pin. THEN, it can use that instance's data.

Thank you for your response. I am still quite new at this, so I am not completely understanding your reply. However, I now do understand that some internal bookkeeping needs to take place to keep track of which instance is associated with which pin and through which instance processSonar() is activated.

I am not familiar enough with the static method to follow up on your recommendations. Could you please explain by example what it means: “to keep track of the instances created with a static function”, and how to keep track of which pin is associated with witch instance by using the static method.

Thank you much

In any non-static method of a class, there is a pointer, this, that points to the current instance.

If your constructor takes a pin number, you can, in the constructor, call a static method, passing it this and the pin number.

That static method can populate a static array of structs or two static arrays of pointers and pin numbers.

You'll need to allocate those static arrays as part of the class. Make the size appropriate for the number of instances that can reasonably be created. You'll need another static variable to count the number of instances, or you'll need to have the destructor set the pin number for the destroyed instance to some non-valid value (-1 or 255 come to mind, depending on the type of the array).

Suppose that you add

static byte pinsUsed[10];
static Sonar_rk *instances[10];

Your constructor can look through the array of instances for a non-used position, and store this in that position, and store the pin number in the corresponding position in the other array.

Your processSonar() method can then use the other approach, finding the pin number in the pinsUsed array, and then using the instance in the corresponding position in the instances array.

Thank you for your clarification. I thinks I understand the general direction. I will follow up on it and see if I can make it work. Thanks again