Closed tonymonty73 closed 10 months ago
I think the problem is as follows.
Internally the micro_gui
library uses asyncio
to achieve concurrency (see the tutorial). I wrote the library so it is usable by people without needing to write asynchronous code. However this has limits. When a callback runs, it needs to terminate before the library can refresh the screen with any changes. In particular issuing time.sleep()
in a callback is undesirable.
The solution is to write slow running code as an asynchronous task. Something like:
async def cycle(self):
self.homing_seq()
self.been_home_lbl.value("CYCLING")
step_n(2000,-1)
await asyncio.sleep(2) # Screen is refreshed during this delay
step_n(1500,-1)
await asyncio.sleep(2)
for i in range(4):
step_n(2000,-1)
await asyncio.sleep(2)
step_n(2000,1)
await asyncio.sleep(2)
for i in range(4):
step_n(2000,1)
await asyncio.sleep(2)
step_n(2000,-1)
await asyncio.sleep(2)
self.homing_seq()
def cycle_btn(self, button): # Callback launches a task
asyncio.create_task(self.cycle())
There is a little more work involved in making this a practical solution - you need to ensure that pressing the button while the task is running does not create another instance - but I've kept it simple to explain the concept. Welcome to the world of asynchronous programming!
Thank you very much for taking the time to help me. That explains a lot. I was also getting some ticks in the stepper motion. I'll look at that tutorial for sure. Again, these libraries are amazing! Thanks, Tony
you need to ensure that pressing the button while the task is running does not create another instance
One way is to have the task disable the button at the start, then re-enable it on completion.
Hi Peter, I'm pretty new to Python/micropython/micro-gui. Your libraries are top notch. I've practiced on a couple different screens. I'm using micro-gui with an ili9341. I'm practicing with a stepper and linear actuator. Everything is working except one place where I tried changing a label value to new text. It works elsewhere in the code but not in this one method. I hope it is OK that I just pasted the code below. The problem is in the button labeled with text "CYCLE". In it's callback, I try to issue self.been_home_lbl.value("CYCLING") and it doesn't change on the screen. The same label allows a change in another method with a successful change on the screen. I would also much appreciate your advice on my code anywhere else I may not be understanding things if it isn't too much trouble. Thank you, Tony M
from machine import Pin from stepper import Stepper import time
import hardware_setup from gui.core.ugui import Screen, ssd from gui.widgets import Button, CloseButton, Label from gui.core.writer import CWriter import gui.fonts.arial10 as arial10 import gui.fonts.arial35 as arial35 from gui.core.colors import * from gui.widgets import Label, Scale, ScaleLog, Button, CloseButton, Slider, HorizSlider, Knob, Checkbox
step_pin = 2 home_pin = 3 dir_pin = 5
s1 = Stepper(step_pin,dir_pin,steps_per_rev=200,speed_sps=1000) endswitch = machine.Pin(home_pin, machine.Pin.IN, machine.Pin.PULL_UP) wri = CWriter(ssd, arial10, WHITE, BLACK, verbose=False) big_btn_wri = CWriter(ssd, arial35, WHITE, BLACK, verbose=False)
def step_n(n,d): for i in range (n): s1.step(d)
def home_seq(): s1.speed(400) s1.free_run(-1) while endswitch.value() == 0: pass s1.stop() s1.overwrite_pos(0) s1.target(0) s1.speed(1000) s1.track_target()
class Motor1Screen(Screen):
class Motor2Screen(Screen):
class HomeScreen(Screen):
def test(): print('Stepper demo.') Screen.change(HomeScreen)
test()