IR controlled dual stepper motorvolume control

Hello all,

New to the forum, but not new to Arduino, I have a few questions that I got partially answered by searching posts on the subject.

In a nutshell I would like to make an IR volume control with ULN2003/28BYJ-48. This I can do. But I want a second / stepper motor that can “follow” or better said track the master volume control via RF. The slave is just is for displaying the current volume setting of the masterunit.
After reading the nRF24L01 tutorial I think this can be done, but I am worried if this will stay in sync.

Any thoughts?

Ronnie

I think you are properly being worried about "sync". And how would you ever know if they were not in "sync".

Paul

Yes, staying synchronized is key. Some kind of feedback between the two will be needed I think.

rh75:
Yes, staying synchronized is key. Some kind of feedback between the two will be needed I think.

And limit switches so the zero point and the end point can be determined for both.

Paul

@rh75

Are you trying to use something like a BLDC motor as the volume control ?
If so it has been done to death so lots of completed projects for you to follow via google.

Hello all,

After some time I got the wireless working including homing the stepper. Infrared remote control works too, but I can only with a potentiometer attached to the sending arduino control the stepper on the receiving one wirelessly.

The receiver reads the PotVal from the sender in this case on Analogread 0.

But how can I send the IR signal ( which in my case is on the digital pin 3) to the receiver? Is there another method?

Below receivercode :

#include "Stepper.h"
#include "IRremote.h"
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#define pin1  4//these are the Arduino pins that we use to activate coils 1-4 of the stepper motor
#define pin2  5
#define pin3  6
#define pin4  7
const byte homeButton = 2;
byte hBval;   // new variable

#define CE_PIN   9
#define CSN_PIN 10
#define  POT     0

//Variabel met het adres van het kanaal waardoor het zal worden verzonden
byte direccion[5] ={'c','a','n','a','l'};


RF24 radio(CE_PIN, CSN_PIN); // make radio-object (NRF24L01)
float datos[3]; // vector met de te verzenden gegevens

#define STEPS  32   // Number of steps per revolution of Internal shaft
int  Steps2Take;  // 2048 = 1 Revolution
int receiver = 3; // Signal Pin of IR receiver to Arduino Digital Pin 6

Stepper small_stepper(STEPS, 4, 6, 5, 7);
IRrecv irrecv(receiver);    // create instance of 'irrecv'
decode_results results;     // create instance of 'decode_results'


#define delaytime 3 // Stepper


void setup() {
  // initialize the 8 pin as an output:
  pinMode(pin1, OUTPUT);
  pinMode(pin2, OUTPUT);
  pinMode(pin3, OUTPUT);
  pinMode(pin4, OUTPUT);
  pinMode(homeButton, INPUT_PULLUP); 
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
  Serial.println("Homing......");
  stepperHome();
  Serial.println("Homed");
  Serial.println(" ");
  
  //initialiseren van de NRF24L01
  
  radio.begin(); //initialiseren van de seriele poort
  Serial.begin(9600);

  radio.openReadingPipe(1, direccion); //We openen het Reading-kanaal

  radio.startListening();  //we begonnen te luisteren op het kanaal
}

void stepperHome()
{
  hBval = digitalRead(homeButton);
  int hm = 0; 
   while (hBval == HIGH )
   //while ( hm < 200 )
  {
    //backwards slowly till it hits the switch and stops
    backward();
    digitalWrite(13, LOW);
    hBval = digitalRead(homeButton);
    hm ++;
    Serial.println(hm);
    if ( hm > 600){   //Timed exit if switch malfunctions
      break;
   }
  }
  digitalWrite(13, HIGH); //
  delay(400);
  stukjeomhoog(10);
digitalWrite(13, LOW);
  //
}
void loop(){
 uint8_t numero_canal;
  //if ( radio.available(&numero_canal) )
  if ( radio.available() )
  {
    //we lezen de gegevens en slaan deze op in de gegevensvariabele[]
    radio.read(datos, sizeof(datos));

    //we rapporteren de ontvangen gegevens via de seriële poort
    Serial.print("Potentiometer" );
    Serial.println(datos[0]);


  }
  else
  {
    Serial.println("Geen radiogegevens beschikbaar");
  }
  //delay(100);

  int receiver = datos[0];


 if (irrecv.decode(&results)) // have we received an IR signal?

  {
    switch(results.value)

    {

      case 0x77E1505E: // UP button pressed
                      small_stepper.setSpeed(100); //Max seems to be 700
                      Steps2Take  =  14;  // Rotate CW
                      small_stepper.step(Steps2Take);
                      delay(50);
                      step_OFF(); 
                      break;

      case 0x77E1305E: // DOWN button pressed
                      small_stepper.setSpeed(100);
                      Steps2Take  =  -14;  // Rotate CCW
                      small_stepper.step(Steps2Take);
                      delay(50);
                      step_OFF();  
                      break;

      
                      
    }
    
      irrecv.resume(); // receive the next value
  }  
}


void stukjeomhoog(int steptemp){

step_OFF();         //turning all coils off
  // steptemp = numberOfSteps;
    while(steptemp>0){
    forward();       //going forward
    steptemp -- ;//counting down the number of steps
  }
   step_OFF();
 
}




//these functions set the pin settings for each of the four steps per rotation of the motor (keep in mind that the motor in the kit is geared down,
//i.e. there are many steps necessary per rotation

void Step_A(){
  digitalWrite(pin1, HIGH);//turn on coil 1
  digitalWrite(pin2, LOW);
  digitalWrite(pin3, LOW);
  digitalWrite(pin4, LOW);
}
void Step_B(){
  digitalWrite(pin1, LOW);
  digitalWrite(pin2, HIGH);//turn on coil 2
  digitalWrite(pin3, LOW);
  digitalWrite(pin4, LOW);
}
void Step_C(){
  digitalWrite(pin1, LOW);
  digitalWrite(pin2, LOW);
  digitalWrite(pin3, HIGH); //turn on coil 3
  digitalWrite(pin4, LOW);
}
void Step_D(){
  digitalWrite(pin1, LOW);
  digitalWrite(pin2, LOW);
  digitalWrite(pin3, LOW);
  digitalWrite(pin4, HIGH); //turn on coil 4
}
void step_OFF(){
  digitalWrite(pin1, LOW); //power all coils down
  digitalWrite(pin2, LOW);
  digitalWrite(pin3, LOW);
  digitalWrite(pin4, LOW);
}

//these functions run the above configurations in forward and reverse order

//the direction of a stepper motor depends on the order in which the coils are turned on.
void forward(){//one tooth forward
  Step_A();
  delay(delaytime);
  Step_B();
  delay(delaytime);
  Step_C();
  delay(delaytime);
  Step_D();
  delay(delaytime);
}

void backward(){//one tooth backward
  Step_D();
  delay(delaytime);
  Step_C();
  delay(delaytime);
  Step_B();
  delay(delaytime);
  Step_A();
  delay(delaytime);
}

Transmitter:

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

//Define pins CE and CSN
#define CE_PIN 9
#define CSN_PIN 10
#define  POT     0

byte direccion[5] ={'c','a','n','a','l'}; //Variabel met het adres van het kanaal waardoor het zal worden verzonden


RF24 radio(CE_PIN, CSN_PIN); // create object radio (NRF24L01)


float datos[3]; // vector met de te verzenden gegevens

void setup()
{
  
  radio.begin(); // initialiseren van de NRF24L01
 
  Serial.begin(9600);  // initialiseren van de seriele poort
 

 radio.openWritingPipe(direccion); // opening writingchannel
 
}
 
void loop()
{
 
 datos[0]=analogRead(0); // we laden de gegevens in de gegevensvariabele[]

 
 bool ok = radio.write(datos, sizeof(datos)); // sending data
  //we rapporteren de verzonden gegevens via de seriële poort
  if(ok)
  {
     Serial.print("data send: ");
     Serial.print(datos[0]);
   
  }
  else
  {
     Serial.println("could not send");
  }
  //delay(1000);
}
[code]

rh75:
After some time I got the wireless working including homing the stepper. Infrared remote control works too, but I can only with a potentiometer attached to the sending arduino control the stepper on the receiving one wirelessly.

I'm confused. In your Original Post you mention two stepper motors - is one of them controlled by the nRF24 and one by the IR signal?

Where are the two stepper motors located?

You say "I can only with a potentiometer attached to the sending arduino control the stepper". How do you want to control it?

...R
Simple nRF24L01+ Tutorial

Hi Robin2,

I have 2 steppers, one located in my pre amp, and the other one in another device.
I have 2 arduino’s. The one in the pre amp controls the first stepper via Infrared remote control.
What I am trying to accomplish, is that the second Arduino, should “mirror” the stepper in the pre amp wireless. So from your tutorial, the one way transmission, master to slave situation..
With a simple pot connected to the master i accomplished to control the slavestepper wirelessly. But how to manage this with IR data?
Hope that clarifies. :slight_smile:

Let's say that ArduinoP and stepperP are in the Pre-amp and ArduinoM and steppperM are in the Mirror device

Am I correct to think that you want ArduinoP to receive IR signals and move stepperP and also to send a wireless message to ArduinoM so it can move stepperM to the same position as stepperP ?

If so I don't understand where the potentiometer fits into the system.

If you ignore the need for the "mirror" device can you control stepperP with the IR signal? If not then I suggest your first task is to get that working.

What IR transmitter are you using? I don't have any experience with decoding IR signals.

...R

Hi Robin2,

"Am I correct to think that you want ArduinoP to receive IR signals and move stepperP and also to send a wireless message to ArduinoM so it can move stepperM to the same position as stepperP ?"

That is what I want to achieve.
I can control ArduinoP and stepperP via IR remote alrrady. That works, including moving to home position. Forget the pot.meter. It was a test to see if I can achieve the above with a pot.meter connected to arduinoP instead of an IR signal. That works wirelessly. But how to achieve this with an IR signal?
Send the received IR data on ArduinoP to the other device? Or send the data that the stepper moves on ArduinoP to the other device?

Ronnie.

rh75:
Send the received IR data on ArduinoP to the other device? Or send the data that the stepper moves on ArduinoP to the other device?

It seems to me you can do either.

If it was my project I think I would get ArduinoP to send the actual stepper position to ArduinoM. For example if the latest IR signal causes stepperP to move 40 steps to the position 2733 then I would send 2733 to ArduinoM. That way, even if a message was lost the correct position would be re-established with a subsequent wireless message.

...R

Thanks for your advice. I think the second option I will try.

also:

Could I not just simply sent the data ''Steps2Take'' to the ArduinoM?

From sketch:

small_stepper.step(Steps2Take);

rh75:
Could I not just simply sent the data ‘‘Steps2Take’’ to the ArduinoM?

You probably could.

But what happens if you send 23 as the number of steps to take and that wireless message is never received? Never assume that wireless is as reliable as a wired connection.

…R

“But what happens if you send 23 as the number of steps to take and that wireless message is never received? Never assume that wireless is as reliable as a connection”

Point taken. Makes sense.
I might be wrong, but is this possible with my simple sketch? I mean is actual position possible with arduino stepper library?

rh75:
I might be wrong, but is this possible with my simple sketch? I mean is actual position possible with arduino stepper library?

Of course. You HOME the stepper (actually both steppers) at startup and that sets the ZERO position. Then for every move of stepperP you just add or subtract the extra steps and send the accumulated value to ArduinoM

…R

Robin,

I think I am going the wrong way with this..see code
To my understanding I have to use the case value when a keypress from the remote moves the motor plus or minus 14 steps each keypress.

So this way adds/ subtracts from the value to be send..

int move(int target) {
      
      if (target == stepperHome) {
      rotationDistance = 0;
     
    } else {
      rotationDistance = target - previousPos; //last position
    }
     return rotationDistance;  
  }

Sorry but I can't see how your code snippet relates to your comment.

My inclination would be something like this pseudo code (in ArduinoP)

if (IRcode == X) {
  stepsToMove = 14;
}
else if (IRcode == Y) {
  stepsToMove = -14;
}

stepper.step(stepsToMove);
currentStepperPosition += stepsToMove;

and then send the value in currentStepperPosition to ArduinoM

...R

Hi, trying to solve, but a bit out of my league to be honest. :roll_eyes:

This line:

‘‘currentStepperPosition += Steps2Take;’’

So, if I am right, currentStepperPosition gets updated like x=x+y. plus 14 adds and -14 subtracts to currentStepperPosition…

Transmittercode:

#include "Stepper.h"
#include "IRremote.h"
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#define pin1  4//these are the Arduino pins that we use to activate coils 1-4 of the stepper motor
#define pin2  5
#define pin3  6
#define pin4  7
const byte homeButton = 2;
byte hBval;   // new variable
#define STEPS  32   // Number of steps per revolution of Internal shaft
int  Steps2Take;  // 2048 = 1 Revolution
#define CE_PIN 9
#define CSN_PIN 10

//Variabel met het adres van het kanaal waardoor het zal worden verzonden
byte direccion[5] ={'c','a','n','a','l'};
//creamos el objeto radio (NRF24L01)
RF24 radio(CE_PIN, CSN_PIN);

//vector met de te verzenden gegevens
float datos[3];

int receiver = 3; // Signal Pin of IR receiver to Arduino Digital Pin 6
int IRcode;
int currentStepperPosition;

Stepper small_stepper(STEPS, 4, 5, 6, 7);
IRrecv irrecv(receiver);    // create instance of 'irrecv'
decode_results results;     // create instance of 'decode_results'

// Stepper
#define delaytime 3


void setup() {
  // initialize the 8 pin as an output:
  pinMode(pin1, OUTPUT);
  pinMode(pin2, OUTPUT);
  pinMode(pin3, OUTPUT);
  pinMode(pin4, OUTPUT);
  pinMode(homeButton, INPUT_PULLUP); 
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
  Serial.println("Homing......");
  stepperHome();
  Serial.println("Homed to Open (Drain) position");
  Serial.println(" ");
  //initialiseren van de NRF24L01
  radio.begin();
  //initialiseren van de seriele poort
  Serial.begin(9600);
 
//We openen een schrijfkanaal
 radio.openWritingPipe(direccion);
}

void stepperHome()
{
  hBval = digitalRead(homeButton);
  int hm = 0; 
   while (hBval == HIGH )
   //while ( hm < 200 )
  {
    //backwards slowly till it hits the switch and stops
    backward();
    digitalWrite(13, LOW);
    hBval = digitalRead(homeButton);
    hm ++;
    Serial.println(hm);
    if ( hm > 600){   //Timed exit if switch malfunctions
      break;
   }
  }
  digitalWrite(13, HIGH); //
  delay(400);
  stukjeomhoog(10);
digitalWrite(13, LOW);
  //
}
void loop(){
 

 if (irrecv.decode(&results)) // have we received an IR signal?

  {
    switch(results.value)

    {

      case 0x77E1505E: // UP button pressed
                      small_stepper.setSpeed(100); //Max seems to be 700
                      Steps2Take  =  14;  // Rotate CW
                      small_stepper.step(Steps2Take);
                      delay(50);
                      step_OFF(); 
                      break;

      case 0x77E1305E: // DOWN button pressed
                      small_stepper.setSpeed(100);
                      Steps2Take  =  -14;  // Rotate CCW
                      small_stepper.step(Steps2Take);
                      delay(50);
                      step_OFF();  
                      break;

      case 0xFFFFFFFF: // DOWN button pressed
                      small_stepper.setSpeed(100);
                      Steps2Take  =  -14;  // Rotate CCW
                      small_stepper.step(Steps2Take);
                      delay(10);
                      step_OFF();  
                      break;
                      
    if (IRcode == 0x77E1505E) {
      Steps2Take = 14;

  } else if (IRcode == 0x77E1305E) {
      Steps2Take = -14; 
  }

  small_stepper.step(Steps2Take);
  currentStepperPosition += Steps2Take;
  }

    
      irrecv.resume(); // receive the next value
  }  

  
 datos[0]=currentStepperPosition; //we laden de gegevens in de gegevensvariabele[]

 //we sturen de gegevems
 bool ok = radio.write(datos, sizeof(datos));
  //we rapporteren de verzonden gegevens via de seriële poort
  if(ok)
  {
     Serial.print("Gegevens verzonden: ");
     Serial.print(datos[0]);
   
  }
  else
  {
     Serial.println("kon niet verzenden");
  }
  //delay(1000);
}


void stukjeomhoog(int steptemp){

step_OFF();         //turning all coils off
  // steptemp = numberOfSteps;
    while(steptemp>0){
    forward();       //going forward
    steptemp -- ;//counting down the number of steps
  }
   step_OFF();
 
}


  


//these functions set the pin settings for each of the four steps per rotation of the motor (keep in mind that the motor in the kit is geared down,
//i.e. there are many steps necessary per rotation

void Step_A(){
  digitalWrite(pin1, HIGH);//turn on coil 1
  digitalWrite(pin2, LOW);
  digitalWrite(pin3, LOW);
  digitalWrite(pin4, LOW);
}
void Step_B(){
  digitalWrite(pin1, LOW);
  digitalWrite(pin2, HIGH);//turn on coil 2
  digitalWrite(pin3, LOW);
  digitalWrite(pin4, LOW);
}
void Step_C(){
  digitalWrite(pin1, LOW);
  digitalWrite(pin2, LOW);
  digitalWrite(pin3, HIGH); //turn on coil 3
  digitalWrite(pin4, LOW);
}
void Step_D(){
  digitalWrite(pin1, LOW);
  digitalWrite(pin2, LOW);
  digitalWrite(pin3, LOW);
  digitalWrite(pin4, HIGH); //turn on coil 4
}
void step_OFF(){
  digitalWrite(pin1, LOW); //power all coils down
  digitalWrite(pin2, LOW);
  digitalWrite(pin3, LOW);
  digitalWrite(pin4, LOW);
}

//these functions run the above configurations in forward and reverse order

//the direction of a stepper motor depends on the order in which the coils are turned on.
void forward(){//one tooth forward
  Step_A();
  delay(delaytime);
  Step_B();
  delay(delaytime);
  Step_C();
  delay(delaytime);
  Step_D();
  delay(delaytime);
}

void backward(){//one tooth backward
  Step_D();
  delay(delaytime);
  Step_C();
  delay(delaytime);
  Step_B();
  delay(delaytime);
  Step_A();
  delay(delaytime);
}

rh75:
'currentStepperPosition += Steps2Take;''

So, if I am right, currentStepperPosition gets updated like x=x+y. plus 14 adds and -14 subtracts to currentStepperPosition..

Yes

Transmittercode:

What happens when you run it?

Your variable currentStepperPosition is an int. Why are you converting it to a float in the array datos. You will lose precision. The count of steps will never be a fraction so don't use a float. As well as which floating point maths is very slow on an Arduino.

Are you sure that currentStepperPosition will always be in the range -32768 to +32767? If the range might be bigger use a long rather than an int.

...R