Welcome to the Pycom forum Forum
    • \[\[global:header.categories\]\]
    • \[\[global:header.recent\]\]
    • \[\[global:header.tags\]\]
    • \[\[global:header.popular\]\]
    • Login

    Explore Pybytes | Official Documentation | Report a Firmware Bug/Issue | GitHub

    TimerWipy

    Scheduled Pinned Locked Moved WiPy 2&3
    wipy 2timer interruptimerirq
    17 Posts 2 Posters 2.0k Views 2 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • V Offline
      VFlorio94
      last edited by

      Hi , can someone explain how the method
      ''''timerchannel.irq(*, trigger, priority=1, handler=None)''' works?
      I have to use TimerWiPy.PERIODIC.
      I don't undestand also handler function.

      robert-hhR 1 Reply Last reply Reply Quote 0
      • robert-hhR Offline
        robert-hh @VFlorio94
        last edited by robert-hh

        @vflorio94 With that method you can achieve, that a certain function, the handler, is called when the time expires. That is what you need for your project. The setting of timer.PERIODIC means, that it is called over & over again. Like:

        from machine import timer
        PERIOD = 0.2  # call every 0.2 seconds
        
        def sample_and_write(timer_obj):
        # this is a function which reads form the sensor and writes
        # to disk. timer_obj identifies the timer, which calls this function
        # Can be ignored
            pass
        
        alarm = Timer.Alarm(sample_and_write, PERIOD, periodic=True)
        

        And when you want to stop it, call

        alarm.cancel()
        

        Edit: It should be positively noted that the callback is no interrupt. This means you are free for almost any Python operation, especially allocating memory.

        V 2 Replies Last reply Reply Quote 0
        • V Offline
          VFlorio94 @robert-hh
          last edited by

          @robert-hh thank you, now i'm trying to modify my function.

          • so, is 'timer_obj' my time of acquisition?
          • is alarm the command that I have to use in main?
            thank you a lot
          robert-hhR 1 Reply Last reply Reply Quote 0
          • V Offline
            VFlorio94 @robert-hh
            last edited by

            @robert-hh the function can be like this?

            import machine 
            import pycom
            from machine import Timer
            import time
            import lib_imu
            import lib_imu2
            from machine import I2C
            from math import sqrt
            from machine import PWM
            from machine import SD
            import gc
            import os
            sd = SD()
            os.chdir('/sd')
            
            PERIOD= 0.02 #sample time
            
            lib_imu.set_configmode()
            time.sleep(0.01) 
            lib_imu.set_units()
            time.sleep(0.01)
            lib_imu.set_mode('ndof')
            time.sleep(0.01)
            
            lib_imu2.set_configmode() 
            time.sleep(0.01)
            lib_imu2.set_units()
            time.sleep(0.01)
            lib_imu2.set_mode('ndof')
            time.sleep(0.01)
            fileIMU1 = open('/sd/dati_IMU1.txt', 'w')
            #fileT_IMU1 = open("/sd/datiT_IMU1.txt", "w")
            fileIMU2 = open('/sd/dati_IMU2.txt', 'w')
            #fileT_IMU2 = open("/sd/datiT_IMU2.txt", "w")
            file_tempi = open('/sd/tempi.txt', 'w')
            list_eul = [ ]
            list_eul2 = [ ]
            list_tempi = []
            
            def sample_and_write(timer_obj):   #timer_obj??
                #list_tempi.append(temp.read())
                list_eul.append(lib_imu.get_euler_int())
                #list_tempi.append(temp.read())
                list_eul2.append(lib_imu2.get_euler_int())
                pass
            
            def acquisition(sec):
                t = Timer.Chrono()
                t.start()
                while 1: 
                    t = t.read()
                    if  t <= sec :
                        alarm = Timer.Alarm(sample_and_write, PERIOD, periodic = true)
                    else:
                        alarm.cancel()
                        fileIMU1.write(  repr(list_eul) + '\t')
                        fileIMU2.write( repr(list_eul2) + '\t')
                        del list_eul
                        del list_eul2
            
            robert-hhR 1 Reply Last reply Reply Quote 0
            • robert-hhR Offline
              robert-hh @VFlorio94
              last edited by

              @vflorio94 You do not have to call alarm. Actually, it is not a function, it is a timer object. The callback function is called by the Timer periodically without further action by your main program. You main code has to prepare the data & objects needed by the callback and then start the timer. Typically, all of that would be enclosed in a class, and the main program would just instantiate this class. That could look like this:

              #
              from machine import Timer, idle
              #
              # add the other imports here that you need
              
              #
              # acquire  values. The paramters of the constructor are:
              #
              class Acquire:
                  def __init__(self, filename_imu1, period=0.2, runtime = 60):
                      self.fileIMU1 = open(filename_imu1, "w") # or append
                      self.temp = Timer.Chrono()
                      self.busy = True
                      self.runtime = runtime
                      self.temp.start()
                      self.alarm = Timer.Alarm(self.sample_and_write, period ,periodic=True)
                      # and add all other init tasks you need
              
                  def stop(self):
                      self.alarm.cancel()
                      self.fileIMU1.close()
              
                  def sample_and_write(self, alarm):
                      passed = self.temp.read()
                      # check, if done, if the time for sampling is expired, then stop
                      if passed >= self.runtime:
                          self.stop()
                          self.busy = False
                      else:
                          # get data and write
                          print(passed, self.runtime)
                          self.fileIMU1.write(repr(passed) + "," + lib_imu.get_euler_int() + "\n")
                          #
                          # and what else you have to do.
              
              #
              # now here the skeleton main_
              #
              
              # set up the hardware
              #
              
              # and start
              acquire = Acquire("my_data_file", 0.2, 20)
              #
              # now get the data, until it's done
              #
              while acquire.busy:
                  idle()
              #
              # whatever you have to do for cleanup, do it here
              #
              
              V 1 Reply Last reply Reply Quote 0
              • robert-hhR Offline
                robert-hh @VFlorio94
                last edited by

                @vflorio94 Timer.Alarm() has to be called only once.

                V 1 Reply Last reply Reply Quote 0
                • V Offline
                  VFlorio94 @robert-hh
                  last edited by

                  @robert-hh I understand all. finally it works without any interrupt
                  than you a lot.

                  1 Reply Last reply Reply Quote 0
                  • V Offline
                    VFlorio94 @robert-hh
                    last edited by

                    @robert-hh Hello. I have to ask you a new thing correlate with this code that you wrote previously.
                    I want to implement the code with another part in which I desire to activate PWM depending on the data sample and wrote by IMU. So, the question is:
                    Is it correct if I introduced a control on the data that I wrote and the command to activate PWM in the fuction 'sample and write'?
                    And have I also to complete class acquire like this?

                    self.pwm = PWM(0.02, frequency=500 ) #This sets up the timer to 
                            #oscillate at the specified frequency. timer is an integer from 0 to 3. 
                            # frequency is an integer from 1 Hz to 78 KHz 
                    

                    I know that I have also to set PWM channel where I put set-up Hardware parameters.
                    I'll be newly grateful if you can help me.

                    robert-hhR 1 Reply Last reply Reply Quote 0
                    • robert-hhR Offline
                      robert-hh @VFlorio94
                      last edited by

                      @vflorio94 said in TimerWipy:

                      self.pwm = PWM(0.02, frequency=500 )

                      The first argument of the class instantiation is a timer ID, not a time or the like. The value range is 0 - 3. See: https://docs.pycom.io/firmwareapi/pycom/machine/pwm
                      So it should be:
                      self.pwm = PWM(0, frequency=500 )

                      V 1 Reply Last reply Reply Quote 0
                      • V Offline
                        VFlorio94 @robert-hh
                        last edited by

                        @robert-hh yes, I checked and you are right. And about command to activate pwm responding to data acquire by sensor?

                        robert-hhR 1 Reply Last reply Reply Quote 0
                        • robert-hhR Offline
                          robert-hh @VFlorio94
                          last edited by

                          @vflorio94 ???

                          V 1 Reply Last reply Reply Quote 0
                          • V Offline
                            VFlorio94 @robert-hh
                            last edited by

                            @robert-hh sorry, I describe the problem in a bad way. I have another question.
                            I have a data that I want to use inside the function 'sample_and_write', but I have some difficulties to pass it from main to the class '''Acquire''' and in the end to the function. Is it possible ? can you help me?

                            robert-hhR 1 Reply Last reply Reply Quote 0
                            • robert-hhR Offline
                              robert-hh @VFlorio94
                              last edited by

                              @vflorio94 That's a question of scope and visibility in Python.
                              So most simple but unelegant method is to have that data global. So it is created outside every function. Then at any part of your code you can declare is a global to access it. Example:

                              # at the top level of your code:
                              data_buffer = bytearray(100)
                              data_ptr_in = 0
                              data_ptr_out = 0
                              
                              #
                              # 
                              class MyClass:
                                  def my_func(self):
                                      # declare symbols as global
                                      global data_buffer, data_ptr_in, data_ptr_out
                                      data_buffer[data_ptr_in] = some_data
                                      data_ptr_in = (data_ptr_in + 1) % len(data:buffer)
                              

                              You can also define functions (or better to say methods) to pass along data, and you can use property and setter and getter methods of classes, ...

                              V 1 Reply Last reply Reply Quote 0
                              • V Offline
                                VFlorio94 @robert-hh
                                last edited by

                                @robert-hh Thank you, I solved this problem. I put data as metod.
                                Now I have a new problem because I want to read data from sensor and after a comparisono with reference data I want to activate pwm. I did it in this way.
                                But the problem is that the period change a lot, sample time decrease to 0.04.
                                Is there another way to modify this code for activate pwm that can be better??
                                I need if it is possible that period remain more possible like 0.02.

                                thank you

                                import machine 
                                import pycom
                                from machine import Timer
                                from machine import idle
                                import time
                                import lib_imu
                                import lib_imu2
                                from machine import I2C
                                from math import sqrt
                                from math import fabs
                                from machine import PWM
                                from machine import SD
                                import gc
                                import os
                                sd = SD()
                                os.chdir('/sd')
                                from machine import idle
                                
                                #
                                # add the other imports here that you need
                                # fileIMU1 = open('/sd/dati_IMU1.txt', 'w')
                                #
                                # acquire  values. The paramters of the constructor are:
                                #
                                class Acquire:
                                    def __init__(self, filename_imu1, data, period=0.02, runtime = 60):
                                        self.fileIMU1 = open(filename_imu1, "w")
                                        self.temp = Timer.Chrono()
                                        self.busy = True
                                        self.data = data
                                        self.runtime = runtime
                                        self.temp.start()
                                        self.alarm = Timer.Alarm(self.sample_and_write, period , periodic=True)
                                        # and add all other init tasks you need
                                
                                    def stop(self):
                                        self.alarm.cancel()
                                        pwm_c2.duty_cycle(0)
                                        pwm_c5.duty_cycle(0)
                                        self.fileIMU1.close()
                                        #self.fileIMU2.close()
                                
                                    def sample_and_write(self, alarm):
                                        passed = self.temp.read()
                                        # check, if done, if the time for sampling is expired, then stop
                                        if passed >= self.runtime:
                                            self.stop()
                                            self.busy = False
                                            print('end')
                                        else:
                                            # get data and write
                                            #print(passed, fabs(lib_imu2.get_euler()[2]))
                                            self.fileIMU1.write(repr(passed) + repr(lib_imu2.get_euler()) + "\n")
                                             # avanti
                                            if fabs(lib_imu2.get_euler()[2]) > ( fabs(dati_rif[2]) + 0.2):
                                                if fabs(lib_imu2.get_euler()[2]) < (fabs(dati_rif[2]) + 0.4):
                                                    pwm2 = PWM(0, frequency=1000 )
                                                    pwm_c2.duty_cycle(0.5)
                                                    pwm_c5.duty_cycle(0) 
                                                elif fabs(lib_imu2.get_euler()[2]) >= (fabs(dati_rif[2]) + 2): 
                                                    pwm2 = PWM(0, frequency=2000 )
                                                    pwm_c2.duty_cycle(0.6)
                                                    pwm_c5.duty_cycle(0) 
                                            # indietro  
                                            elif fabs(lib_imu2.get_euler()[2]) <  fabs(dati_rif[2]) + 0.2:
                                                if fabs(lib_imu2.get_euler()[2]) > (fabs(dati_rif[2]) + 0.4):
                                                    pwm5 = PWM(0, frequency=1000 )
                                                    pwm_c2.duty_cycle(0)
                                                    pwm_c5.duty_cycle(0.5) 
                                                elif fabs(lib_imu2.get_euler()[2])< (fabs(dati_rif[2]) + 2): 
                                                    pwm5 = PWM(0, frequency=2000 )
                                                    pwm_c2.duty_cycle(0)
                                                    pwm_c5.duty_cycle(0.5)
                                            # and what else you have to do.
                                
                                #
                                # now here the skeleton main_
                                #
                                sd = SD()
                                os.chdir('/sd')
                                
                                # set up the hardware
                                ''' SET UP IMU 0X29 '''
                                # Scala Berg: imu L5 - lib_imu - acc
                                lib_imu.set_acc()
                                time.sleep(0.01)
                                lib_imu.set_configmode()
                                time.sleep(0.01) 
                                lib_imu.set_units()
                                time.sleep(0.01)
                                lib_imu.set_mode('ndof')
                                time.sleep(0.01)
                                ''' SET UP IMU 0X28 '''
                                # imu t1 - lib_imu2 - eul
                                lib_imu2.set_configmode() 
                                time.sleep(0.01)
                                lib_imu2.set_units()
                                time.sleep(0.01)
                                lib_imu2.set_mode('ndof')
                                time.sleep(0.01)
                                ''' PWM '''
                                pwm2 = PWM(0, frequency=500 )
                                pwm5 = PWM(0, frequency=500 )
                                #This sets up the timer to 
                                #oscillate at the specified frequency. timer is an integer from 0 to 3. 
                                # frequency is an integer from 1 Hz to 78 KHz 
                                pwm_c5 = pwm2.channel(5, pin='P12') #dietro
                                pwm_c2 = pwm5.channel(2, pin='P5')   # avanti
                                pwm_c5.duty_cycle(0)
                                time.sleep(0.01)
                                pwm_c2.duty_cycle(0)
                                time.sleep(0.01)
                                
                                ''' START''' 
                                with open("/sd/Rif.txt", "r") as f:
                                    line = f.read()
                                    # now you have a list of one string per line
                                    dati_rif = [float(el) for el in line.strip("()\n ").split(",")]  # reference data
                                print('start')
                                acquire = Acquire('Acquisition_Vibration.txt', dati_rif[2], 0.02, 30)
                                
                                #
                                # now get the data, until it's done
                                #
                                while acquire.busy:
                                    idle()
                                #
                                # whatever you have to do for cleanup, do it here
                                #```
                                robert-hhR 1 Reply Last reply Reply Quote 0
                                • robert-hhR Offline
                                  robert-hh @VFlorio94
                                  last edited by

                                  @vflorio94 For a consistent operation at a period of 0.02 or 50 ms it is required that the handler takes not longer than that, and that is executes the OWM changes at almost the same time within the handler. Looking at your code, I see at least two things that could affect timing:
                                  a) You write to a file. File i/O is buffered. As long as the data is written into the buffer, it's fast. When the buffer will be written, it can be slow.
                                  b) You call lib_imu2.get_euler() several times in the timer handler. I do not know the complexity of that call, but if it includes access to external hardware, then it may take some time. Better call it once, store the result and use that in consecutive statements.

                                  V 2 Replies Last reply Reply Quote 0
                                  • V Offline
                                    VFlorio94 @robert-hh
                                    last edited by

                                    @robert-hh I solved the problem creating a new function to compare data acquire by sensor with reference data and then it power on pwm. And in this way the period remain 50 ms.
                                    thank you

                                    1 Reply Last reply Reply Quote 0
                                    • V Offline
                                      VFlorio94 @robert-hh
                                      last edited by

                                      @robert-hh Hi, sorry for my insistence on this topic.
                                      I 'm not able to use thread but I read about it and I think that it's better for my code if I use them . So do you know if is it possibile to use thread to read from two I2C through the code that I posted before?
                                      thank you.

                                      1 Reply Last reply Reply Quote 0

                                      Hello! It looks like you're interested in this conversation, but you don't have an account yet.

                                      Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

                                      With your input, this post could be even better 💗

                                      Register Login
                                      • 1 / 1
                                      • First post
                                        Last post

                                      Pycom on Twitter

                                      Pycom