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
}
}
}
}
}
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
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
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
}
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 !
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?
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?
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?
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
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 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.