0

I have made a setup with Arduino Uno, Nema 17, T8 lead screw, IR Sensor and a DC motor. I am trying to establish a code which:

  1. Resets Home position of the Machining Head on the lead screw
  2. Has an action button, which operates only when the position of the Head is on the lead screw, goes down the specified depth
  3. Takes input from user to run the DC Motor (to rotate the tool on the machine head)
  4. Takes second input to stop rotating and return to the reset position.

I am facing one major problem and two minor problems:

Major Problem: To remove an error which was later resolved, I added the line: action_permit=0 Now due to some reason (I have pulled a lot of hairs trying to understand this), when I remove this action_permit line, the DC Motor rotation is stopped. I have to include this line to rotate my DC Motor.

Minor Problem: To get input from the user as to control when the DC motor starts and stops, I included the code which accepts 'y' for yes (start rotating the DC motor) and 'n' as no (stop rotation and return to home position)

Minor Problem: I am not sure how to control the PWM, I have copied the code from a video, but do not know how to reach maximum and minimum rpm; also I understand the variation between PWM value and RPM is not linear. Any feedback on how to precisely control the rpm of the motor would be great

int IR_signal=2;
int DC_ENB=11;
int DC_IN3=4;
int DC_IN4=5;
int STE_dir=6;
int STE_step=7;
int STE_ena=10;
int button_reset=8;
int button_action=9;
//define arduino pin
int action_permit;//0-action part is not allowed to run. 1-action part is allowed to run
int IRon;
int COUNT;//the amount of steps that the machine head should go
int HEIGHT;//total height that the machine head should go
int i;
int reset_on;
int action_on;
String Switch_DC;

//parameter
void setup() {
  // put your setup code here, to run once:
  pinMode(IR_signal,INPUT);
  pinMode(button_reset,INPUT);
  pinMode(button_action,INPUT);
  //input part
  pinMode(DC_ENB,OUTPUT);
  pinMode(DC_IN3,OUTPUT);
  pinMode(DC_IN4,OUTPUT);
  pinMode(STE_dir,OUTPUT);
  pinMode(STE_step,OUTPUT);
  pinMode(STE_ena,OUTPUT);
  //output part
  action_permit=0;// ban the action part at the beginning
  COUNT=0;
  HEIGHT=0;

  //original value of parameters
  //digitalWrite(DC_ENB,HIGH);
  analogWrite(DC_ENB,200);
  digitalWrite(STE_ena,LOW);
  digitalWrite(DC_IN3,HIGH);
  digitalWrite(DC_IN4,HIGH);
  //original pin output
  Serial.begin(9600);
  // start the monitor
}

void loop() {
  // put your main code here, to run repeatedly:
  reset_on=digitalRead(button_reset);
  action_on=digitalRead(button_action);
  //read the signal from the button
  if(reset_on==0)//reset button is pressed
  {
    delay(10);
    // preventing manual error
    if(reset_on==0)
    {
      RES();
    }
  }
  if(action_on==0)//action button is pressed
  {
    delay(10);
    // preventing manual error
    if(action_on==0)
    {
      ACT();
    }
  }
}
void RES()//reset part
{
  while(action_permit==0)//when 0, this "while" loop will keep running
  {
    IRon=digitalRead(IR_signal);// read the signal from IR sensor
    if(IRon==1)// machine head is not in original position
    {
      delay(1);
      //ensure the signal is not happened by a BUG
      IRon=digitalRead(IR_signal);
      if(IRon==1)
      {
        digitalWrite(STE_dir,LOW);
        digitalWrite(STE_step,HIGH);
        delay(1);
        digitalWrite(STE_step,LOW);
        delay(1);
        //if machine head is not in original position, it will go up for one step
      }
    }//if HIGH, go up
    else if(IRon==0)
    {
      action_permit=1;
      COUNT=0;

    }//once machine head reaches the original position, controller will get out this loop and allow action part to run
  }
}
void ACT()//action part
{
  if(action_permit==1)
  {

   for(i=0;i<3523;i+=1)
   {
     digitalWrite(STE_dir,HIGH);
     digitalWrite(STE_step,HIGH);
     delay(1);
     digitalWrite(STE_step,LOW);
     delay(1);
   }
   delay(100);
   for(i=0;i<100;i+=1)
   {
     digitalWrite(STE_step,HIGH);
     delay(10);
     digitalWrite(STE_step,LOW);
     delay(10);
   }
   action_permit=0;

   Serial.println("Please press y to start tool rotation");
   while((Serial.available()==0))
   {
    //waiting for input  
   }
   Switch_DC=Serial.readString();
   if (Switch_DC == "y")
   action_permit=0;
   {
    analogWrite(DC_ENB,200);
    digitalWrite(DC_IN3,HIGH);
    digitalWrite(DC_IN4,LOW);
    delay(2000);
   }

   Serial.println("Please press n to stop tool rotation");
   while((Serial.available()==0))
   {
    //waiting for input 
   }
   Switch_DC=Serial.readString();
   if(Switch_DC == "n")
   action_permit=0;
   {
    analogWrite(DC_ENB,200);
    digitalWrite(DC_IN3,LOW);
    digitalWrite(DC_IN4,LOW);
   }
   digitalWrite(STE_dir,LOW);
   for(i=0;i<4523;i+=1)
   {
     digitalWrite(STE_step,HIGH);
     delay(1);
     digitalWrite(STE_step,LOW);
     delay(1);
   }
   action_permit=0;
  }
}
  • 1
    for precise control of motor RPM, you need to use a sensor that generates a pulse, or multiple pulses for one revolution of the motor – jsotola Sep 22 '19 at 0:11
1

You have some obvious problems in your code, though I don't know, if the logic will be correct (doing what you want it to do) if you fix them. But either way it is a good start.

  • You check for action_on and reset_on to be LOW, so I guess the button will pull the pin to LOW, if you press it. You didn't activate the internal pullup resistors, so I guess you already have them externally (if not: You definitely need them). So action_on==0 actually is the case for action is permitted to run, not forbidden. You seem to think, that it is the other way round.
  • Then you are doing this (and the same with reset_on):

    if(action_on==0)//action button is pressed
      {
      delay(10);
      // preventing manual error
      if(action_on==0)
    

    You check, if action_on is zero. If yes, you wait a bit and check the same again. The value of action_on cannot change during the delay, so this will always be true and thus is superfluous. If you meant to read the button again, to check if the button was really pressed (for debouncing), you have to actually read the button state again with digitalRead() and save it to action_on, like you have done before. This is not done automatically for you.

  • for(i=0;i<3523;i+=1) Using a global variable to count in a for loop is not a good idea. Instead you should always use a local variable to do this: for(int i=0;i<3523;i+=1)
  • Switch_DC=Serial.readString(); Using readString() is not good coding, because this function just reads all data, that comes until the timeout hits (default 1s). This is not a reliable way to read data from Serial. Instead you should read each character individually from the Serial interface, put it into a buffer, and only stop and process the output, if a delimiting character was send. Often a newline character \n is used for this. So one message/command, that should be processed as a whole should be ended with a newline character. That will prevent, that the input from serial is processed incorrectly, only because the timing was different. If you only have commands, that consist of only 1 character, you can instead use a single Serial.read(), which reads exactly one character from the Serial interface (or returns -1 if there is no character to read).
  • Then you wrote this:

    if (Switch_DC == "y")
    action_permit=0;
    {
    

    I guess, here you have inserted the action_permit=0. This cannot be, want you meant. As you wrote it, the action_permit=0 line will only be executed, if Switch_DC is equal to "y", since this statement is inside the if statement. The ; at the end of the statement also closes the if statement. So the code inside the following brackets will always be executed and the brackets are superflous. I don't know, where you intended to insert the action_permit=0, but since it is never used in the rest of the function, it is sufficient to just use it at the end of the function, like you already did. Remove all other of these lines from that function.


If you want to control the RPM of the motor, not just some relative PWM value, you first need to measure the RPM. PWM just controls the electrical energy going into the motor in a relative way (relative to fully powered on). To set a RPM value for the motor, you need to measure the current RPM (for example with a light barrier or a rotary encoder) and use that as input for a PID controller (Proportional Integral Differential). The output of the PID controller then must be fed into the analogWrite() function. The PID controller will raise or lower the PWM value, until the RPM setpoint is reached. There is a PID library for Arduino, that will help you with the calculation.

| improve this answer | |
  • A big thank you for your help! I will implement your suggestions one by one and see how the code improves. Your help has enabled me to start thinking like a programer and I can't thank you enough for this. As to respond to the action_permit. Yes its a normally closed button, also when I remove action_permit from any place in the code (I have tried removing it one by one at all places), the lines of code near that statement start misbehaving. In regards to your comment about the reading the input from the user, can you suggest a better alternative as to how to read 'y' and 'n'? Thankyou again! – Shreeniket Joshi Sep 23 '19 at 16:52
  • hi Chrisl, as for the PWM function. Yes I do have a tachometer. I am not sure if I want to use a PID, can you suggest as to how I can calibrate it manually? – Shreeniket Joshi Sep 23 '19 at 16:58
  • About Serial: As I already wrote in the answer, if you just have commands consisting of 1 byte/character, you can just use Serial.read(), which reads exactly 1 character. About PWM: This is a a typical situation for a control cycle. Using PID is the best here. It get's you the desired output fastest and without oscillation. If you only calibrate the PWM values (mapping PWM values to RPMs by testing), that disregards the load on the motor and will not be accurate. Ultimately it is your decision, what you need. PID with the linked library is not difficult. – chrisl Sep 23 '19 at 17:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.