Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PONG #17

Open
ProbablyNotAaronFrater opened this issue Apr 6, 2024 · 3 comments
Open

PONG #17

ProbablyNotAaronFrater opened this issue Apr 6, 2024 · 3 comments

Comments

@ProbablyNotAaronFrater
Copy link

Hello,
My senior design team and I (we are seniors in an EE program) are working on a display for the game PONG using two stepper motors and the CoreXY methodology. We are using your code to run the motors simultaneously to decrease the jerkiness of the motion. We are having a hard time figuring out where the "Move Complete" flag is stored. We'd like to use it as a flag to start the next movement.
Can you help?

@juanmf
Copy link
Owner

juanmf commented Apr 6, 2024

Hi,
Interesting application, I'd use the getMpCustomTorqueCharacteristicsDRV8825With factory method if you managed to benchmark your motors (it's hard to do on a finite linear actuator, because it can't continually rotate) otherwise Exponential is very good.

Stepping jobs act like Future proxies (in fact they contain 3 Futures but the result() of a Jobs is a proxy of the result() call to the "job done" future.), Following snippet goes back and forth 1/8th of rotation for ever.

from stepper_motors_juanmf1.Controller import MotorDriver, BipolarStepperMotorDriver
from stepper_motors_juanmf1.ControllerFactory import MultiProcessingControllerFactory
from stepper_motors_juanmf1.StepperMotor import GenericStepper, PG35S_D48_HHC2


def main():
    factory = MultiProcessingControllerFactory()
    motor = GenericStepper(minPps=50, maxPps=300, maxSleepTime=1/50, minSleepTime=1/300, spr=200)
    # motor = PG35S_D48_HHC2(loaded=True)

    driver: BipolarStepperMotorDriver = (factory.setUpProcess()
            .withDriver(multiprocessObserver=None,
                        factoryFnReference=factory.getMpExponentialTMC2209With,
                        # factoryFnReference=factory.getMpCustomTorqueCharacteristicsDRV8825With,
                        stepperMotor=motor, directionGpioPin=16, stepGpioPin=20, enableGpioPin=21)
            .spawn())[0]

    while True:
        driver.signedSteps(int(motor.spr * 1/8)).result()
        driver.signedSteps(-int(motor.spr * 1/8)).result()

You could also use events. If you need not to block on a stepping job, say your app needs to keep vigilant of balls coming, then you could be open to change course on the fly or wait for 2 built in events:

  • <your optionalEventNamePrefix>steppingCompleteAdvance fired by default 10 steps prior to completion. Fired from stepper_motors_juanmf1.Navigation.Navigation.go
  • <your optionalEventNamePrefix>steppingCompleteFinalStep fires on last step, technically before the stepping job completes. Fired from stepper_motors_juanmf1.Controller.BipolarStepperMotorDriver._doOperateStepper.

So, if you are confident you can wait until a job is done to decide on next move, use the snippet as example.

@ProbablyNotAaronFrater
Copy link
Author

I'm running two motors synchronously and need to know when the move I have given them is complete so I can tell them to move again. Currently we are using the sleep command as a poor substitute to ensure the motors don't get overlapping commands. I am an EE and not a CompSci major so I apologize if I am asking an ignorant question.

@juanmf
Copy link
Owner

juanmf commented Apr 8, 2024

No worries,

Your (basic) answer is already there.

No Sleep

Above, these lines complete 1/8th turn in one direction, no time.sleep used, then goes back to original position. then repeat.

    # .result() blocks until stepping job is done.
    while True:
        driver.signedSteps(int(motor.spr * 1/8)).result(). 
        driver.signedSteps(-int(motor.spr * 1/8)).result()

2 motors in sync

Make sure you use the MultiProcessingControllerFactory factory to minimize pulse timing issues (also start your app with nice -15 or something high to help here) .

Then you have several scenarios.

  1. your main app can have the luxury of blocking while motors work (your time.sleep case is a poor approach to this one).
xJob = driverX.signedSteps(300)
yJob = driverY.signedSteps(200)

# We get here immediately, jobs probably didn't start yet.
xJob.result(). # blocks until done
yJob.result()  # blocks until done, continues if already done

print("both drivers just completed their job, but this thread was blocked all along")
  1. You can't afford to block because your app need to be responsive to other events. I'd assume a PONG game won't work well with blocking. Maybe you are going to an initial position and the opponent already shot, so you need to change course before running stepping job is done.

Simplest approach is same as before but instead of blocking right away you test for some input.

If there are other parts of your system that need to get notified of a stepping job done you could use the EventDispatecher to register listeners. But that's a more sophisticated topic.

Hope this helps.

BTW BasicSynchronizedNavigation has a latch feature to start motors after the last expected one sent it's job for stepping. If you want full sync, including starts time. If motors/drivers are of the same kind, this can be more efficient as both motors' initial and subsequent pulses would require one go through the logic, emitting signals perfectly at the same time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants