Controlling servo MG90S motor with touch sensor

Hello, I'm fairly new to Arduino. I would greatly appreciate help with my project. Initially, I'm trying to control the position and rotation of a servo motor arm with a touch sensor. I'm using an Arduino Uno board and powering the 1 Servo motor from my laptop for this initial setup. I'm trying to initialize the arm to start at angle 0, then rotate to 90, then return to 3. However, if the touch sensor is touched prior to reaching 10, then it rotates back to 90, and repeats unless it's not touched before 10, in which case it would rotate to 180 and stay there.

The code I've written initializes the arm at angle 0 but then just goes to 180 when touched. I can't figure out what I'm doing wrong.
This is the most recent code I've written. Thanks for your help. E



#include <Servo.h>

// constants won't change

const int TOUCH_SENSOR4_PIN = 7;   // pin connected to touch sensor4 's pin
const int myServo4_PIN     = 11;  // pin connected to servo motor4 's pin

Servo myServo4; // create servo object to control myServo4 motor

// Fourth Arm motor and sensor variables will change:
int angle4 = 0;           // the current angle of myServo4 motor
int lastTouchState4;      // the previous state of touch sensor4
int currentTouchState4;   // the current state of touch sensor4


void setup() 

{

//Fourth Arm motor and sensor:
 
   pinMode(TOUCH_SENSOR4_PIN, INPUT);               // set pin to input mode
     myServo4.attach(myServo4_PIN,400,7700);        // attaches the servo on pin to the servo object

     myServo4.write(angle4);
     currentTouchState4 = digitalRead(TOUCH_SENSOR4_PIN);
          
}


void loop() 

{

 lastTouchState4    = currentTouchState4;                 // save the last state
 currentTouchState4 = digitalRead(TOUCH_SENSOR4_PIN);     // read new state

        if(lastTouchState4 == LOW && currentTouchState4 == HIGH ){
            if(angle4 = 0){
            myServo4.write(90);
            delay(1000);
            myServo4.write(3);
          }
        
        else {
        if(angle4 >= 10 && angle4 < 90) {
             myServo4.write(90);
             delay(1000);
             myServo4.write(3);
          }
        
       else {
       if(angle4 < 10) {
            myServo4.write(180);    //servo motor goes to 180 degrees and stops if don't touch sensor4 before 10 degrees angle, must reset
            delay(900000000);       //extended delay
          }
        }     
        }
      }
}

    


    

hello, thanks for responding and your help. That's exactly what I'm trying to accomplish. : )

Hi @ed111

welcome to the arduino-Forum
read this short tutorial on how to post code as a code-section

additional here is a tuotrial how to write code for having different modes of operation

a description very similar to Delta_G's description just using the word "mode"
Initial mode Servo is at 0
mode 1: Servo starts moving towards 90. When it gets to 90 enter state 2
mode 2 : Servo starts moving back towards 3 degrees. If the touch sensor is triggered in this state then return to state 1. If you reach 3 degrees then enter state 3.
mode 3: Servo moves to 180 and does not leave this state.

in programming such modes of operation are called "states" and the code that realises such multiple modes of operation is called a state-machine

best regards Stefan

Hi Stefan - thanks for the quick response and for taking the time to educate me. Sorry for my first posting mistake. I will try to follow this guidance when posting future code. Hopefully I get it right.
Thanks,
E

You should RE-edit your first posting to have the code in a code-section
this is described in the tutorial too

ok, I just edited it...Please confirm I did it right?

Thanks for your help

Yes well done

thanks for your guidance. I'm trying to digest the " A Demo-Code explaining the switch-case state-machine and how to do things (almost) in parallel"

It's a bit overwhelming : )

So feel free to ask whatever you like. I want to improve this tutorial to be as easy to understand as possible

will do...thanks Stefan

Hello - so after 2 solid days of trying to figure this out, this is the code I've come up with. Unfortunately, I can't seem to figure out what I'm doing wrong. I've tried several approaches as to where I place the conditions, but nothing completes the task at hand correctly.

When I upload this code, the motor arm initially goes to pos 0, but then when sensor is first touched, it goes to pos 180 and stays there.

Can you determine where I am placing the wrong code and conditions?
Any help is greatly appreciated at this point .
Thanks in advance.
E


#include <Servo.h>


//define states and working functions
//myServo1 states
const byte START = 0;          //move Motor to 10 degrees
const byte MOVETO90 = 1;      //move Motor towards 90 degrees
const byte MOVEBKTO0 = 2;  //move Motor back to 0 degrees
const byte MOVETO180 = 3;    //move Motor to 180 if reaches 3 degrees
const byte STOP = 4;       //stop Motor at 180 degrees

// We want to start in state "START"
byte currentStateVar = START;


// constants won't change
// the momentary switch (Touch Sensor) we use to change the motor angle 
const int TOUCH_SENSOR1_PIN = 7;        // Arduino pin connected to touch sensor1 's pin

Servo myServo1;                         // create servo object to control a myServo1 motor

//define motor controller pins
const int myServo1_PIN = 11;            // Arduino pin connected to servo motor1 's pin

// variables will change:
int pos = 0;                            // the current angle of servo motor
int lastTouchState;                    // the previous state of touch sensor
int currentTouchState;                 // the current state of touch sensor


void setup() {
 // All motor control pins
  pinMode(TOUCH_SENSOR1_PIN, INPUT);    //Arduino pin connected to touch sensor pin
  myServo1.attach(myServo1_PIN);        // attaches the servo on pin 11 to the servo object

  lastTouchState    = currentTouchState;     //save last state of touch sensor
  currentTouchState = digitalRead(7);        //read new state of touch sensor
  
  Serial.begin(9600);
  
}




void startMotor(){
   //move Motor to 0 degrees
   pos = 0;
   myServo1.write(pos);
   delay(15);  //delay for 15 micro seconds
}

void turnMotor90(){
   //move Motor towards 90 degrees   
    
   while (pos = 0 && pos < 90) {
          (pos += 1);         // goes from 0 degrees to 90 degrees in steps of 1 degree
      { 
      myServo1.write(pos);    // tell servo to go to position in variable 'pos'
      delay(10);                       // waits 10ms for the servo to reach the position 
      }
    
    }
  }

void turnMotorBack0(){
   //move Motor back to 0 degrees
    
   while (pos = 90 && pos >=1) {
          (pos -=1);           // goes from 90 degrees to 0 degrees in steps of 1 degree
       {                       
       myServo1.write(pos);    // tell servo to go to position in variable 'pos'
       delay(10);                       // waits 10ms for the servo to reach the position 
    }
     
     currentTouchState = digitalRead(7);        //read new state of touch sensor
          if(currentTouchState == HIGH) {
          //The sensor is touched
          //set motor state depending on current state
                if(pos>0){                //sensor was touched on time so rotation continues
                  currentStateVar = MOVETO90;
                    }
                  else if(pos <=0) {           //sensor was not touched on time so rotation stops
                    currentStateVar = MOVETO180;
                    }
                    
                 }
   }
}


void turnMotor180(){
   //move Motor to 180 if reaches 0 degrees
   pos = 180;
   myServo1.write(pos);
   delay(50);  //delay for half microsecond
}

void stopMotor(){
   //stop Motor at 180 degrees
   Serial.print("Motor stopped because sensor not touched befor reaching 3 degrees angle");
   Serial.print("Press reset when you're ready to Start Motor again");
   delay(500);
}




void myStateChain() {
  
  switch(currentStateVar)  {         // this is the start of the switch 
    case START:                   // this starts the state of START and it is what we do if
                                  //current state == START

        Serial.print("START");
        startMotor();
        
        currentTouchState = digitalRead(7);        //read new state of touch sensor
        
        if(currentTouchState == HIGH) {
          //The sensor is touched
          //set motor state depending on current state
          currentStateVar = MOVETO90;
        }
        break;                                    //this ends the state of "START"

    case MOVETO90:                                //start of the "MOVETO90" case
                                                  //current state == MOVETO90

        Serial.print("Moving to 90 degrees angle");
        turnMotor90();

        
        if(pos=90) {
        currentStateVar = MOVEBKTO0;       //set motor state depending on current state
        }
        break;                                    //this ends the state of "MOVETO90"

    case MOVEBKTO0:                               //start of the "MOVEBKTO3" case
                                                  //current state == MOVEBKTO3

        Serial.print("Moving back to 3 degrees angle from 90 degrees angle");
        turnMotorBack0();
        break;                                    //this ends the state of "MOVEBKTO3"   


    case MOVETO180:                               //start of the "MOVETO180" case
                                                  //current state == MOVETO180

        Serial.print("Sensor not touched on time so rotation stopping");
        turnMotor180();
        if(pos=180) {
          currentStateVar = STOP;
        }
        break;                                    //this ends the state of "MOVETO180" 

    case STOP:                                    //start of the "STOP" case
    
        //motor moves to 180 degrees and stops until reset      
        stopMotor();
        break; 
        
            
  } // this is the end of the possible cases for switch(currentStateVar)machine
  

//delay(100);
}
    
void loop() {
  myStateChain();                  // Run state machine
}
 

Is anyone able to help me with this project? I appreciate any help : )

Here is a WOKWI-simulation of your code with some added lines of code

At the top there are useful macros which were not yet used
I added an array of array of char to print changes from state to state
but they were printed only once per state-change

This makes it much easier to follow what the code is doing.
You will see that your code runs through all states at maximum speed.
Your servo has no chance to reach a position you just move on to the next state immediately
this means you have to check if the new servo-position is read by using the command servo.read();

changing to a new state should only be done if the new servo-position is reached.

try a modification by adding what I have described above.
Additionally you should have described in your posting what you observed when running your code.

You should always describe what behaviour you do observe running your code.
This is very important information to distinguish between pure software-bugs and hardware-bugs

printing only on a variable-change is also very useful.
Another way for analysing is to insert delay()
just for analysing !

best regards Stefan

Hi Stefan - thanks for responding. I really appreciate you taking the time to help me solve this task. In my last post I had mentioned what I observed when running the last code, namely "When I upload this code, the motor arm initially goes to pos 0, but then when sensor is first touched, it goes to pos 180 and stays there."

That's all it did, nothing else unless I hit reset. I'm not sure if there was other behavior you were wondering about?? Unfortunately, there was none : )

If I'm understanding your feedback correctly, the behavior is taking place because it's running though all states too fast to register and read the sensor being touched in between the initial and final states. Therefore, it just jumps to the final state.

Can you confirm a couple of things for me before I make some changes?

  1. What should I use for the timing in my formulas in order to give this machine enough time for the user to react (i.e. touch the sensor) without the motor arm movement being too slow?

  2. What is the right place(s) / timing in the code structure / sequence to read the new servo-position using the servo.read(); command ?

Should it be within each case or within each state function?

Thank you
E

BTW, thanks for creating this simulation and adding the line of code to help me learn through this exercise. I find it very useful. Hopefully I can get this process to work soon so I can move to the next phase - multiple motors.
Cheers!
E

I do not yet understand what your wanted behaviou in detail is
write down all things and all conditions

as an example
state 1: move servo to 0 degrees

state 2: wait for touchbutton to be pressed
if touchbutton is pressed go on to state 3
state3: wiggle the servoarm 5 times for 20 degrees
etc. etc.

I suggest inside the function myStateChain() as these checking is used to change the state-variable

Hello ed111

I only have one small question for my understanding:

What is this programme used for in the real world?

The behavior is exactly as summarized by Delta_G and then your self:

Initial mode: start Servo at angle 0. If the touch sensor is touched, then it enters Mode 1
mode 1: Servo starts moving towards 90. When it gets to 90, it enters state 2

mode 2 : Servo starts moving back towards 0 degrees. If the touch sensor is triggered in this state before the angle reaches 3, then it returns to state 1 (starts cycle over again...mode1 then mode2). However, If you reach 3 degrees then it enters state 3.

mode 3: Servo moves to 180 and does not leave this state until reset.

Hi Paul - I'm fairly new to Arduino and came up with this project as a way to learn.
I appreciate any help.
Thanks,
E

Hi Stefan - are you able to write a simple code to complete the task I'm trying to perform?

I've tried several adjustments and approaches and nothing works. I'd really appreciate your assistance as there's something I'm just not able to figure out to get this to work.

Thanks