I have a a stepper motor running a different pattern for each key press on an IR remote. I am struggling with two things though.
If I am running a pattern and press a different key I need that new key press to interrupt the current process and start the pattern assigned to that key.
When it does start the new pattern I need it to first go back to starting point. The same starting point for all patterns.
I am sure this isnt complicated but I just cant seem to figure it out on my own.
Below is my current code.
#include "IRremote.h"
uint16_t RECV_PIN = 5;
IRrecv irremote(RECV_PIN);
decode_results results;
const int stepPin = 4;
const int dirPin = 3;
#define CW 0
#define CCW 1
#define DELAYMICROS 250
void rotate(int round, int direction) {
if (direction == CCW) {
digitalWrite(dirPin, HIGH); // Enables the motor to move in a particular direction
} else {
digitalWrite(dirPin, LOW); //Changes the rotations direction
}
while (round > 0) {
for (int x = 0; x < 400; x++) {
digitalWrite(stepPin, HIGH);
delayMicroseconds(DELAYMICROS);
digitalWrite(stepPin, LOW);
delayMicroseconds(DELAYMICROS);
}
round = round - 1;
}
}
void pattern1(){
//Rotate 3 times, pause 1 second, rotate 3 times, pause 1 second, rotate 3 times, pause 5 seconds, return to start position
rotate(3, CW);
delay(1000);
rotate(3, CW);
delay(1000);
rotate(3, CW);
delay(1000);
rotate(9, CCW);
}
}
void pattern2(){
//Rotate 3 times, pause 1 second, rotate 3 times, pause 1 second, rotate 3 times, pause 5 seconds, return to start position
rotate(1, CW);
delay(1000);
rotate(1, CW);
delay(1000);
rotate(1, CW);
delay(1000);
rotate(3, CCW);
}
void setup() {
Serial.begin(9600);
irremote.enableIRIn();
// Sets the two pins as Outputs
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
}
void loop() {
if (irremote.decode(&results)) {
if (results.value >> 32) // print() & println() can't handle printing long longs. (uint64_t)
Serial.print((uint32_t) (results.value >> 32), HEX); // print the first part of the message
Serial.println((uint32_t) (results.value & 0xFFFFFFFF), HEX); // print the second part of the message
switch(results.value){
case 0xFF30CF:
Serial.println("1");
pattern1();
break;
case 0xFF18E7:
Serial.println("2");
pattern2();
break;
case 0xFF7A85:
Serial.println("3");
pattern1();
break;
case 0xFF10EF:
Serial.println("4");
pattern1();
break;
case 0xFF38C7:
Serial.println("5");
pattern1();
break;
case 0xFF5AA5:
Serial.println("6");
pattern1();
break;
case 0xFF42BD:
Serial.println("7");
pattern1();
break;
case 0xFF4AB5:
Serial.println("8");
pattern1();
break;
case 0xFF52AD:
Serial.println("9");
pattern1();
break;
}
irremote.resume(); //again rcv
}
delay(100);
}
Your stepper code uses delay(), while and for loops so is blocking code. Nothing else can happen while the for loops, while loops and delays execute. You have to wait till they are done to do anything else. You need to write non-blocking code to have responsive code. The AccelStepper and MobaTools stepper libraries (among others) have non-blocking ways to control steppers. Also using milllis() and micros() to do non- blocking timing to replace delays.
Non-blocking timing tutorials: Blink without delay(). Beginner's guide to millis(). Several things at a time.
I think that the MobaTools library is a bit easier to learn. See the documentation.
That is correct. And a for loop or while loop will loop until it finishes before the processor can check for anything new. The key is to do things one little step at a time each time through loop. The several things at a time tutorial shows how to do this. Writing non blocking code is probably the hardest part of embedded processor programming.
Admittedly there are a lot of things to learn. I have been at this microcontroller hobby for 50 years (Arduino and C++ for 10 years) and learn stuff every day. Keeps one interested.
The stepper libraries can help a lot.
If you still want to write your own stepper code (and that is perfectly fine), Robin2's simple stepper code tutorial is a starting point. He shows how to do stepping without blocking, too.
It’s been fun to learn. So many options are out there.
I don’t necessarily need to write my own code I just haven’t been able to piece together using an IR remote to initiate patterns on a servo with the actual servo control any other way.
The beginners guide to millis() is a pretty long and pretty deep introduction how to use millis()
for non-blockling timing
I claim that my tutorial gives at least a much quicker overview how the principle of non-blocking timing works and is easier to understand as it uses an everyday example
I recommend using the MobaTools. The MobaTools create the step-pulses based on a timer-interrupt
this enables to create the step-pulses in the backround.
The MobaTools use hardware-Timer1
IR-remote uses hardware-Timer2 by default.
On AVR-Arduinos (= Arduino-Uno, Arduino-Mega 2560) has not many hardwaretimers.
Things like analogWrite, tone(), Servo use hardware-timers too and will conflict with the IR-library or the MobaTools-library
If you need all of these MobaTools, and IR-remote, and analogWrite, and tone(), and Servo all together the best solution will be to migrate to a microcontroller that has much more hardware-timer-ressources than a microcontroller-board based on an AVR-microcontroller.
The MobaTools manage the stepper-position internally
You can do a stop-command at any time and simply call myStepper.MoveTo(0) and this will drive back to the zero-point.
One question though. Will the stepper be able to remember the position of “0” if it loses power mid movement? Or upon powering back up will it assume it’s current position is “0”?
I’m trying to avoid adding a limit switch if I can.
No it can't. The reason is that a stepper-motor has nothing to report its position.
How should any kind of system do that if your stepper-motor does more than one rotation?
This requires a sensor that is mounted along the whole driveway if the stepper-motor makes something moving linear
or
a sensor that counts steps and multiple rotations and keep this information even on power-loss.
Compared to that a limit-switch is pretty simple.
The Company Trinamic has stepper-motor-drivers (TMC2209) that can detect a "stall" electronically.
I haven't researched if this enables to use driving the stepper-motor against a mechanical endstop as the "reference-point" . But I guess it is very likely that it works for that.
Moving a stepper-motor against a mechanical endstop is not very smart but if your mechanic is robust enough the steppermotor itself can stand it. Rambling against mechancial blocking needs just the same current as smooth moving or steppermotor standing still.
Ok that’s what I thought. The motor is only going 6rpm and it’s attached to a 30:1 speed reducer so it won’t be hitting the limit switch with much speed. No different than a 3D printer finding its home position is it?
unprecise posting. What is "No different"
Depends on the 3D-printer
You haven't specified if "No different" means 3D-printer has a limit switch
or
if "No different" means 3D-printer finds home-position by run agains mechanical endstop
If you want to proceed at 150% speed compared to short postings that cost extra time through an extra round of asking back and answering
you post detailed and precise information self-initiated.
proceeding in a user-forum is very different from snap-chattering
I’m trying to use these forums correctly, sorry if I’m not proficient yet. Very new to this type of forum and project.
My reference to a 3D printer is that it will use a mechanical end stop to establish the print heads position. So I think doing the same for my project is a logical next step now that I know for sure my stepper motor will not be able to know it’s position without something to tell it where it is.
Very important and good point. And a wonderful example that describing a lot of details is helpful to find a good solution.
Depending on the precisision you need in finding the reference-point different principles of limitswitches can be used.
If you repeat finding the reference-point at which the limit switch changes and the required precision is 0,2 mm any kind of simple mechanical switch will do
for higher precisions a precise microswitch would be nescessary.
mechanical switches wear out if you push them 10-thousands of times
induktive proximity switches don't wear out but have a bigger size than a mechanical microswitch
depending on their quality and price you can have 0,05 mm precision in repeating finding the reference-point. I know this from personal experience with programming special engineered machines.
Of course I don't want to force you to damage your mechanics for my personal curiosity.
But it would be indeed an interesting experiment of the trinamic steper-motor-drivers with their electronic stallguard-function would be able to detect the mechanical rammed-block early enough to prevent the stepper-motor to damage the gear or the mechanical endstop.
Precision and repeatability of homing can be increased by approaching the limit switch (mechanical, optical or magnetic [Hall Effec]) at higher speed till it actuates, then backing away from the switch (pull off) an approaching it again at a much slower speed. That is the way that Grbl and Marlin control firmware do it.