[QuecPython] A vicious BUG in the built-in GNSS positioning of the EC800M IoT development board (possible reason for failure to obtain data, currently there is no complete solution)

[QuecPython] A vicious BUG in the built-in GNSS positioning of the EC800M IoT development board (possible reason for failure to obtain data, currently there is no complete solution)

GNSS configuration is as follows:
【QuecPython】EC800M IoT development board’s built-in GNSS positioning acquisition (Beidou, GPS and GNSS)

Test video (including BUG reproduction):

[QuecPython] A vicious BUG in the built-in GNSS positioning of the EC800M IoT development board (there is currently no complete solution)

Program running bug

BUG recurrence:
In my previous article, I put an infinite loop in the main function
to read GNSS data every 1s At the same time, print it out through the serial port
The GNSS data is valid after running 25 times
I found that after running about 20 times (that is, the 45th time), the program will directly It will die and then recover after about 30 seconds
After recovery, it can continue to read and will not die again

Print has been printed before this death, and the serial port output is consistent, as shown in the figure:
Insert image description here
The relevant functions are all in my previous article

So I conducted the following test:

  1. Comments are sent via serial port. Just use print to find that it still exists.
  2. Replace time.sleep(1) with a for loop delay and find that GNSS data cannot be read, which leads to the second BUG.
  3. Keep GNSS initialization Will read GNSS annotations Only use serial port to print a number of times or just use print to find that it still exists
  4. Add GNSS initialization comments and GNSS reading comments. Only use serial port and print to print once. No BUG found.
  5. Keep GNSS initialization, annotate GNSS reading, conduct serial port and print tests indoors, and find no BUG.

I showed both Situation 3 and Situation 2 together in the video.

It can be seen that when a BUG occurs, it will occur after the GNSS module is initialized and powered on, and after the data needs to be obtained (regardless of whether it is read or not).

Main thread occupation BUG (can be solved)

GNSS itself becomes a thread after initialization, so it cannot be occupied by other threads. However, GNSS itself will also occupy other threads such as sound playback, etc.
The second situation mentioned above< /span>
wrote a simple delay:

def delay(n):
	for i in range(n):
		for j in range(500):
			i=i
delay(500)

The actual measured delay is about 1s slightly longer than 1s
As shown in the figure:
There is always no GNSS data (if the data is invalid, there is no Will return NMEA-0183 protocol data but the value inside does not exist)
and remain like this

Insert image description here
And do not use higher-priority peripherals such as hardware timers, otherwise GNSS will not be able to read the data.
For example:
【Quectel QuecPython] Hardware TIM timer of EC800M IoT development board with accurate delay

Possible causes of BUG and current solutions

This py environment is actually a virtual environment
The bottom layer is RTOS. Then RTOS generates an environment for running the command line in Python and finally executes py code through this environment< a i=2> That is, three levels of nesting

GNSS data cache out of bounds

It is observed that after the GNSS is successfully initialized and powered on and the first data can be read, it will run to death about 30 seconds after it begins
and it is particularly stable and always reaches that counting point< /span> To be verified However, it can continue to work after the runaway is restored, so it may be an initialized pointer. The location was not given correctly?
So it may be that the cache of the underlying register went out of bounds during this period, causing the runaway BUG.

Thread priority occupation

RTOS is mainly responsible for task scheduling of registers and CPU
Then it is possible that an infinite loop runs in the main thread, causing the thread of the GNSS module to be unable to perform initialization
But the manual does not mention this, it just says that it will seize LTE resources
It needs to be verified

Current solution

Multi-thread solution
Interrupt priority>Thread>Main thread
This method can solve the problem of GNSS being occupied by threads but cannot solve the problem of running Flying problem
In addition, it is not recommended to use multi-threading. One of the reasons is that if the thread is not forced to close or reset, it is unsafe and easy to cross the boundary

And do not use higher priority peripherals such as hardware timers, otherwise GNSS will not be able to read the data.

Appendix: List assignment types and py packaging

list assignment

BUG recurrence

I wrote a small program when I had nothing to do. The code is as follows:

# -*- coding: utf-8 -*-
"""
Created on Fri Nov 19 19:47:01 2021

@author: 16016
"""

a_list = ['0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15']
#print(len(a_list))
#b_list = ['','','','','','','','','','','','','','','','']
c_list = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]
#for i in range(16):
if len(a_list):
    for j in range(16):
        a_list[j]=str(a_list[j])+'_'+str(j)
        print("序号:",j)
        print('a_list:\n',a_list)
        
        
        c_list[j]=a_list
        print('c_list[0]:\n',c_list[0])
        print('\n')
#        b_list[j]=a_list[7],a_list[8]
#        print(b_list[j])
        # 写入到Excel:
#print(c_list,'\n')    

I made a 16-time for loop in the program and added "_" and the loop serial number after each value of list a.
For example, the xth time of looping is Add _x to the , '1_1', '2_2', '3_3', '4_4', '5_5', '6_6', '7_7', '8_8', '9_9', '10_10', '11_11', '12_12', ' 13_13', '14_14', '15_15'] This is also correct

At the same time, I write the value of list a into the empty list c during each cycle. For example, the xth cycle is to write the changed value of list a into the xth position of list c
The value of c[0] after the 0th loop should be ['0_0', '1', '2', '3', '4', '5', '6', '7' , '8', '9', '10', '11', '12', '13', '14', '15'] This is also correct
But in the 1st After this cycle, the value of c[0] has been changing into the value of c[x]
, which is equivalent to changing c_list[0] into c_list[1]...and so on. The value of the resulting list c is exactly the same for every item
I don’t understand what’s going on
My c[0] is only at the 0th time It is assigned a value during the loop but its value changes later

As shown in the figure:
Insert image description here
The first time a bug occurred. After the assignment, the value of c[0] was changed every time it was looped. It took a long time and it didn’t work out
No matter whether it is added with the append function or defined with a two-dimensional array or a third empty array is added for transition, it cannot be solved

Code improvements

Later, under the guidance of my Huake classmates, I suddenly thought that the assignment can be assigned to an address. The value in the address keeps changing, causing the assignment to keep changing. So I used the loop within loop deep copy in the second picture to implement it.

code show as below:

# -*- coding: utf-8 -*-
"""
Created on Fri Nov 19 19:47:01 2021

@author: 16016
"""

a_list = ['0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15']
#print(len(a_list))
#b_list = ['','','','','','','','','','','','','','','','']
c_list = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]
#for i in range(16):
if len(a_list):
    for j in range(16):
        a_list[j]=str(a_list[j])+'_'+str(j)
        print("序号:",j)
        print('a_list:\n',a_list)
        
        
        for i in range(16):
            c_list[j].append(a_list[i])
        print('c_list[0]:\n',c_list[0])
        print('\n')
#        b_list[j]=a_list[7],a_list[8]
#        print(b_list[j])
        # 写入到Excel:
print(c_list,'\n')    

solved the problem

Insert image description here

optimization

The third time I asked the teacher to use the copy function to assign a true value.

code show as below:

# -*- coding: utf-8 -*-
"""
Created on Fri Nov 19 19:47:01 2021

@author: 16016
"""

a_list = ['0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15']
#print(len(a_list))
#b_list = ['','','','','','','','','','','','','','','','']
c_list = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]
#for i in range(16):
if len(a_list):
    for j in range(16):
        a_list[j]=str(a_list[j])+'_'+str(j)
        print("序号:",j)
        print('a_list:\n',a_list)
        
        
        c_list[j]=a_list.copy()
        print('c_list[0]:\n',c_list[0])
        print('\n')
#        b_list[j]=a_list[7],a_list[8]
#        print(b_list[j])
        # 写入到Excel:
#print(c_list,'\n')    

The problem can also be solved
Insert image description here
Finally, the problem is concluded that the pointer is to blame!

a_list points to an address, not a value. a_list[i] points to a single value. The copy() function also copies a value, not an address.

If this is written in C language, it will be more intuitive. No wonder C language is the basis. If you don’t learn C in optical Python, you will not be able to solve such a problem.

C language yyds What kind of rubbish retarded language is Python?

Summarize

Since Python cannot define a value as a pointer or an independent value, it can only be transferred using a list
As long as the assignment points to a list as a whole, it is a pointer memory address. There is only one solution, which is to deeply copy and assign each value (extract the elements in the sublist and reconnect them in sequence) or use the copy function to assign values ​​individually

Test as shown:
Insert image description here
Insert image description here
Insert image description here
Insert image description here
Insert image description here
Part of the code:

# -*- coding: utf-8 -*-
"""
Created on Sat Nov 20 16:45:48 2021

@author: 16016
"""

def text1():
    A=[1,2,3]
    B=[[],[],[]]
    for i in range(len(A)):
        A[i]=A[i]+i
        B[i]=A
        print(B)

def text2():
    A=[1,2,3]
    B=[[],[],[]]
    
    A[0]=A[0]+0
    B[0]=A
    print(B)
    A[1]=A[1]+1
    B[1]=A
    print(B)
    A[2]=A[2]+2
    B[2]=A
    print(B)
    
if __name__ == '__main__':
    text1()
    print('\n')
    text2()

py package

Pyinstaller packages exe (including packaging resource files, never error version)

Dependent packages and their corresponding version numbers

PyQt5 5.10.1
PyQt5-Qt5 5.15.2
PyQt5-sip 12.9.0

pyinstaller 4.5.1
pyinstaller-hooks-contrib 2021.3

Pyinstaller -F setup.py package exe

Pyinstaller -F -w setup.py packaging without console

Pyinstaller -F -i xx.ico setup.py packages the specified exe icon package

Package exe parameter description:

-F: Only a single exe format file is generated after packaging;

-D: Default option, creates a directory containing exe files and a large number of dependent files;

-c: Default option, use the console (a black box similar to cmd);

-w: Do not use the console;

-p: Add a search path to find the corresponding library;

-i: Change the icon of the generated program.

If you want to package resource files
you need to convert the path in the code
Also note that if you want to package resource files py The path in the program needs to be changed from ./xxx/yy to xxx/yy and the path conversion is performed
But if the resource file is not packaged, it is best to use the path as ./xxx/yy and not perform the path conversion. Path conversion

def get_resource_path(relative_path):
    if hasattr(sys, '_MEIPASS'):
        return os.path.join(sys._MEIPASS, relative_path)
    return os.path.join(os.path.abspath("."), relative_path)

Then add the directory in the datas part of the spec file
For example:

a = Analysis(['cxk.py'],
             pathex=['D:\\Python Test\\cxk'],
             binaries=[],
             datas=[('root','root')],
             hiddenimports=[],
             hookspath=[],
             hooksconfig={
    
    },
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)

Then directly Pyinstaller -F setup.spec

If the packaged file is too large, just change the excludes in the spec file and include the libraries you don’t need (but have already been installed in the environment).

These unnecessary libraries are output in the shell during the last compilation
For example:
Insert image description here

Insert image description here
Then use pyinstaller --clean -F XX.spec

Guess you like

Origin blog.csdn.net/weixin_53403301/article/details/134212028