ev3dev / ev3dev-lang-python

Pure python bindings for ev3dev
MIT License
425 stars 144 forks source link

Program Exits w/ OSError: 24 After 47 Consecutive Calls of a Function That is Under Test #689

Closed ghost closed 4 years ago

ghost commented 4 years ago

WHAT'S GOING ON:

My team was running a test of a function for their EV3 robot called FORWARD. Using nested loops to increment the power and distance, they were evaluating the error in the function.

Without fail, after running the command with new variables, 46 times, on the 47th, they got this error message.

Line 326 is the function call: Forward(Speed, Distance, Ramp_Up, Ramp_Down, Brake_On, State)
In the function, line 137 is: Motor_Left = LargeMotor(OUTPUT_A)

Traceback (most recent call last):
--
File "/home/robot/District2019/workbench.py", line 326, in <module>
File "/home/robot/District2019/workbench.py", line 137, in Forward
File "ev3dev2/motor.py", line 1109, in __init__
File "ev3dev2/motor.py", line 413, in __init__
File "ev3dev2/motor.py", line 471, in count_per_rot
File "ev3dev2/__init__.py", line 298, in get_cached_attr_int
File "ev3dev2/__init__.py", line 291, in get_attr_int
File "ev3dev2/__init__.py", line 249, in _get_attribute
File "ev3dev2/__init__.py", line 249, in _get_attribute
File "ev3dev2/__init__.py", line 288, in _raise_friendly_access_error
File "ev3dev2/__init__.py", line 244, in _get_attribute
File "ev3dev2/__init__.py", line 238, in _attribute_file_open
OSError: 24
----------
Exited with error code 1.

OSError: 24 is "Too many files open" according to what I could find.

I have no idea what that means.

I have a 64GB card that EV3DEV2 is loaded on.

There is no error handling in the function or the module.

I don't think this will affect us in competition as there probably won't be more than 20 move/turn function calls per run.

Any thoughts on what this is, or what can be done would be appreciated.

dlech commented 4 years ago

FYI, SD cards > 32GB are not supported.

It looks like you are creating a new LargeMotor object each time you call the function. This should only be done once per program per motor.

ghost commented 4 years ago

Thank you!

That makes perfect sense, seeing where it is bombing.

Should I have the kids add that to the robot state initialization function they have that sets up the robot's initial position and orientation or at the beginning of the module/main program?

Does the same proscription against multiple calls of the LargeMotor apply to the MoveSteering command, also?

The kids are using the MoveSteering to drive the motors, but needed to get the position and speed of each motor to check the robot's travel distance, and used the LargeMotor object to access that data.

Re: the SD Card - it is 32GB.

Thanks again!

WasabiFan commented 4 years ago

The idea is just that you should use a long-lived instance for things like motors and Drive objects. Setting up a Motor is slow, so you should do it once then use it for the duration.

ghost commented 4 years ago

Would the same advice apply to sensors?

WasabiFan commented 4 years ago

Yes. Pretty much every class in this library, when initialized, has to do some file I/O to prepare to talk to the device it's supposed to interact with. They aren't designed to be rapidly created or have lots of them in memory at once.

ghost commented 4 years ago

I just tested it. Worked like a charm. I think I know how to explain it to them when we meet next.

I declared the MoveSteering and 2 LargeMotor objects at the beginning of the module and passed them into the Forward function, e.g.:

Forward(Speed, Distance, Ramp_Up, Ramp_Down, Brake_On, State, DriveMotors, LeftMotor, RightMotor)

But then I tested instantiating the LargeMotors and MoveSteering and didn't pass them in"

Forward(Speed, Distance, Ramp_Up, Ramp_Down, Brake_On, State)

And it still worked - so I guess they are global in scope.

Method 2 is less complicated - I suppose we'll go with that, although my kids will give me back my own warning talk about the evils of Globals.

The kids wanted to do something beyond the EV3-G environment, so we've all tried to muddle our way through Python this FLL season and I'm luckily a few steps ahead of the kids.

Thanks @dlech and @WasabiFan for the late night help.

BTW: It also began running WAYYYYY faster than before - like 5-6 seconds.

WasabiFan commented 4 years ago

Glad to hear it! Classes in this library are designed to be instantiated once then used forever, so they're optimized for that case. Good to hear it's faster.