Stop stepper motor when IR beam breaks, reliable and independent

Hey everyone,

Goal
I am building a bead dispenser, and I made some good progress so far. Users can input the number of plastic beads they want to receive. Let’s say a user enters 3. The stepper motor will start to rotate and if a single bead is falling through a hole in the dispenser, it will break the IR beam and the counter gets incremented. If the counter is equal to the user’s input the motor will stop.

The code of this scenario is here:

Problem
During development, I noticed that if Arduino is turning the stepper motor it is blocking subsequent code. Subsequently, I am actually performing the check if the IR beam was broken. Because of the blocking behavior, I ended up making the step size as little as possible (i.e., 1 — (see lines 90 and 91).
This code is working okay. Let’s say the accuracy is around 80%; however, I am looking for a different approach:

Solution
I am a freshman in the Arduino sphere but I guess there must be a solution to instruct the Arduino to rotate the stepper motor independently from IR beam breaker. However, once the input is satisfied, the motor should also stop and wait for new input.

I am trying to make a video now, I guess this could be helpful.
UPDATE:

of course, but as there is some latency between a bead falling in the hole and it's detection by the IR beam, you need to be careful how fast you rotate the motor or when you arrive at the expected count there might be already a new bead "in transit".

This is correct, controlling the speed is another issue, because at step size 1, values for the setSpeed(X) method have no effect... But I guess once the motor moves independently I regain control of speed...

the code does

while (isCounting) {
    myMotor->step(1, FORWARD, SINGLE);  // ➜ perform 1 step
   
  ➜  then do a state change detection 

if you want independent behavior, you need to use a library that is non blocking (if I remember correctly Adafruit_MotorShield is blocking). Using AccelStepper for example would let you achieve this

--> once you get a count from the Serial console you ask the motor to spin (set a very far step count) and then you await for the beads. Once you got the right count, you stop the motor.

bonus point, as you get closer to the count, you slow down the motor up to a point you go very slowly between two steps to ensure you don't get one extra bead.

1 Like

Thanks for the cue; I’ll check out AccelStepper — btw. is there any go-to library for stepper motors? I was just using the Adafruit Motorshield Library because it was used in some tutorial.

well if you have Adafruit's Motorshield then it kinda makes sense but it offers less features than AccelStepper.

There are multiple stepper libraries available, each with their values.

Hey @J-M-L; I added a few in my script to use the AccelStepper library, which indeed increases the accuracy a lot — Yet, I got a strange bug, and hope it is okay to follow up within this thread. Once I enter the first number in my Serial Monitor everything rotates at the given speed as it is supposed to be, and when the expelled beads equal the provided number the motor stops. Yet, if I enter the second number; the motor turns at a really slow pace (iooks like 1 step (1.8°) per second) slow.
Any idea why the first run is normal and consecutive runs are acting weird?

the updated code is here: arduino-dispenser/arduino-dispenser.ino at main · ccp-eva/arduino-dispenser · GitHub

thank you so much any help!

Your code is mixing now two ways to control the motor.. if you go AccelStepper you need to get rid of Adafruit_StepperMotor

I am actually following the Example:

they are also declaring this in line 25: Adafruit_Motor_Shield_V2_Library/Accel_ConstantSpeed.ino at master · adafruit/Adafruit_Motor_Shield_V2_Library · GitHub

No, the Accelstepper cannot directly drive a motor by means of the Adafruit_Motor_Shield_V2. This motorshield uses I2C commands for stepping. The Accelstepper lib needs assistance from the Adfruit_StepperMotor to do the steps.

1 Like

right I forgot they had this special case for the Motorshield v2 where you tell AccelStepper what are the functions to use to perform 1 step

try to issue the Astepper1.setSpeed(200); command before the Astepper1.runSpeed();

My assumption is that the stop()calls calculates how to slow down the motor and go to a complete stop safely and modifies the speed.

worth trying

1 Like

Thanks, @MicroBahner for chiming in. And thank you @J-M-L for that suggestion putting setSpeed() before runSpeed()! That actually did the trick! Love it!

great ! have fun