Recently, our team has been moving from C++ (VEXcode pro V5), over to the python platform offered by VEXcode V5.
In the past we have been using:
vex::task::yield();
to ensure control is passed between our many vex::task objects and threads while wasting as little time as possible.
The closest thing I have found in python is this:
wait(20, MSEC)
# Not necessarily 20 msecs, but you get the idea.
while this is an option, I would prefer a solution that doesn’t force the thread (or task) to wait the specified amount. Rather, something that allows as little time as possible to be “wasted” between times of control returned to the scheduler.
Desired functionality example:
def some_thread_callback():
while True:
# Do something
yield()
# Not to be confused with the built in 'yield' keyword for python generators
thread = Thread(some_thread_callback)
# main loop
while True:
# Do something
yield()
where each ’ yield() ’ would behave like vex::task::yield() found from C++, as seen below:
Just use sleep (or wait, same thing), wait(1, MSEC) is the closest you can get, there is no binding for yield.
You may also find that just having no delay (sleep etc.) in the loop works, I think I have a hook that calls yield for each loop iteration so python doesn’t ever block the scheduler.
but yield is rarely needed even in C++ code, what’s the actual use case ?
Now, in answer to your question, the code below is our use case (this code will run on our robot and work as intended)
def _drive_(distance, speed):
pid = PID(2.5, 0, 0, 200, 0, speed)
distance_in_degrees = distance / WHEEL_CIRCUMFRENCE *REVERSE_GEAR_RATIO * 360
for motor in DRIVE_MOTORS:
motor.set_position(0, DEGREES)
motor.set_velocity(0, PERCENT)
motor.set_stopping(BRAKE)
motor.spin(FORWARD)
not_done = True
last_time = brain.timer.time(SECONDS)
current_time = brain.timer.time(SECONDS)
while not_done:
error = distance_in_degrees - sum([motor.position(DEGREES) for motor in DRIVE_MOTORS]) / 6
last_time = current_time
current_time = brain.timer.time(SECONDS)
dt = current_time - last_time
speed = pid.update(error, dt)
for motor in DRIVE_MOTORS:
motor.set_velocity(speed, PERCENT)
if abs(error) < 0.5:
not_done = False
# This wait (and others) is where I was planning on implementing a 'yield()' function
wait(20, MSEC)
for motor in DRIVE_MOTORS:
motor.stop()
def drive(distance, speed, wait=True):
global THREAD
if wait == True:
_drive_(distance, speed)
else:
THREAD = Thread(_drive_, (distance, speed))
also…
I apologize for my confusion, but by ‘yield’ do you mean…
def infinite_counter():
i = 0
while True:
yield i
# ^ that yield ^
i += 1
Most loops that are controlling motors or reading sensors can sleep for a few mS as the motor/sensor update rate is not that fast. A PID loop also needs some delay otherwise derivative is almost always 0 as the error hasn’t changed.