picandies
Posts: 199
Joined: Wed Nov 26, 2014 5:13 pm

Accessing IO in new class

Wed Nov 14, 2018 8:58 pm

Hi I have a program running well, it uses a few io pins to read some status of the external world , such as a few pushbuttons.

There is a class, in one file, called MotorSys which does the import RPi.GPIO as GPIO, and sets the names of the pins & direction for reading in the initialization, __init__(self). Then there are methods to look at the signals and take some actions and calculate & display messages, etc.
That is all fine & dandy.

Now I am working on another class file Pump_Mon, that needs to also look at some of these same signals. But am I supposed to init them again? It may be that Motor_sys is not always used, so that can't be relied upon. However if I init the I/O again in the Pump_Mon class that seems dubious, and when I do it twice I get errors/warnings that the I/O is already defined/in use.

is there a way to define init/init these signals, so that they are ready to be monitored by either (or both) classes? There is also a status led output, which either class would need to turn on in case of overload.

User avatar
MrYsLab
Posts: 375
Joined: Mon Dec 15, 2014 7:14 pm
Location: Noo Joysey, USA

Re: Accessing IO in new class

Thu Nov 15, 2018 9:48 pm

Without seeing your code it is somewhat difficult to give you an answer. It is not clear how these 2 classes are being instantiated.
If Pump_Mon is always instantiated as part of your application and MotorSys is optionally instantiated, you could have Pump_Mon have an initialization parameter that specifies whether or not MotorSys is to be instantiated, and instantiate MotorSys within Pump_Mon. You would then have enough information to decide when and where to init the pins.

picandies
Posts: 199
Joined: Wed Nov 26, 2014 5:13 pm

Re: Accessing IO in new class

Fri Nov 16, 2018 3:52 am

Say there is one instance of each class, they'd each be defining the pin. I don't want each to define the pin but each needs to be able to read the pin. Say the pin was an "emergency stop" input & several classes need to react to that...how is it usually set up?

I don't want "invent a problem" ,should each one just blindly define the pin & use it as an input & without regard to the other user? Then, what about the resultant error message about the pin being in use?

User avatar
MrYsLab
Posts: 375
Joined: Mon Dec 15, 2014 7:14 pm
Location: Noo Joysey, USA

Re: Accessing IO in new class

Fri Nov 16, 2018 12:52 pm

There are many solutions to the problem. Why not create a class whose function is to initialize the GPIO library, offers methods to set the pin modes and ability to both read and write the pins. This separates out GPIO control from the logic in your motor and pump classes.

I suggest you do some research on object-oriented design such as described here: https://medium.freecodecamp.org/a-short ... aa0a622c83

picandies
Posts: 199
Joined: Wed Nov 26, 2014 5:13 pm

Re: Accessing IO in new class

Sat Nov 17, 2018 8:06 am

Why not create a class whose function is to initialize the GPIO library, offers methods to set the pin modes and ability to both read and write the pins

Do you have simple example to do that? I think that has been my thought. Say this class was called my_io_setups....wouldn't each class that used it (pump_mon & motorsys) cause the pins to be defined/set up multiple times?

User avatar
MrYsLab
Posts: 375
Joined: Mon Dec 15, 2014 7:14 pm
Location: Noo Joysey, USA

Re: Accessing IO in new class

Sat Nov 17, 2018 2:32 pm

I am assuming that you want to run each of your classes as separate processes. Below are 2 classes that look identical except for their names and the sleep times.

They listen for a button press and also flash an LED. The faster flash rate is what you see on the board, both flash rates do coexist without crashing.

I can run both at the same time and have no gpio conflicts.

Code: Select all

import pigpio
import time

class ABC:
    def __init__(self, id):
        self.id = id
        self.pi = pigpio.pi()
        output_value = 0
        
        self.pi.set_mode(11, pigpio.INPUT)
        self.pi.set_mode(17, pigpio.OUTPUT)
        self.pi.callback(11, pigpio.EITHER_EDGE, self.callback)
        while True:
            output_value ^= 1
            self.pi.write(17, output_value)
            time.sleep(1)
        
    def callback(self, gpio, level, tick):
        print("{} Pin:{} Value:{}".format(self.id, gpio, level))
    
        
              
ABC('1')
        

Code: Select all

import pigpio
import time

class DEF:
    def __init__(self, id):
        self.id = id
        self.pi = pigpio.pi()
        output_value = 0
        
        self.pi.set_mode(11, pigpio.INPUT)
        self.pi.set_mode(17, pigpio.OUTPUT)
        self.pi.callback(11, pigpio.EITHER_EDGE, self.callback)
        while True:
            output_value ^= 1
            self.pi.write(17, output_value)
            time.sleep(.1)
        
    def callback(self, gpio, level, tick):
        print("{} Pin:{} Value:{}".format(self.id, gpio, level))
    
        
DEF('2')              

picandies
Posts: 199
Joined: Wed Nov 26, 2014 5:13 pm

Re: Accessing IO in new class

Sat Nov 17, 2018 4:54 pm

Thanks for the code, though it isn't what we were talking about. All my codes use RPi.GPIO, and get the errors like this:
RuntimeWarning: This channel is already in use, continuing anyway.
This makes sense since the pin has already been defined by someone. So how do you do what you were proposing?

Why not create a class whose function is to initialize the GPIO library, offers methods to set the pin modes and ability to both read and write the pins.

I am assuming that you want to run each of your classes as separate processes Not sure what you mean by that . There is only ONE program running. Each class is in a file, which gets imported. An instance of class A is made, fine. Then an instance of class B is made and the error appears when class B sets up the io (since A has already set it). If I take the setups out of class B those errors go away, but then lots of other errors appear, everywhere in class B, when I use I/O (It doesn't know the pin names , undefined, etc).

User avatar
MrYsLab
Posts: 375
Joined: Mon Dec 15, 2014 7:14 pm
Location: Noo Joysey, USA

Re: Accessing IO in new class

Sat Nov 17, 2018 5:15 pm

I do not use Rpi.GPIO, so I am sorry I can't be of much help. Perhaps someone else will step in.
It would probably be very helpful if you actually post your code so that others can see exactly what you are doing.

picandies
Posts: 199
Joined: Wed Nov 26, 2014 5:13 pm

Re: Accessing IO in new class

Sat Nov 17, 2018 6:12 pm

thanks for your help...I was wondering if you still have an example for your thought, doesn't matter which I/o lib is used.
Why not create a class whose function is to initialize the GPIO library, offers methods to set the pin modes and ability to both read and write the pins.

here is a strawman:

Code: Select all

myprogram

import classA as myclassA
import classB as myclassB

psense=myclassA.PressureSensor()   #causes  i/os to be setup
thealarm=myclassB.Motors      #causes more i/os to be set up & cause duplication errors

print(psense.reportPressure(3))
print(thealarm.switchstate())

while (psense.pressuremax() > thealarm.maxcondition()):
blahblah
can the I/Os be set up in one class (maybe a third), yet be used by all classes? If so, how

MisterYsLab
Posts: 10
Joined: Mon Dec 15, 2014 7:16 pm

Re: Accessing IO in new class

Sat Nov 17, 2018 7:26 pm

Code: Select all

import pigpio

class PressureSensor:
    def __init__(self):
        self.pi = pigpio.pi()
        
        # add the rest of your class here
        
class Motors:
    def __init__(self):
        self.pi = pigpio.pi()
        
        # add the rest of your class here
        
# import PressureSensor
# import Motors
import time

class MyApp:
    def __init__(self):
        ps = PressureSensor()
        motors = Motors()
        
        ps.pi.set_mode(17, pigpio.OUTPUT)
        motors.pi.set_mode(17, pigpio.OUTPUT)

        while True:
            ps.pi.write(17, 1)
            time.sleep(1)
            motors.pi.write(17, 0)
            time.sleep(1)
            
MyApp()
Both classes have their own instance of pigpio. In MyApp, I am using the instance in the pressure sensor to turn on the LED and the instance in motors to turn it off.

picandies
Posts: 199
Joined: Wed Nov 26, 2014 5:13 pm

Re: Accessing IO in new class

Sat Nov 17, 2018 8:00 pm

Thanks very much , gives me some ideas.
One thing I noticed is the classes (pressuresensor & motors) in your example aren't using the io, since no methods are present

Say there was a method .ReportPressure defined in PressureSensor to look at pin 17 & if the pin was high, read & print the pressure

And a method .SpeedUp defined in Motors to look at pin 17 & if high, increase the PWM and if low, print a message the no speed adjustment made

Then we want to do:

Code: Select all

code 
code
ps = PressureSensor()
motors = Motors()
code code
motors.SpeedUp()     ....needs to use io17
code 
code
ps.ReportPressure ()  ....needs to use io 17
code
would this do the trick?

MisterYsLab
Posts: 10
Joined: Mon Dec 15, 2014 7:16 pm

Re: Accessing IO in new class

Sat Nov 17, 2018 8:31 pm

You can organize your classes anyway that makes sense to you. Here I modified the program to handle a button push in the motor and pressure sensor classes. Both are simultaneously listening for a button press on the same pin. I am using a pigio callback that will fire on a rising edge for one class and a falling edge for the other. In this way I am turning on the LED in on one class and turning it off in the other. For your case, you could modify the callback to do whatever you wish. If you prefer not to use a callback, you can poll the pin in each class within a loop and then process the change for that pin specifically within and for that class.

You can also, access the pigpio library for either of the classes in the MyApp since you have references to the classes (ps and motors).

Organize things that work best for you. With the code above, you have a lot of flexibility where the monitoring of sensors and control of actuators resides.

Code: Select all

import pigpio

class PressureSensor:
    def __init__(self):
        self.pi = pigpio.pi()
        self.pi.set_mode(17, pigpio.OUTPUT)
        self.pi.set_mode(11, pigpio.INPUT)
        self.pi.callback(11, pigpio.RISING_EDGE, self.cb)
        
    def cb(self, pin, level, tick):
        # we know that the level is on the rising edge
        # so turn on the LED here
        print('Pressure Sensor detected change')
        self.pi.write(17, 1)
        
class Motors:
    def __init__(self):
        self.pi = pigpio.pi()
        self.pi.set_mode(17, pigpio.OUTPUT)
        self.pi.set_mode(11, pigpio.INPUT)
        self.pi.callback(11, pigpio.FALLING_EDGE, self.cb)
        
    def cb(self, pin, level, tick):
        # we know that the level is on the rising edge
        # so turn off the LED here
        print('Motors detected change')
        self.pi.write(17, 0)
                
# import PressureSensor
# import Motors
import time

class MyApp:
    def __init__(self):
        ps = PressureSensor()
        motors = Motors()
        
        while True:
            time.sleep(1)
            
MyApp()

picandies
Posts: 199
Joined: Wed Nov 26, 2014 5:13 pm

Re: Accessing IO in new class

Sat Nov 17, 2018 9:12 pm

Thanks for the update...however now your example is having each class setting up the pins, so now it will be back to the "pin is already define/in use error...I thought we were trying to only init/config/define them once. We want to set up & define all the io's and thereafter let each class use them, when their methods are called by the main program.

The main program determines when to call the different methods (under various calculations & conditions), so at that time it will do a ps.ReportPressure() , or motor control.

User avatar
MrYsLab
Posts: 375
Joined: Mon Dec 15, 2014 7:14 pm
Location: Noo Joysey, USA

Re: Accessing IO in new class

Sat Nov 17, 2018 9:21 pm

If you run the code, you will see there are no errors. Each instance of pigpio allows you to initialize, control and monitor the GPIO pins. To run the code, first open up a terminal and start the pigpio daemon by typing:

Code: Select all

sudo pigpiod
Try it, you'll like it :D

If you run into any errors, post the exception stack and I can take a look.

User avatar
MrYsLab
Posts: 375
Joined: Mon Dec 15, 2014 7:14 pm
Location: Noo Joysey, USA

Re: Accessing IO in new class

Sat Nov 17, 2018 9:30 pm

From the last paragraph of your last reply it seems that you wish to share a single instance of the GPIO control - either pigpio or Rpi.GPIO.
Doing that complicates things greatly. You will need some mechanism to determine if a pin has already been initialized by the other class. Also, if both classes are trying to access the same instance of GPIO control, you will need a method to make sure that only one has access to the GPIO. You would need to provide a semaphore or resource lock around the GPIO contol functions. It can be done, but by using pigpio, you can avoid all of this complication. Each class owns its own pigpio instance that is separate from any other pipgpio instance. Each instance initializes the pins for themselves and allows access to the pins without having to provide any resource locking mechanism of your own.

User avatar
MrYsLab
Posts: 375
Joined: Mon Dec 15, 2014 7:14 pm
Location: Noo Joysey, USA

Re: Accessing IO in new class

Sat Nov 17, 2018 9:40 pm

Here is a comment by Joan, the author of pigpio that describes using multiple instances of pipgio viewtopic.php?t=212237#p1389254.

picandies
Posts: 199
Joined: Wed Nov 26, 2014 5:13 pm

Re: Accessing IO in new class

Sat Nov 17, 2018 11:33 pm

Thank you MRyslab:

Sound like maybe this is simply not possible unless I use pigrpio. I may have to rip up my code and see if pigrpio does the trick.

Idahowalker
Posts: 445
Joined: Wed Jan 03, 2018 5:43 pm

Re: Accessing IO in new class

Sun Nov 18, 2018 3:46 pm

I have classes, threads, and a multiprocess that uses the GPIO pins all with out giving error.

In the main code, I have a function that sets up the GPIO pins, states, and callbacks. This code, to setup GPIO, runs before any threading, class instantiations or, multiprocess are started. East-peasy.
Without knowing why you are deleting my postings, I will not know how...

picandies
Posts: 199
Joined: Wed Nov 26, 2014 5:13 pm

Re: Accessing IO in new class

Sun Nov 18, 2018 4:12 pm

In the main code, I have a function that sets up the GPIO pins, states, and callbacks. This code, to setup GPIO, runs before any threading, class instantiations or, multiprocess are started.
Exactly what I am looking for--how is it set up? How do the other classes access the set-up I/O? Please show your example---nobody else has been able to without multiple setups.

Return to “Python”