Internet-controlled stepper motor - software issue

Hi there,

I’m trying to control a stepper motor from the internet by hacking together two tutorials that I read here and here.

Obviously, I’ve made a software error when trying to combine the two sets of code, since I get error messages when trying to flash to the device. Code copied below. Any suggestions?

// This #include statement was automatically added by the Particle IDE.
#include "PhoBot/PhoBot.h"


PhoBot p = PhoBot(12.0, 12.0);

void setup() {
    Spark.function("motor", motorSwitcher);
}

void loop() {
    forward(100, 5);
    reverse(100, 5);
}


void forward(int numSteps, int period) {
    int motorSwitcher(String command) {
        if(command.equalsIgnoreCase("on")){
            for (int i = 0; i < numSteps; i++) {
                p.setMotors("M3-F-100");
                p.setMotors("M4-B-100");
                delay(period);
                p.setMotors("M3-F-100");
                p.setMotors("M4-F-100");
                delay(period);
                p.setMotors("M3-B-50");
                p.setMotors("M4-F-50");
                delay(period);
                p.setMotors("M3-B-50");
                p.setMotors("M4-B-50");
                delay(period);
    } 
    }
}
}

void reverse(int numSteps, int period) {
    int motorSwitcher(String command)) {
        if(command.equalsIgnoreCase("off")){
            for (int i = 0; i < numSteps; i++) {
                p.setMotors("M3-B-100");
                p.setMotors("M4-B-100");
                delay(period);
                p.setMotors("M3-B-100");
                p.setMotors("M4-F-100");
                delay(period);
                p.setMotors("M3-F-50");
                p.setMotors("M4-F-50");
                delay(period);
                p.setMotors("M3-F-50");
                p.setMotors("M4-B-50");
                delay(period);
    }
    }
}
}

You shouldn’t have a function, motorSwitcher, inside other functions like forward or reverse. Instead, move that function outside, and use it to set a variable value which you would check inside of forward and reverse. Also, you should change Spark to Particle in your setup function.

// This #include statement was automatically added by the Particle IDE.
#include "PhoBot/PhoBot.h"

PhoBot p = PhoBot(12.0, 12.0);
String state = "on";

void setup() {
    Particle.function("motor", motorSwitcher);
}


void loop() {
    forward(100, 5);
    reverse(100, 5);
}

int motorSwitcher(String command) {
    if(command.equalsIgnoreCase("on")){
        state = "on";
    }else{
        state = "off";
    }
}



void forward(int numSteps, int period) {
    
     if(state == "on"){
        for (int i = 0; i < numSteps; i++) {
            p.setMotors("M3-F-100");
            p.setMotors("M4-B-100");
            delay(period);
            p.setMotors("M3-F-100");
            p.setMotors("M4-F-100");
            delay(period);
            p.setMotors("M3-B-50");
            p.setMotors("M4-F-50");
            delay(period);
            p.setMotors("M3-B-50");
            p.setMotors("M4-B-50");
            delay(period);
        }
    } 
}


void reverse(int numSteps, int period) {
    if(state == "off"){
        for (int i = 0; i < numSteps; i++) {
            p.setMotors("M3-B-100");
            p.setMotors("M4-B-100");
            delay(period);
            p.setMotors("M3-B-100");
            p.setMotors("M4-F-100");
            delay(period);
            p.setMotors("M3-F-50");
            p.setMotors("M4-F-50");
            delay(period);
            p.setMotors("M3-F-50");
            p.setMotors("M4-B-50");
            delay(period);
        }
    }
}

Hey Ric,

Thanks so much! That totally did the trick! The motor is now successfully moving one direction when I click “ON” and then moving the other direction when I click “OFF.”

One final question: how do I edit the script so that the motor will only spin for 30 seconds in a given direction? I just want the motor to open my curtains and then stop. I assume there’s some way to break out of that loop after 30 seconds, but I don’t know C at all.

If all you want to do is open and close the curtains, which presumably would take the same number of steps, then I wouldn’t use the loop() function at all. Just figure out how many steps it takes to open (or close) the curtains, and hard code that. You would probably also want a flag to make sure you don’t try to open the curtains if they’re already open, so I’ve added that to the code below.

#include "PhoBot/PhoBot.h"

PhoBot p = PhoBot(12.0, 12.0);
int numSteps = 1000; // figure out how many steps you need to open the curtains, and change this number to that
int period = 5;
bool curtainsAreOpen;

void setup() {
    Particle.function("motor", motorSwitcher);
    curtainsAreOpen = true;
}

void loop() {
}


int motorSwitcher(String command) {
    if(command.equalsIgnoreCase("on") && curtainsAreOpen){ // I'm assuming that the "on" direction closes the curtains.
        for (int i = 0; i < numSteps; i++) {
            p.setMotors("M3-F-100");
            p.setMotors("M4-B-100");
            delay(period);
            p.setMotors("M3-F-100");
            p.setMotors("M4-F-100");
            delay(period);
            p.setMotors("M3-B-50");
            p.setMotors("M4-F-50");
            delay(period);
            p.setMotors("M3-B-50");
            p.setMotors("M4-B-50");
            delay(period);
        }
    curtainsAreOpen = false;
    
    
    }else if (!curtainsAreOpen){
        for (int i = 0; i < numSteps; i++) {
            p.setMotors("M3-B-100");
            p.setMotors("M4-B-100");
            delay(period);
            p.setMotors("M3-B-100");
            p.setMotors("M4-F-100");
            delay(period);
            p.setMotors("M3-F-50");
            p.setMotors("M4-F-50");
            delay(period);
            p.setMotors("M3-F-50");
            p.setMotors("M4-B-50");
            delay(period);
        }
    curtainsAreOpen = true;
    }
}

There is a problem with his approach, potentially, in that it assumes that the curtains are open to start with ( curtainsAreOpen = true in setup()). If you close the curtains, power down the photon, and start it up again, then curtainsAreOpen will be in the wrong state. I don’t know what your physical setup is, but I would probably add some sort of sensors (limit switches or hall effect devices for example) to determine what state the curtains are in. If you did that, then you wouldn’t even need to know the number of steps. You could just run the motors until you get a signal from the sensor, and use that to shut off the motor.

I guess this procedure takes a while, so having it in a Particle.function() might not be the best :wink:

@ScruffR Could you please elaborate. Why is a Particle function not appropriate for this use? Does a Particle function need to return quickly?

It's not that a Particle.function() would not be appropriate, but your code inside it is too long (running).

Exactly this is the reason, since they are called via a HTTP POST request which should receive a HTTP response within a certain time to signal if it was successful or not - hence the return type int of the function.

This is actually something you omitted in your code - return someIntAsStatus;.
Without it your code might run into stack corruptions.

@ScruffR, thanks for the response. I hadn’t really thought about the time requirement for an HTTP response. I suspect that a lot of people on the forum (including me), are not too familiar with HTTP protocols, so this aspect doesn’t come readily to mind. Perhaps the documentation for Particle functions should be more explicit on this point.

@mabrow8454, As @ScruffR has pointed out, Particle functions should return a value in a timely fashion, so you should ignore the code in my second post. The more I think about this, the more I think you should have limit switches to detect the ends of travel for your curtains. If you have any physical slippage in your system, or the power to the Photon is cut off when the curtains are somewhere in between open and closed, you’ll run into trouble if you use a fixed time or number of steps for the motor run. I think the code below should work, if you can use limit switches. The motor should only run if neither of the switches is closed. I’ve replaced forward and reverse with a single function that does a single step of the motor for each turn of the loop() function – that way, as soon as one of the switches gets closed, the motor will stop.

// This #include statement was automatically added by the Particle IDE.
#include "PhoBot/PhoBot.h"

PhoBot p = PhoBot(12.0, 12.0);
String motorAction;
int closedSensorPin = D2; // assumes a limit switch connected between D2 and ground
int openSensorPin = D4; // assumes a limit switch connected between D4 and ground
int closedState;
int openState;

void setup() {
    pinMode(closedSensorPin, INPUT_PULLUP);
    pinMode(openSensorPin, INPUT_PULLUP);
    Particle.function("motor", motorSwitcher);
}


void loop() {
    closedState = digitalRead(closedSensorPin);
    openState = digitalRead(openSensorPin);
    while(closedState == HIGH && openState == HIGH) {
        moveCurtains(5);
    }
}

int motorSwitcher(String command) {
    if(command.equalsIgnoreCase("close")){
        motorAction = "close";
        return 1;
    }else if(command.equalsIgnoreCase("open")){
        motorAction = "open";
        return 2;
    }else{
        return -1;
    }
}


void moveCurtains(int period) {
    
     if(motorAction == "close") {
        p.setMotors("M3-F-100");
        p.setMotors("M4-B-100");
        delay(period);
        p.setMotors("M3-F-100");
        p.setMotors("M4-F-100");
        delay(period);
        p.setMotors("M3-B-50");
        p.setMotors("M4-F-50");
        delay(period);
        p.setMotors("M3-B-50");
        p.setMotors("M4-B-50");
        delay(period);
    }

    else if(motorAction == "open") {
        p.setMotors("M3-B-100");
        p.setMotors("M4-B-100");
        delay(period);
        p.setMotors("M3-B-100");
        p.setMotors("M4-F-100");
        delay(period);
        p.setMotors("M3-F-50");
        p.setMotors("M4-F-50");
        delay(period);
        p.setMotors("M3-F-50");
        p.setMotors("M4-B-50");
        delay(period);
    }
}

Hey @Ric, thanks for the detailed messages. What’s a limit switch?

Depending on your answer, I might prefer your original script recommendation for time-based motor action. I’m already stretching the limits of my understanding of the C language and Photon hardware, and I’m also hesitant to make additional purchases if it’s too expensive. But I’ll try to keep an open mind.

@mabrow8454, a limit switch is just a small (micro) switch that usually has a flexible arm that when pushed, closes the switch (something like this, https://www.adafruit.com/products/819).

Basically any button would do. Place it at the end, and make sure it gets pressed where you want to object to stop. When/if pressed, turn off the motor. A hall sensor would also work (those cheap magnet door/window sensors),

Hey guys,

Thanks so much for all the useful info. For now, I’m going to configure the more basic version (Photon opens blinds according to a motor on a timer). Once that’s in place, I might re-visit to add in those switches / sensors. I’ll need to see how much my fiance is willing to let me modify our existing window frames haha.

I just tested that version and it works great, thanks again!

Ric

sorry to bring an old topic back to life but was looking for examples on how to control my blinds using a photon and phobot. Your code above looks great and really intrigued me to get started on this effort.

I’ve got the photon on a phobot and using some basic code I was able to control the direction and stop/start it.

my issue is that when I use your example (with no changes) things compile great but when I flash it my photon accepts the code but can never connects back to the cloud (breaths green instead of blue).

only way I can recover is to put it in safe mode and flash tinker.

I’m no expect but can’t see any issue with your example code. any suggestions?

I only have a DC motor connected to M4 with no other inputs but can’t think that would cause to not connect to the cloud

I’m at a loss… thanks!

I don’t have a Phobot to test with, so it’s hard to troubleshoot the code. The only thing I see that might cause a problem is the while clause in loop. The first thing I would try would be to use threading to see if that fixes the problem ( add SYSTEM_THREAD(ENABLED); to the top of your file).

Ric,

that must have been it. I added the SYSTEM_THREAD(ENABLED) function and a short delay and have no issues with the unit. I plan to use your code as a reference to build the blinds control.

appreciate the help - thanks!