Wipy 2.0 and save data on my pc, not in flash memory



  • @vflorio94 In the first step, i changed two functions, media and calcolo_position. I simplified calcolo_position and reordered some lines. The major problem as I guess was a termination problem. It simply never hit the 0.5 second window for termination. It still is not perfect in matters of memory allocation, because it would better preallocate the "lists" as arrays. But that is a bigger change.
    I changed media(), because the way it is it would implicitely allocate a list. The way it is now it's a little bit slower.

    def calcolo_position(secondi):
    # function to calculate the position each second, the number of second is assigned
        gc.collect()
        # Configure I2C to extract euler angle
        lib_imu.set_configmode()
        time.sleep(0.03)
        # set unit
        lib_imu.set_units()
        time.sleep(0.03)
        # set mode
        lib_imu.set_mode('ndof')
        # create 3 lists 
        lista_heading = []
        lista_roll = []
        lista_pitch = []
        t = Timer.Chrono()
        t.start()
        time.sleep(0.1)
        while 1: 
            t_now = t.read() 
            if  t_now <= secondi:
                eul = lib_imu.get_euler()
                lista_heading.append(eul[0])
                lista_roll.append(eul[1])
                lista_pitch.append(eul[2])
                time.sleep(0.5) 
                if t_now > (secondi - 0.5):
                # Calculate mean and standard deviation
                    print(lista_heading)
                    print(lista_roll)
                    print(lista_pitch)
                    print("Calcolo media")
                    mean_pos = (media(lista_pitch), 
                                media(lista_pitch),
                                media(lista_heading))
                    # Calcolo deviazione standard
                    devstd_pos = (dev_std(lista_heading), 
                                  dev_std(lista_roll), 
                                  dev_std(lista_pitch))
                    return mean_pos, devstd_pos
            else:
                t.stop()
                del lista_heading
                del lista_pitch
                del lista_roll
                gc.collect()
                print("Acquisizione terminata")
                break
    
    def media(sequenza):
        # calculate mean
        mean = 0.0
        for _ in range (1, len(sequenza)):
            mean += sequenza[_]
        return mean / (len(sequenza)-1)
    


  • @robert-hh Sorry, I didn't understand your question before.
    it returns TUPLE
    thank you for your help and your patience



  • @vflorio94 said in Wipy 2.0 and save data on my pc, not in flash memory:

    lib_imu.get_euler return the Euler Angle of pitch, roll and yaw.

    I am asking about the data type: Does it return a tuple with three float values?



  • @robert-hh
    The intention of calcolo_position(sec) is which you have write. The function collect 2 values each second, calculate mean and re-use this value in the next function "acquisizione_interval_pitch", to generate the output.
    I need to mantain this time of acquisition because i work on subject and I want to extract data about their trunk posture in real time. I want to give them some feedback in real time.

    lib_imu is a simple library create to extract by I2c BNO055.
    lib_imu.get_euler return the Euler Angle of pitch, roll and yaw.



  • @vflorio94 A few questions:
    So you call calcolo_position() and it never returns, but gives that error?
    The intention of calcolo_position(sec) is to collect data for the time sec, about 2 values per second, and return the average values?
    Is the exact time the acquisition runs important?
    Edit:
    what is returned by lib_imu.get_euler()?



  • @robert-hh there isn't any line number.
    only this message

    ╝MemoryError: memory allocation failed, allocating 2029 bytes
    ╝>
    MicroPython v1.8.6-849-56d00234 on 2018-05-18; WiPy with ESP32
    Type "help()" for more information.```


  • @vflorio94 When the error pops ups, there is usually a line number shown. Which line number is it?



  • @robert-hh I think that the error can be caused by the function "Calcolo_position', because I call it more and more time when the code run
    thank you



  • @vflorio94 Which line is causing the error?



  • @robert-hh the line isn't indicate.
    I show you the code if you can help me i'll be greatful

    import machine 
    import pycom
    from machine import Timer
    import time
    import lib_imu
    from machine import I2C
    from math import sqrt
    from machine import PWM
    import gc
    def media(sequenza):
        # calculate mean
        return sum(sequenza[1:len(sequenza)]) / (len(sequenza)-1)
    
    def varianza(sequenza):
        # calculate variance
        mean = media(sequenza)
        return sum([(x-mean)**2 for x in sequenza])/len(sequenza)
    
    def dev_std(sequenza):
        # Calculate standard deviation
        return sqrt(varianza(sequenza))
    
    def calcolo_position(secondi):
    # function to calculate the position each second, the number of second is assigned
        gc.collect()
        # Configure I2C to extract euler angle
        lib_imu.set_configmode()
        time.sleep(0.03)
        # set unit
        lib_imu.set_units()
        time.sleep(0.03)
        # set mode
        lib_imu.set_mode('ndof')
        # create 3 lists 
        lista_heading = []
        lista_roll = []
        lista_pitch = []
        t = Timer.Chrono()
        t.start()
        time.sleep(0.1)
        while 1: 
            t_now = t.read() 
            if  t_now <= secondi:
                eul = lib_imu.get_euler()
                lista_heading.extend([eul[0]])
                lista_roll.extend([eul[1]])
                lista_pitch.extend([eul[2]])
                time.sleep(0.5) 
                if ( ((secondi - 0.5) < t_now < secondi)  & (len(lista_heading) == len(lista_roll)) & (len(lista_roll) == len(lista_pitch))):
                # Calculate mean and standard deviation
                    print(lista_heading)
                    print(lista_roll)
                    print(lista_pitch)
                    l = len(lista_pitch)
                    print("Calcolo media")
                    for i in range (0,l):
                        mean_pitch = media(lista_pitch)
                        mean_roll = media(lista_pitch)
                        mean_heading = media(lista_heading)
                    mean_pos = (mean_heading,mean_roll,mean_pitch)
                    # Calcolo deviazione standard
                    dev_std_heading = dev_std(lista_heading)
                    dev_std_roll = dev_std(lista_roll)
                    dev_std_pitch = dev_std(lista_pitch)
                    devstd_pos =(dev_std_heading, dev_std_roll, dev_std_pitch)
                    return mean_pos, devstd_pos
            else:
                t.stop()
                gc.collect()
                del lista_heading[0:l]
                del lista_pitch[0:l]
                del lista_roll[0:l]
                print("Acquisizione terminata")
                break
    def acquisizione_interval_pitch(delta_t,sec, mean_pos_ok,mean_pos_no, dev_std_no ):
        lib_imu.set_configmode()
        lib_imu.set_units()
        lib_imu.set_mode('ndof')
        pwm = PWM(1, frequency=2000) # timer indica il tempo di oscillazione alla specifica frequenza 
        pwm_c5 = pwm.channel(5, pin='P12') #dietro
        pwm_c4 = pwm.channel(4, pin='P7')  # dx
        pwm_c3 = pwm.channel(3, pin='P6')
        pwm_c2 = pwm.channel(2, pin='P5')   # avanti
        pwm_c1 = pwm.channel(1, pin='P3')   # sx
        pwm_c5.duty_cycle(0)
        time.sleep(0.01)
        pwm_c4.duty_cycle(0)
        time.sleep(0.01)
        pwm_c3.duty_cycle(0)
        time.sleep(0.01)
        pwm_c2.duty_cycle(0)
        time.sleep(0.01)
        pwm_c1.duty_cycle(0)
        time.sleep(0.01)
        # DAC
        dacRight = machine.DAC('P21') #right
        dacLeft = machine.DAC('P22') #left
        dacRight.deinit()
        dacLeft.deinit()
        # Intervallo di inclinazione
        if mean_pos_no[2] < mean_pos_ok[2]:
            position_intervalPitch = (mean_pos_ok[2] - mean_pos_no[2] - (dev_std_no[2])/2 ) 
        elif  mean_pos_no[2] > mean_pos_ok[2]:
            position_intervalPitch = (mean_pos_no[2] - mean_pos_ok[2] - (dev_std_no[2])/2 )
        print("intervallo totale", position_intervalPitch)
        delta_i = position_intervalPitch / 4 #imposto un valore fisso per la suddivisione dell'intervallo
        # CRONOMETRO
        chrono_i = Timer.Chrono()
        chrono_i.start()
        time.sleep(0.01)
        position_sec = []
        while 1:
            chrono_i_now = chrono_i.read()
            x = 500
            y = 3
            if chrono_i_now <= delta_t:
                gc.collect()
                position_sec = calcolo_position(sec)
                media_pos_sec= position_sec[0]
                dev_std_pos_sec = position_sec[1]  
                # Calcolo per il pitch : movimento avanti-indietro
                # Calcolo posizioni di partenza, tenendo conto della std:
                # - maggiore di 90° indietro
                # - minore di 90° avanti        
                start_p_av = (mean_pos_ok[2] - (dev_std_no[2])/2 )
                start_p_ind = (mean_pos_ok[2] + (dev_std_no[2])/2 )
                print("start avanti",start_p_av )
                print("start ind",start_p_ind)
                # Movimento AVANTI: pwm C2 = P5
                if media_pos_sec[2] <= mean_pos_ok[2]: 
                    if start_p_av <= media_pos_sec[2] < (start_p_av - delta_i):
                        # for x in seq:
                        #     pwm_c2.duty_cycle(x)
                        pwm_c2.duty_cycle(0.3)
                        pwm_c4.duty_cycle(0)
                        pwm_c5.duty_cycle(0)
                        pwm_c1.duty_cycle(0)
                        time.sleep(0.01)
                        dacLeft.deinit()
                        dacRight.init()
                        dacRight.tone(x,y)
                        time.sleep(0.01)
                    elif (start_p_av - delta_i) <= media_pos_sec[2] < (start_p_av - (2)*delta_i):
                        pwm_c2.duty_cycle(0.5)
                        pwm_c5.duty_cycle(0)
                        pwm_c4.duty_cycle(0)
                        pwm_c1.duty_cycle(0)
                        time.sleep(0.05)
                        dacLeft.deinit()
                        dacRight.init()
                        x= x + 1000
                        y = y - 1
                        dacRight.tone(x,y)
                        time.sleep(0.01)
                    elif (start_p_av - 2*delta_i) <= media_pos_sec[2] < (start_p_av - (3)*delta_i): 
                        pwm_c5.duty_cycle(0)
                        pwm_c4.duty_cycle(0)
                        pwm_c2.duty_cycle(0.7)
                        pwm_c1.duty_cycle(0)
                        time.sleep(0.01) 
                        dacLeft.deinit()
                        dacRight.init()
                        x= x + 2000
                        y = y - 1
                        dacRight.tone(x,y)
                        time.sleep(0.01)
                    elif (start_p_av - 3*delta_i) <= media_pos_sec[2] < (start_p_av - (4)*delta_i): 
                        pwm_c5.duty_cycle(0)
                        pwm_c4.duty_cycle(0)
                        pwm_c2.duty_cycle(0.8)
                        pwm_c1.duty_cycle(0)
                        time.sleep(0.01) 
                        dacLeft.deinit()
                        dacRight.init()
                        x= x + 3000
                        y = y - 1
                        dacRight.tone(x,y)
                        time.sleep(0.01) 
                    elif media_pos_sec[2] <= (start_p_av - 4*delta_i)  :                                             
                        pwm_c5.duty_cycle(0.5)
                        pwm_c4.duty_cycle(0.5)
                        pwm_c2.duty_cycle(0.5)
                        pwm_c1.duty_cycle(0.5)
                        time.sleep(0.01) 
                        dacLeft.deinit()
                        dacRight.init()
                        x= x + 4000
                        y = y - 1
                        dacRight.tone(x,y)
                        time.sleep(0.01)
                # Movimento INDIETRO: pwm C5 = P12
                elif media_pos_sec[2] > mean_pos_ok[2]: 
                    if start_p_ind <= media_pos_sec[2] < (start_p_ind + delta_i):
                        # for x in seq:
                        #     pwm_c2.duty_cycle(x)
                        pwm_c2.duty_cycle(0)
                        pwm_c4.duty_cycle(0)
                        pwm_c5.duty_cycle(0.3)
                        pwm_c1.duty_cycle(0)
                        time.sleep(0.01)
                        dacLeft.deinit()
                        dacRight.init()
                        dacRight.tone(x,y)
                        time.sleep(0.01)
                    elif (start_p_ind + delta_i) <= media_pos_sec[2] < (start_p_ind + (2)*delta_i):
                        pwm_c2.duty_cycle(0)
                        pwm_c5.duty_cycle(0.5)
                        pwm_c4.duty_cycle(0)
                        pwm_c1.duty_cycle(0)
                        time.sleep(0.05)
                        dacLeft.deinit()
                        dacRight.init()
                        x= x + 1000
                        y = y - 1
                        dacRight.tone(x,y)
                        time.sleep(0.01)
                    elif (start_p_ind + 2*delta_i) <= media_pos_sec[2] < (start_p_ind + (3)*delta_i): 
                        pwm_c5.duty_cycle(0.7)
                        pwm_c4.duty_cycle(0)
                        pwm_c2.duty_cycle(0)
                        pwm_c1.duty_cycle(0)
                        time.sleep(0.01) 
                        dacLeft.deinit()
                        dacRight.init()
                        x= x + 2000
                        y = y - 1
                        dacRight.tone(x,y)
                        time.sleep(0.01)
                    elif (start_p_ind + 3*delta_i) <= media_pos_sec[2] < (start_p_ind + (4)*delta_i): 
                        pwm_c5.duty_cycle(0.8)
                        pwm_c4.duty_cycle(0)
                        pwm_c2.duty_cycle(0)
                        pwm_c1.duty_cycle(0)
                        time.sleep(0.01) 
                        dacLeft.deinit()
                        dacRight.init()
                        x= x + 3000
                        y = y - 1
                        dacRight.tone(x,y)
                        time.sleep(0.01) 
                    elif media_pos_sec[2] >= (start_p_ind + 4*delta_i)  :                                             
                        pwm_c5.duty_cycle(0.5)
                        pwm_c4.duty_cycle(0.5)
                        pwm_c2.duty_cycle(0.5)
                        pwm_c1.duty_cycle(0.5)
                        time.sleep(0.01) 
                        dacLeft.deinit()
                        dacRight.init()
                        x= x + 4000
                        y = y - 1
                        dacRight.tone(x,y)
                        time.sleep(0.01)
                    time.sleep(0.01) 
                    dacRight.deinit()
                    dacLeft.init()
                    x= x + 1000
                    y = y - 1
                    dacLeft.tone(x,y)
                    time.sleep(0.01)
            else:
                chrono_i.stop()
                print("fine prova")
                pwm_c5.duty_cycle(0)
                pwm_c4.duty_cycle(0)
                pwm_c2.duty_cycle(0)
                pwm_c1.duty_cycle(0)
                dacRight.deinit()
                dacLeft.deinit()
                break
    # the instruction like the main, in which I use the function
    print("START ACQUISITION")
    print("Rilevazione posizione corretta")
    time.sleep(1)
    position_ok = []
    position_ok = calcolo_position(6)
    mean_pos_ok = position_ok[0]
    print("media posizione corretta", mean_pos_ok[2])
    dev_std_ok = position_ok[1]
    gc.collect()
    print("END FIRST ACQUISITION")
    time.sleep(2)
    print("SECOND AQUISITION ")
    time.sleep(1)
    position_no =[]
    position_no = calcolo_position(6)
    mean_pos_no = position_no[0]
    dev_std_no = position_no[1]
    gc.collect()
    print("END SECOND AQUISITION")
    time.sleep(1)
    print("START test pitch")
    time.sleep(1)
    acquisizione_interval_pitch(20, 1,  mean_pos_ok, mean_pos_no, dev_std_no )
    


  • @vflorio94 The error message shown below:

    MemoryError: memory allocation failed, allocating 1954 bytes
    

    tells, that your code wants to allocat a chunk of memory. What line is causing that? Doese teh code create a buffer, or doesn it try to write to a file?
    Just the explanation of the code does not help, we need the source to help you, since it's about the little details.



  • @robert-hh
    in the code, first I collect the data about position in a time interval of 1 second and I immediately use this data to set an output.
    But in the next second I need to recalculate the data position and the data that i use before now aren't important and I don't need them.
    I go on like this for 20 second or more.



  • @vflorio94 So it looks like a heap fragmentation problem, and it's hard to tellm what to do without knowing the code. The basic rule with heap fragmentation is to avoid allocation of large objects over and over, and instead to allocate buffers only once and re-use them. If slices are needed, use memoryview to create a slice.



  • @robert-hh thank you, I use the command gc.collect() as you suggets but the first time that I run my code it works, but then, when I want to run for the second time the same code, it print me the same error in memory allocation.
    In my code I define a function and I call it in another part of my code.
    I call the function that calculate the position every 1 second during a time interval of 20 second.

    so, what do you think that it's better to do ?
    thank you a lot



  • @vflorio94 WiPy2 is short of RAM.
    If that happens immediately during import, then you may have to put some of your code into frozen bytecode. For that, you have to build you own firmware images. Once set up, that is not complicated. But the way of setting up looks difficult, even if it's not. Just follow the documentation step by step.

    If the message comes up when the code runs, adding
    gc.collect() at certain places in your code may help to reduce heap fragmentation.

    Some information can also be found here: http://docs.micropython.org/en/latest/pyboard/reference/speed_python.html, sections "Buffers", "Arrays" and "Controlling garbage collection"



  • @robert-hh sorry, can I ask you about another problem?
    I extract data from I2C and i do lot of calculation in real time.
    I need data in real time and I compare them in real time to some reference value to give feedback to the subject. But my code has a problem.

    MemoryError: memory allocation failed, allocating 1954 bytes```
    How I can solve it?
    Thank you


  • @robert-hh for the moment I am able to use ftp with filezilla and it works.
    thank you very much, your help was very important.



  • @vflorio94 For FTP, please follow the documentation: https://docs.pycom.io/chapter/gettingstarted/programming/FTP.html
    I never user MQTT mself, but other people mentioned having it used. So maybe someone stpes in and explains.
    There is also a mesh protocol in preparation by pycom, which, as far as I can tell, could be used for your purpose. That is already part of the development variants of the firmware.



  • Thank you for your suggest, but I haven't ftp on my pc.
    Can you give me more information or a simple example about how to do ponit 'a' and also 'd'?

    I don't know anything about mqtt that you mentioned in pont 'd' and if I want to use point 'a' I have no idea on how to use ftp of my wipy and initiate the process by PC.

    thanks in advance



  • @vflorio94 You have a few options:
    a) Once the data is save on your WIPY, you can transfer the to you PC by accessing the WIPY file system with ftp. That transfer is initiated by the PC
    b) You can open a telnet session to the WiPy, print the data to the telnet screen an log the screen on the PC to a file.
    c) If you have a ftp server on your PC, you can install an ftp client on your WiPy and transfer the files from WIPY to the PC. That transfer is initiated by the WIPY.
    d) You can use a protocol like mqtt to transfer data to the PC at the time when the data is acquired.
    .....



Pycom on Twitter