How to get a rain sensor to activate a stepper motor

Another newbie question here - please be patient!

I am building a unit for auto-closing a top-hung window whenever it rains. This will involve turning a pulley on a stepper motor a certain number of times when activated by a rain sensor, using an Elegoo Uno R3 and a Pololu High-Power Stepper Motor Driver 36v4.

So far, I have successfully used a rain sensor Arduino sketch to beep a beeper when the sensor becomes wet; and I have set up my stepper motor so that it responds to Pololu’s basicsteppingSPI sketch. So the basic electronics and mechanicals are in place.

What I need to do now is to combine versions of these two sketches in such a way that every time the rain sensor gets wet, the stepper motor turns x times, then goes to sleep until it is reset.

Is anyone aware of a single sketch that I could use/adapt to do this?

If not, what would be the best approach for a complete newbie?

Thanks!

Hello, provastian.

It is probably unlikely that anyone will have a sketch that specific to work from, but it sounds like you already have a good start if you have a program that beeps a buzzer when the stepper motor should move.

Have you tried using the methods from the BasicSteppingSPI example to move the stepper in your rain sensor sketch? If you try it and run into problems, you can post your code here and I would be glad to take a look. Also, you might consider momentarily decoupling your stepper motor from the actual mechanics of your system until you get your code working as intended, just in case.

Brandon

Thanks Brandon – I’ll give it a go.

In the meantime, please could you quickly tell me which output from which Arduino pin would start the stepper motor operation?

And also how I tell the stepper motor to only operate once, for x turns, and then go to sleep until I hit a Reset button?

Once I’ve got those two sorted, I should be well on the way to success.

Thanks!

OK - I’ve made some progress. I’ve combined the BasicSteppingSPI example with someone else’s rain sensor sketch, and edited it so that when I wet the rain sensor, the motor starts, and is initiated only once. This is exactly what I wanted to happen.

I still have a few problems though:

  1. As soon as I plug in the motor power supply (24v 5A), the motor makes clicking noises, with the occasional small jolt. I need it to be absolutely dormant unless and until it is triggered by the rain sensor.
  2. When the motor starts, it runs in 3-4 bursts, rather than the one continuous movement that I need to close the window. It is also a bit juddery/noisy.
  3. I don’t really understand how to set the speed and duration of the motor (which may also explain 2. above). I am aiming for around 60rpm. It does 200 steps per revolution which is fine for the job in hand - hence do I need to use microstepping?
  4. I managed to find a way to make the motor go to sleep after it has been activated once - but could I have done this more elegantly/reliably?

Any suggestions welcome!

Thanks.

Here is my code:

#include <SPI.h>
#include <HighPowerStepperDriver.h>

const uint8_t CSPin = 4;

// This period is the length of the delay between steps, which controls the
// stepper motor's speed.  You can increase the delay to make the stepper motor
// go slower.  If you decrease the delay, the stepper motor will go faster, but
// there is a limit to how fast it can go before it starts missing steps.
const uint16_t StepPeriodUs = 300;

HighPowerStepperDriver sd;

int rainsense = 0; // analog sensor input pin 0
int activatemotor = 11; // digital output pin 11 - activate 5v supply from Arduino to motor controller
int countval = 0; // counter value starting from 0 and goes up by 1 every second

void setup() {

  //Rain sensor setup
  Serial.begin(9600);
  pinMode(activatemotor, OUTPUT);
  pinMode(rainsense, INPUT);

  //Stepper motor setup
  {
    SPI.begin();
    sd.setChipSelectPin(CSPin);

    // Give the driver some time to power up.
    delay(1);

    // Reset the driver to its default settings and clear latched status
    // conditions.
    sd.resetSettings();
    sd.clearStatus();


    // Set the current limit. You should change the number here to an appropriate
    // value for your particular system.
    sd.setCurrentMilliamps36v4(4200);

    // Set the number of microsteps that correspond to one full step.
    sd.setStepMode(HPSDStepMode::MicroStep32);
  }
}

void loop() {
  int rainSenseReading = analogRead(rainsense);
  Serial.println(rainSenseReading); // serial monitoring message
  delay(250);// rain sensing value from 0 to 697 (using 3.3v feed from Arduino).
  // set the amount of rain needed for the motor to be activated.
  if (rainSenseReading <= 400) {
    // Enable the motor outputs.
    sd.enableDriver();
 
  }

  delay(1000);

  // Step in the default direction specified number of times.
  sd.setDirection(1);
  for (unsigned int x = 0; x < 10000; x++)
  {
    sd.step();
    delayMicroseconds(StepPeriodUs);
  }
  sd.disableDriver();

}

And here is the motor spec:

  • Manufacturer Part Number: 23HE45-4204S
  • Number of phase: 2
  • Step Angle: 1.8 deg
  • Holding Torque: 3.0 Nm(425oz.in)
  • Rated Current/phase: 4.2 A
  • Phase Resistance: 0.9 ohms± 10%
  • Inductance: 3.8 mH ± 20%(1KHz)

Full details here.

All wiring is as per the Highpower 36v4 product pages as far as I can tell.

Hello.

Thank you for posting your code. It looks like it is trying to step the motor every time it loops instead of only when the sensor triggers (even though the driver is disabled until it triggers). One quick way to fix this is to just move the code inside of your ifstatement, like this:

if (rainSenseReading <= 400) {
    // Enable the motor outputs.
   sd.enableDriver();
 
   delay(1000);

    // Step in the default direction specified number of times.
    sd.setDirection(1);
    for (unsigned int x = 0; x < 10000; x++)
    {
      sd.step();
      delayMicroseconds(StepPeriodUs);
    }
    sd.disableDriver();
}

I think the rest of your questions would be answered by describing what that for loop actually does. Each time the loop runs through, it sends a command to tell the driver to step the motor once then delays for the amount of time specified by StepPeriodUs (in microseconds). This means you can adjust the speed by changing StepPeriodUs. A lower value will move the motor faster since it will spend less time delaying. By the way, your code is currently setting the microstep mode to 1/32 with sd.setStepMode(HPSDStepMode::MicroStep32);, so in that microstep mode, it will take 6400 steps to make 1 revolution (200 steps per revolution × 32 microsteps per step). If you want to use full steps instead, you can change that line of code to sd.setStepMode(HPSDStepMode::MicroStep1);. Lastly, you can change the number of steps taken by adjusting the x<10000 value in the for loop, since it is stepping once for each cycle through the loop.

Brandon

Thanks Brandon. I copied and pasted your amended code, but there is a “}” missing.

I tried putting a } at the very end of the sketch, but the motor kept turning random amounts (generally around 1.5 revolutions, for about 3 seconds) and then pausing for a short while and then restarting, until I disconnected it.

I also tried removing the { in the middle of

for (unsigned int x = 0; x < 10000; x++)
{
sd.step();

but that made the motor do even more random stuff. It also varied between being really juddery, and beautifully smooth.

It seems odd that, if the coding is causing a problem, it is not a consistent tone. To do re-runs I have tried both turning off the 24v dc supply and pushing the Uno’s reset button - but I can’t see any pattern to what is going on here.

Please could you advise?

Thanks!

The code snippet I posted is not missing any curly brackets; it has 2 open brackets and 2 close brackets, so the problem must be something bigger in your modified code.

Missing or wrong brackets could definitely cause unpredictable and unusual behavior, depending on where they are. If you post an updated version of your code, I would be glad to take another look.

Brandon

Thanks Brandon!

I have spent a few more hours trying to tweak the code and I still can’t get the motor to run consistently. The latest version of the code (pasted below) eventually gets the motor to perform a controlled number of turns at more or less the right speed, but there are two fatal flaws:

  1. It requires several resets to get there. (I have been doing this by disconnecting the 24v supply or pressing the Uno’s reset button - it doesn’t seem to matter which). What happens in the meantime is that every time I restart the system, the motor makes small, noisy, juddery movements, generally for only a fraction of a revolution - and sometimes skipping forward or even stepping back. There is no pattern to these movements: sometimes they will repeat indefinitely, other times the motor will just make a quick banging sound and then do nothing at all. Eventually, after several resets, the motor will start off noisily and juddery, and then after a few seconds it will settle down into a nice smooth rotation and perform the number of turns I expect it to (in this case, five).
  2. The second issue is that once it finally sorts itself out and does five smooth revolutions, the motor then repeats this ad infinitum. I need it to do this only once - otherwise it will continue to try to close an already closed window, which would obviously be a bad thing.

If you could review the code and suggest how to fix these two issues, I would be really grateful.

Thanks!

// Before using this example, be sure to change the setCurrentMilliamps36v4 line
// to have an appropriate current limit for your system.  Also, see this
// library's documentation for information about how to connect the driver:
//   http://pololu.github.io/high-power-stepper-driver

#include <SPI.h>
#include <HighPowerStepperDriver.h>

const uint8_t CSPin = 4;

// This period is the length of the delay between steps, which controls the
// stepper motor's speed.  You can increase the delay to make the stepper motor
// go slower.  If you decrease the delay, the stepper motor will go faster, but
// there is a limit to how fast it can go before it starts missing steps.
const uint16_t StepPeriodUs = 300;

HighPowerStepperDriver sd;

int rainsense = 0; // analog sensor input pin 0
int activatemotor = 11; // digital output pin 11 - activate 5v supply from Arduino to motor controller
int countval = 0; // counter value starting from 0 and goes up by 1 every second

void setup() {

  //Rain sensor setup
  Serial.begin(9600);
  pinMode(activatemotor, OUTPUT);
  pinMode(rainsense, INPUT);

  //Stepper motor setup
  {
    SPI.begin();
    sd.setChipSelectPin(CSPin);

    // Give the driver some time to power up.
    delay(1);

    // Reset the driver to its default settings and clear latched status
    // conditions.
    sd.resetSettings();
    sd.clearStatus();


    // Set the current limit. You should change the number here to an appropriate
    // value for your particular system.
    sd.setCurrentMilliamps36v4(4200);

    // Set the number of microsteps that correspond to one full step.
    sd.setStepMode(HPSDStepMode::MicroStep32);
  }
}

void loop()
{
  int rainSenseReading = analogRead(rainsense);
  Serial.println(rainSenseReading); // serial monitoring message
  delay(250);// rain sensing value from 0 to 697 (using 3.3v feed from Arduino).
  // set the amount of rain needed for the motor to be activated.
  if (rainSenseReading <= 400) {

    // Enable the motor outputs.
    sd.enableDriver();
    delay(1000);

    // Step in the default direction specified number of times.
    sd.setDirection(1);
    for (unsigned int x = 0; x < 32000; x++)
    {
      sd.step();
      delayMicroseconds(StepPeriodUs);
    }
    sd.disableDriver();
  }
}
  1. I am not sure what might be causing this issue from just looking at your code. What is your order of operations? Is your Arduino powered and running its program already when you connect the 24V power to the high-power stepper motor driver? Also, I noticed that you are setting the current limit to 4200mA, which is higher than the 36v4 driver can handle continuously without additional cooling. We strongly recommend keeping the current limit to 4000mA or lower unless you are sure that you are adequately cooling the board.

    Could you post some pictures of your setup that show all of your connections?

  2. There is nothing in your code right now to stop it from looping through and repeating the motion if the sensor’s value (rainSenseReading) is still less than 400. One way to accomplish this might be a state variable. For example, you could use a boolean to keep track of whether or not the window is open and also check that boolean in your if statement (e.g. if(rainSenseReading <= 400 && windowOpen)). Inside the if statement, you will need to set the boolean to false, then the code will not be allowed to enter the if statement again until you reset the boolean to false.

Brandon