MrYsLab / telemetrix

A user-extensible replacement for StandardFirmata. All without the complexity of Firmata!
GNU Affero General Public License v3.0
68 stars 26 forks source link

Error trying to register digital and analog pins together #36

Closed caipiranima closed 2 years ago

caipiranima commented 2 years ago

First of all, thank you very much for this incredible project. It is simple and powerfull!

I created a clock that works like this: a Raspebrry Pi controlling and Arduino that at every minute call a program write in Python/Telemetrix that updates the clock. The clock has three wheels with the numbers, a step motor controlling each one and a sensor for each that identifies when a number was changed to stop the motor.

So far, I managed to make the clock work if it is already configured. Then I tryied to create a mechanism to configure the clock when it is first powered on, and that is my problem.

I use a set of buttons connected to the digital pins (2, 3, 4, 5). I also use the analog pins 0, 1 and 2 for the sensors to stop the motors.

The problem is when I call the method sundial.update_time_cylinder from inside the callback of the button press (configure_sundail.handle_btn_pressed), it starts the motor but never stops. It seens the callback sundial.stop_sensor_change is never called.

I want to knopw if you have some clue of what I'm doing wrong. The file update_time.py is the one executed every minute and it calls sundial.update_time_cylinder, but this way it works.

Thank you!

Link for the code: https://gist.github.com/caipiranima/4ce87a6d10f74164beb8c87c72a3364f

MrYsLab commented 2 years ago

@caipiranima Thanks for providing the code. The problem may have something to do with re-initializing the analog input pin. Could you please try removing:

the_board.set_pin_mode_analog_input(STOP_SENSOR_PIN[cylinder_idx], differential=10, callback=stop_sensor_change)

from _stop_sensorchange() and initialize each analog input pin in _configuresundial.py?

Please let me know if that resolves the issue or not. Thanks.

caipiranima commented 2 years ago

Thank you for the reply!

I tryed what you suggested but with no success. It seems that the problem is to call sundial.update_time_cylinder from inside a callback function (in this case configure_sundail.handle_btn_pressed). When I call it directly it works.

I don't know if it is something related to sync or async functions, I'm not very familiar with those concepts.

I'll keep trying.

Thank you again!

MrYsLab commented 2 years ago

Thanks for letting me know. Asyncio does not come into play since you are using the non-asyncio library. Revisiting your code, I don't understand the relationship between configure_sundial.py and the two other Python scripts.

I assume you are running a single Python script that does not do what you wish. If you can provide that script, I would be happy to look at it to try to figure the problem out.

I don't know if you are comfortable with working with Python classes or not, but I have been burned by using Globals in Python. Placing everything in a class (or two) alleviates the need for globals and makes everything explicit. Thanks.

caipiranima commented 2 years ago

Those three scripts are the only ones I'm using. I call configure_sundial.py when I turn on the clock to set the time and update_time.py every minute to update the clock display. Then both call sundial.update_time_cylinder to change the number displayed.

I think I figured a solution for now. I changed the way I handle the digital pin callback. Now, instead of call sundial.update_time_cylinder on the callback, I just set some flags and call the function on the main one. This way I get rid of the global board variable. Also I have more control over multiple callings of sundial.update_time_cylinder. I updated the gist, if somenone is interested:

I still have an issue, a "Maximum number of steppers has already been assigned" exception. I think it is because I set the motor many times but not unregister it (don't know if it is possible). The best way to do that seem to use classes, as you suggested. This way I can instatiate only once each motor and problably don't get the exception again.

Thank you very much for all the help and this incredible library. I learned a lot in the proccess. Keep up with the amazing work!

MrYsLab commented 2 years ago

I am unsure why the code is spread across three files, but that might be a matter of coding style.

I prefer to have all the code in a single file, whether a class is used to implement the design or not.

In general, a set_pin_mode type method call should only be done once. That goes for all pin types - digital, analog, and stepper. You might wish to initialize all the pins in configure_sundial().

caipiranima commented 2 years ago

I have two programs that run in different moments. And then I have a common method used by both, that's why I created a third file. But yes, it is possible to make in a single file.

Well, I'll close the issue. Again, thank you for the help!