object-oriented programming

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
mschulz
Posts: 35
Joined: Fri Apr 17, 2015 11:26 am
Location: Germany

object-oriented programming

Post by mschulz » Mon Apr 20, 2015 8:42 am

Hello

I want to write an OOP Program, but I have a Problem.

How can I start a funktion of one Class in an other Class.

For Example in the Scheduler (http://short4u.de/5534bb60d9855)

When I copy the example, I bekome an error in the LED Class when I whant to start sched.schedule(self.time_on, self.off), because sched.schedule dos not exisit in the LED class.

Thank you for your help

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: object-oriented programming

Post by pythoncoder » Tue Apr 21, 2015 5:35 am

It would help if you posted your actual code but it sounds to me as if you haven't created an instance of the Scheduler class. Have you issued

Code: Select all

sched = Scheduler()
before using the LED class?
Peter Hinch
Index to my micropython libraries.

mschulz
Posts: 35
Joined: Fri Apr 17, 2015 11:26 am
Location: Germany

Re: object-oriented programming

Post by mschulz » Tue Apr 21, 2015 7:15 am

Yes, I have createt the instance in the main

Code: Select all

 # here I import the Classes
import imesscheduler
import led
print('init')
switch=pyb.Switch()
sched = imesscheduler.Scheduler() # here I create the instance
LED1 = led.C_LED(1, 1000, 2000)
LED2 = led.C_LED(2, 1000, 2000)

sched.run()

the LED Class

Code: Select all

class C_LED():
    def __init__(self, led_id, time_on, time_off):
        print('init LED',led_id)
        self.led_id = led_id
        self.time_on=time_on
        self.time_off=time_off

    def on(self):
        pyb.LED(self.led_id).on()
        global sched
        sched.schedule(self.time_on, self.off) # here is the error!!!!

    def off(self):
        pyb.LED(self.led_id).off()
        global sched
        sched.schedule(self.time_off, self.on)
and here the Scheduler Class

Code: Select all

class Scheduler:
    def __init__(self):
        print('init scheduler')
        self.events=[] # keine events

    def schedule(self, delay, function):
        print('schedlule function', function)
        if delay <=0:
            print('ausführen')
            function()
        else:
            print('function zu events')
            self.events.append([delay,function])
            self.events.sort(key=lambda event:event[0])
            #print('events',self.events)

    def run(self):
        while len(self.events)>0:
            print ('len(events):',len(self.events))

            delay, function = self.events.pop(0)
            print('delay',delay)
            print ('function',function)

            for event in self.events:
                event[0]-=delay

            pyb.delay(delay)
            function()
I wrote it as in the example.

Thank you for your help.

Damien
Site Admin
Posts: 647
Joined: Mon Dec 09, 2013 5:02 pm

Re: object-oriented programming

Post by Damien » Tue Apr 21, 2015 10:39 am

The problem is that because C_LED is defined in its own module (in led.py) it does not know about the sched object that is created in main.py. Objects created within a file are global only to that file (file=module).

You have many ways to fix it:
  • put the code for C_LED in main.py (this is the easiest solution)
  • pass sched to the C_LED constructor and save it as a variable in the C_LED instance
  • pass sched to the C_LED on/off functions (this requires modifying the Scheduler class)
  • ...
Does that help?

mschulz
Posts: 35
Joined: Fri Apr 17, 2015 11:26 am
Location: Germany

Re: object-oriented programming

Post by mschulz » Tue Apr 21, 2015 11:47 am

Thank you for your Answer

The first solution: I wil try it for this example, but my Projekt is bigger and I think there is this not a transparency way

I think the Problem with the second solution is, when I have more than one class which will push funktions to the scheduler ?

The Third way I dos not understand, what do you want to say me?


I described my hole Projekt here: http://forum.micropython.org/viewtopic.php?f=5&t=644

Thank you for your solutions.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: object-oriented programming

Post by pythoncoder » Wed Apr 22, 2015 6:23 am

@Damien's third method requires a change to the scheduler class because the definition of function has changed: it now requires an additional argument. If I were coding it I would use method 2. In fact I did, because it struck me that there was no code to start the whole process running. Here is what's needed to make it work using method 2. I altered the timing of one of the LED's so that it's clear that they are flashing asynchronously. Also each file needs to import pyb.
Main module:

Code: Select all

 # here I import the Classes
import imesscheduler
import led
import pyb # was missing
print('init')
switch=pyb.Switch()
sched = imesscheduler.Scheduler() # here I create the instance
LED1 = led.C_LED(sched, 1, 1000, 2000)
LED2 = led.C_LED(sched, 2, 1100, 2000) # Demonstrate the asynchronous flashing
LED1.on() # Start it running
LED2.on()
sched.run()
led.py:

Code: Select all

import pyb
class C_LED():
    def __init__(self, sched, led_id, time_on, time_off):
        print('init LED',led_id)
        self.sched = sched
        self.led_id = led_id
        self.time_on=time_on
        self.time_off=time_off

    def on(self):
        pyb.LED(self.led_id).on()
        self.sched.schedule(self.time_on, self.off) # here is the error!!!!

    def off(self):
        pyb.LED(self.led_id).off()
        self.sched.schedule(self.time_off, self.on)
imesscheduler.py:

Code: Select all

import pyb
class Scheduler:
    def __init__(self):
        print('init scheduler')
        self.events=[] # keine events

    def schedule(self, delay, function):
        print('schedlule function', function)
        if delay <=0:
            print('ausführen')
            function()
        else:
            print('function zu events')
            self.events.append([delay,function])
            self.events.sort(key=lambda event:event[0])
            #print('events',self.events)

    def run(self):
        while len(self.events)>0:
            print ('len(events):',len(self.events))

            delay, function = self.events.pop(0)
            print('delay',delay)
            print ('function',function)

            for event in self.events:
                event[0]-=delay

            pyb.delay(delay)
            function()
I'm afraid I don't understand your difficulty with the second solution. The functions scheduled are class methods so the class instance is saved as a hidden argument to the function. So, just as the scheduler "knows" which LED to schedule, it will also call the correct class instance method if you define other classes and create instances of them.
Peter Hinch
Index to my micropython libraries.

mschulz
Posts: 35
Joined: Fri Apr 17, 2015 11:26 am
Location: Germany

Re: object-oriented programming

Post by mschulz » Wed Apr 22, 2015 8:45 am

Thank you, for your help.

Now the 2. Solution works.

My problem was, that I think that I should create the instance of the scheduler in the construktor of the LED class, and then I have a problem, when I have more then one class.

But this solution is verry nice and should work for my case.

With kind regards
Martin

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: object-oriented programming

Post by pythoncoder » Wed Apr 22, 2015 3:47 pm

Logically there is a single scheduler and instantiating it as a global simplifies the code.

Incidentally, looking at your code I think you may not have understood the meaning of Python's global keyword. To access an object created in the outermost scope of a python program you don't need a global specifier. This is because Python searches the local namespace, working outwards until it finds the global instance. Where global is essential is in situations like this:

Code: Select all

x = 4
def foo():
	x = 10
foo()
print(x)
Unless you declare global x in the function Python will create a local variable called x and assign a value of 10 to it, leaving the global unchanged: the code above will output 4, not 10. It's a feature of the language which often confuses beginners. The following will behave as expected:

Code: Select all

x = 4
def foo():
    global x
    x = 10
foo()
print(x)
Peter Hinch
Index to my micropython libraries.

mschulz
Posts: 35
Joined: Fri Apr 17, 2015 11:26 am
Location: Germany

Re: object-oriented programming

Post by mschulz » Fri Apr 24, 2015 11:46 am

Hello
Thank you. The "global was only a experiment.

But I have an other question. Now I use the Scheduler (and it works), But how I can use a switch or Hardware interrupt?
bevore I start the scheduler with sched.run() it works.

Code: Select all

def callback1(line):
    print("DEBUG: Hardware Y3 Interupt!")
    ext1.disable()
    ext2.enable()
    global interrupt3
    global interrupt4
    interrupt3=True
    interrupt4=False

ext1 = pyb.ExtInt(pyb.Pin('Y3'), pyb.ExtInt.IRQ_RISING, pyb.Pin.PULL_DOWN, callback1)

def callback2(line):
   print("DEBUG: Hardware Y4 Interupt!")
   ext2.disable()
   ext1.enable()
   global interrupt3
   global interrupt4
   interrupt3=False
   interrupt4=True

ext2 = pyb.ExtInt(pyb.Pin('Y4'), pyb.ExtInt.IRQ_FALLING, pyb.Pin.PULL_NONE, callback2)

Damien
Site Admin
Posts: 647
Joined: Mon Dec 09, 2013 5:02 pm

Re: object-oriented programming

Post by Damien » Sun Apr 26, 2015 12:00 pm

The code you have for the 2 hardware interrupts should continue to run even when the scheduler is running. Does any part of the scheduler (or any other code) disable interrupts or change the pin configuration?

Post Reply