Controlling servos with Joystick via LCD

Hi,

Here is my basic project plan:

  • I want to display values x, y, and z on an LCD screen.

  • Two servos will turn x times per y minutes for a total time of z minutes.

  • The values on the LCD screen can be changed using a joystick to move the cursor, and a potentiometer to increase/decrease digits.

  • When i press the joystick switch, the servos will start/ pause.

I’m stuck because:

  • I’m not sure how to write code that would enable me to use the joystick to set the cursor on the LCD screen and then use a single potentiometer to individually adjust values xyz.

  • I’m not sure how to write code that would let me use the joystick as a ‘switch’ to start/stop the servos.

This is my code so far:

/*
Joystick + LCD + 2 Servos

JOYSTICK - 2, A0, A1
LCD OUTPUT PINS - 4, 6, 10, 11, 12, 13
POT1 control LCD Brightness
POT2 - A5 
SERVO1 - 7
SERVO2 - 8

The servos will turn x many times every y minutes for a total 
time of z minutes.

The LCD will display the variables x, y, and z

The joystick will set cursor position on LCD

POT2 =INPUT - will increase/ decrease variables x, y, and z

When the joystick is pushed, the servos start/stop

   -=TO DO=-
   -Find out how to change cursor position with joystick+ enter new values
   -Find out how to Control servos with xyz values
  */
  
#include <LiquidCrystal.h>
LiquidCrystal lcd(4, 6, 10, 11, 12, 13);
char Line1[]="Rotate x      ";  //the string to print on the LCD
char Line2[]="For total";  //the 2nd string to print on the LCD

#define xyzPin A5 //POT2 controls input of variables x, y, + z

int xVal = 0; //desired x int to be displayed on LCD-Position(8,0)
int yVal = 0; //desired y int to be displayed on LCD-Position(11,0)
int zVal = 0; //desired z int to be displayed on LCD-Position(10,1)
int pot2Val = 0;        //initial analog reading of POT2 Pin A5


#include <Servo.h>
Servo myservo1;//create servo object to control servo1
Servo myservo2;//create servo object to control servo2

const int SW_pin = 2; // JOYSTICK digital pin connected to switch output
const int X_pin = 0; // JOYSTICK analog pin connected to X output
const int Y_pin = 1; // JOYSTICK analog pin connected to Y output

void setup()
{
  
  lcd.begin(16, 2);  // set up the LCD's number of columns + rows
  
  pinMode(A5, INPUT); //establish POT2 as input
  
  pinMode(SW_pin, INPUT); //Joystick z axis (SWITCH) = input
  digitalWrite(SW_pin, HIGH);
  Serial.begin(115200);   // check that brackets# corresponds in serial monitor 
 
  myservo1.attach(7);//attaches the servo on pin 7 to servo object
  myservo1.write(0);//back to 0 degrees 
 
  myservo2.attach(8);//attaches the servo on pin 8 to servo object
  myservo2.write(0);//back to 0 degrees 
  }
  

void loop() {
  
  Serial.print("Switch:  ");    //Joystick Info to be displayed in Serial Monitor
  Serial.print(digitalRead(SW_pin));
  Serial.print("\n");
  Serial.print("L-R: ");  //0=L 1000=R  Left-Right Joystick x axis
  Serial.print(analogRead(X_pin));
  Serial.print("\n");
  Serial.print("UP^vDOWN: ");  //0=UP 1000=DOWN Up-Down Joystick y axis
  Serial.println(analogRead(Y_pin));
  Serial.print("\n\n");
   
    pot2Val = analogRead(xyzPin);  // Read input of Pot2 to set required xyz values
   
   xVal = (pot2Val * 0.009765625);  // conversion of data to rotations - 10/1024 = 0.009765625 - max amount of rotations is 10
   yVal = (pot2Val * 0.0146484375);  // conversion of data to minutes - 15/1024 = 0.0146484375 - max amount of minutes is 15
   zVal = (pot2Val * 0.029296875);  // conversion of data to minutes - 30/1024 = 0.029296875 - max length of time is 30mins

  lcd.clear();   //stops problems when you change from two to one digit figures - the last digit is erased
  lcd.setCursor(0,0); // set the cursor to column 0, Row 0: Top LHC
  lcd.print(Line1);   // Print line one 
  lcd.setCursor(10,0);
  lcd.print("/");
  lcd.setCursor(13,0);
  lcd.print("min");

  lcd.setCursor(0,1);
  lcd.print(Line2);   // Print line two
  lcd.setCursor(13,1);
  lcd.print("min");
    
 
 

  delay(800);
  
   
}

As you can see, I’ve set up the serial monitor to display info about Joystick position, so I’m guessing I would need to use this data to build the code that I am trying to make, i’m just not sure how to go about it.

Any ideas or links or hints would be wonderful!!

Thanks very much

So I assume by your description, "The servos will turn x many times every y minutes for a total
time of z minutes.", that these are continuous-rotation servos. (Please correct me if this assumption is wrong.)

If they are C-R servos:-
a. How will you know how many rotations they've done?

b. This will not move the servo to any particular position, it will start it turning at full speed in one direction, (CW I think):-

myservo1.write(0);//back to 0 degrees

At the moment i just have regular servos, but I will need to get CR ones eventually yes.

As i'm just in the early stages of my little prototype i'll adjust the code for testing purposes to suit the servos that i have to hand.

What i am really more interested in right now is changing the values on the LCD with the joystick/potentiometer, and and finding out how to get servos to start/stop by pushing joystick like a switch.

Sorry didn't mention that before!

I'm unclear about how you want to determine the positions for the servos to move to when the joystick button is pressed. I assume that you want both servos to move simultaneously when the button is pressed. When the button is pressed, do you want the current joystick x and y values to be mapped to servo positions in degrees, then the servos moved to those positions?

As far as getting a servo value from an analogue input value, you can use 'map()' to map the 0-1023 ADC value to 0-180 for the servo position like this:-

int adcVal = analogRead(A0);
byte servoVal = map(adcVal, 0, 1023, 0, 180);
servo.write(servoVal);

Edit: It's past my bedtime, and I'm on the way to bed, so can't think more about this right now, sorry.

What i am really more interested in right now is changing the values on the LCD with the joystick/potentiometer,

All you write to the LCD now is two hard-coded strings. Add some more/different lcd.print() statements.

and and finding out how to get servos to start/stop by pushing joystick like a switch.

You don't understand what a servo is, do you? Starting or stopping a servo makes no sense. Moving a servo to a position (or speed when you replace the servos with not-really-servos) does make sense.

Ok guys, thanks for getting back to me..

Perhaps i should have made it more explicitly clear that I am a total beginner with no background in anything vaguely technical whatsoever doing my best, and I posted the question because i'm stuck and needed help.

I KNOW i don't know what i'm doing - that's why i asked for help! It's incredibly difficult to find information that makes any of this stuff even a little bit clear for beginners.

All you write to the LCD now is two hard-coded strings. Add some more/different lcd.print() statements.

I just googled 'hard coded strings' - no luck, i'm just even more confused. Care to elaborate? I realised that i probably need more lcd.print statements - that's not really the part i'm struggling with - it's moving the cursor with a Joystick and then using a single potentiometer to change the different values.

You don't understand what a servo is, do you? Starting or stopping a servo makes no sense. Moving a servo to a position (or speed when you replace the servos with not-really-servos) does make sense

Here is an example of what i am trying to achieve:

The servos will rotate twice (x) every three (y) minutes for fifteen (z) minutes.

So, after i have somehow entered the variables x y z with the potentiometer, i will press the joystick switch, and the process will begin. I thought it would be good if the joystick switch could be used again to stop everything running.

I don't want to start/stop the servos with the joystick as such, I apologize if i didn't explain things properly - i just want to use it to signal that the variables i have entered are final, and that the servos can start spinning x times per y minutes for z minutes once it has been pressed.

If this isn't possible, i'd appreciate some tips from people who obviously know a lot more than i do.

I'm not trying to wind anyone up, just asking for help in a help forum.

I KNOW i don't know what i'm doing - that's why i asked for help! It's incredibly difficult to find information that makes any of this stuff even a little bit clear for beginners.

It is not. If you do not know what a servo does, why did you buy any? There is a certain expectation that you have at least a fundamental understanding of the hardware before you start trying to control it.

The servos will rotate twice (x) every three (y) minutes for fifteen (z) minutes.

That is NOT possible. If you have standard servos, they have a range of angles that they can move through, typically 0 to 180 degrees. You can't get two rotations from a 0 to 180 servo. You could get two rotations from a sail winch servo, but they are expen$ive, and you could only get two rotations, which does not seem to be what you want.

If you have continuous rotation servos, they are not really servos. All you can control with them is the speed. You would need some other way to know when the servo has rotated enough.

I doubt that servos, continuous rotation or not, are what you should be using. So, lets start with what the servo is actually doing.

So, after i have somehow entered the variables x y z with the potentiometer

Just moving a potentiometer around is not going to give you x, y, and z. You could have a switch that you use to say "read the potentiometer pin now, and save the value in values[n]", where n changes every time you press the switch. Or, you could have three switches that each define a different value for n.

…anyone still out there?

If any of this was obvious, then I wouldn't be here asking for advice. Feel free to refrain from replying to my questions if you feel they are beneath you.

I know that a regular servo can't turn 360, that's why i planned on getting CR servos and i just wanted to experiment for now with what i have. I didn't buy them specially; they came in a kit for beginners.

If the CR servos don't turn out to work, i will experiment with motors or something else (unless i get some good tips from the forum). My project is a work in progress. I'm just trying to learn more so it will get there eventually. If it was all finished perfectly, then i wouldn't be asking for help.

So again, any ideas on how i can use the joystick to set the cursor on the LCD, and then increase/decrease each of the different values with a potentiometer?

Just moving a potentiometer around is not going to give you x, y, and z. You could have a switch that you use to say "read the potentiometer pin now, and save the value in values[n]", where n changes every time you press the switch. Or, you could have three switches that each define a different value for n.

I have already figured out a way of calculating the x y z values with the potentiometer in my code:

 pot2Val = analogRead(xyzPin);  // Read input of Pot2 to set required xyz values
   
  xVal = (pot2Val * 0.009765625);  // conversion of data to rotations - 10/1024 = 0.009765625 - max amount of rotations is 10
  yVal = (pot2Val * 0.0146484375);  // conversion of data to minutes - 15/1024 = 0.0146484375 - max amount of minutes is 15
  zVal = (pot2Val * 0.029296875);  // conversion of data to minutes - 30/1024 = 0.029296875 - max length of time is 30mins

I thought i could just use xVal, yVal etc when figuring out how to code for the servos/motors/ whatever spinning device i end up using. The problem is that i don't know how to set the cursor on the LCD display with the joystick to enter each value individually or if this can be done. Your idea of a button sounds like what i was trying to achieve by pushing the joystick switch... I'm still not what kind of codes i would need though.

The problem is that i don't know how to set the cursor on the LCD display with the joystick to enter each value individually or if this can be done.

The state change detection example shows how to tell when the state of a switch (technically, the state of the pin that the switch is connected to) changes. You can use this to count how many times the switch has become pressed. Do different things when the count is 1, 2, or 3.

I've hinted that you need to talk a bit about your project, not so much about how to do it. If we understood what you are trying to accomplish, we could offer more than "that won't work".

The project is a photo film developing tank.

The best way to get an even development of film is to simultaneously rotate a cylindrical tank longitudinally and latitudinally a set number of times per minute for a certain length of time - the variables change according to the type of photographic film, the chemicals being used, the developing technique, other experimental factors etc.

One servo / motor will be used to spin a platform like a windmill’s blades with the development tank attached, while the other servo (or probably motor) will also be attached to the spinning platform via a split-ring, and will be rotating the tank width-ways.

The tank when full of chemicals is too heavy for a cheap plastic servo, so i will definitely have to change the hardware when (if) i eventually get this thing sorted and built, right now i’m just trying to figure out the codes and fill in the gaping holes in my knowledge and make a sort of miniature prototype just so i know that something like this could in theory work.

One servo / motor will be used to spin a platform like a windmill's blades with the development tank attached, while the other servo (or probably motor) will also be attached to the spinning platform via a split-ring, and will be rotating the tank width-ways.

If the amount of rotation has to be exact (2.1244587455 revolutions, as opposed to turn at somewhere near 30 RPM for 4 seconds to get somewhere near 2 revolutions), then stepper motors are the way to go. If not, then simple electric motors, run for some period of time, are easier.

Stepper motors, and the appropriate drivers, are available in a variety of sizes, so it should be possible to find one that can move your tank/mechanism.

Stepper motor prices go up as the voltage/current goes up, but the increase is minor. Stepper motor drives, on the other hand, become a LOT more expensive as the torque (voltage and current) goes up.

"Servo" frequently refers to a position servo like the one that comes in the Arduino starter kit. Strictly speaking it refers to a (usually electromechanical) arrangement that employs feedback for control of some physical parameter. A motor-tachometer pair, with electronics that use feedback from the tach to hold a steady, commanded speed, i.e. a velocity servo, is just as much a true servo as a position servo is.

A stepper motor, which (with the right drive electronics) can maintain a steady, commanded speed or move to a commanded position* even in open loop operation, is not a servo, but may be a good choice here. I suspect a motor-tach is the better way to go, but I haven't searched for parts so I don't really know.

Frank, I think you have several issues with your project's conceptual design, and would be happy to offer some advice in a separate post or PM if you would like. For now, I'll confine myself to the specific bit of help you've asked for.

If you use a pot as you've described, I think the interface will be awkward to use. Let's say you've just finished setting x to 6. The pot is now somewhere from 55% to 65% of full scale. Now you use the joy stick to move the data entry selector (cursor) to y, and y immediately changes to the same percent of full scale, so 8 or 9. But it's really z you wanted to change next, so you move on to z. It changes to somewhere from 16 to 19. Even after you set z where you want it, you have to go back and fix y.

I suggest that you would be better off with a pair of buttons for "count up" and "count down." Then, when you select one of the parameters to change, no change occurs until you press one of the buttons. You could also use an encoder wheel, as those indicate movement in either direction, but not position.

You are using an analog joy stick. I suggest that you would be better off with a digital stick, which just has a switch for each direction, and can be had with a motion restrictor that keeps you from moving the stick diagonally. (See the photos.) Then, you would use the left-right pair of switches to navigate among the three parameters, and the up-down pair to change the values. This can easily be mocked up using four buttons, and that might even prove more desirable for the final configuration; four-way stick vs. four buttons is really a matter of taste. Paul S has already pointed you toward the state change example elsewhere; in the configuration I'm proposing, you would use that technique for the four-way and the "go" button alike.

Now, if you really do want to use the pot, you've got a couple of mistakes with how you're scaling the pot's value. First is that you're changing all three values (xVal, yVal, and zVal) together. Since you've only selected one of the three parameters to adjust at a time, you should use something like a switch-case structure to pick which one is set according to the pot.

Second, the scaling is wrong. Using z for example:

zVal = (pot2Val * 0.029296875);  // conversion of data to minutes - 30/1024 = 0.029296875

Since the highest value you will ever get from the analogRead() is 1023, the highest value of 0.029296875 times that is 29.970703125, and when that is assigned to an int, you will get 29. You'd be best off, in my opinion, using the map() function, as Old Steve suggested. The code would be:

zVal = map(potVal, 0, 1023, 0, 30);

and similar for xVal and yVal. If you'd rather do the math explicitly, you need to: 1) change 1024 to 1023 in your scale factors and 2) add 0.5 to the floating result before truncating it into the int variables.

zVal = int(potVal * 30.0/1023.0 + 0.5);

The subject line of this thread sets off an alarm in my head. If I'm reading too much into it, please forgive me. The thing is, you're not "controlling servos with Joystick via LCD." The joystick and LCD are parts of the user interface, and that is really a whole different function from controlling the servos. x, y, and z values that are generated within the UI are used by the controller. You could get x, y, and z over the USB line from the computer, and the control code wouldn't change at all. You could (and probably should) send the x, y, and x values from the UI over to the computer (to test the code.) Am I picking trivial nits here? No. When you separate these two functions in your mind, it is likely that some difficulties will disappear, and that certain necessities will become obvious. For instance, you may already have realized that the UI and control code ought to use separate versions of x, y, and z, with the UI values being transferred to the control parameters when the go button is pressed.

Incidentally, it looks to me like you don't really need three parameters, x, y, and z. What you're doing is spinning at (x/y) RPM for z minutes. So algebraically, you could turn at α RPM for β minutes, and only take the two parameters from the user. You may very well have your reasons for using three, such as tradition in the photography world; I wouldn't know about that.

  • While counting steps can bring you to a precise location if everything goes smoothly, it really isn't reliable and you ought to use a position sensor as well. But as this is a speed control problem, it is (mostly, probably) irrelevant.