Creating a Camera Pan/Tilt head with DC Geared Motors & Xbox Style thumbstick

I’m completely new to the Arduino community, so I only know the few basics!

I’m trying to make a pan/tilt system for a camera jib/crane using an Uno board, with this motor controller: http://www.amazon.co.uk/Big-Bargain-Stepper-Controller-Arduino/dp/B00AAYOIEK/ref=reg_hu-rd_add_1_dp and 2x Geared DC Motors (6V, 20RPM) which obviously I have to power separately from the Arduino Uno board.

What I’m trying to achieve is to be able to control the speed and direction each motor shaft with a joystick/thumbstick (the Xbox 360 styled ones), possibly with another potentiometer somewhere to control the speed even further. It’s pretty much the same as David Holmes on Youtube is doing http://youtu.be/1Avm4blyp7Y here.

My Arduino Uno came in the post today so I’ve been programming for the past few hours. I think I’m on the right track with the following code:

int pan = 3;
int tilt = 5;

int VRpan = A0;
int VRtilt = A1;

int panval = 0;
int tiltval = 0;

void setup()
{
  Serial.begin(9600);
  pinMode(pan, OUTPUT);
  pinMode(tilt, OUTPUT);
  
  pinMode(VRpan, INPUT);
  pinMode(VRtilt, INPUT);
}

void loop()
{
  panval = analogRead(VRpan);
  tiltval = analogRead(VRtilt);
  
  if(panval < 502) //for the pan motor
  {
    //Rotate Clockwise
  }
  else if(panval > 522)
  {
   //Rotate Counterclockwise
  }
  else
  {
    //Release
  }
  
  if(tiltval < 502)
  {
    //Rotate Clockwise
  }
  else if(tiltval > 522)
  {
    //Rotate Counterclockwise
  }
  else
  {
    //Release
  }
}

Basically, I want to know if the code looks okay so far, so that I know I’m on the right track! (again, I’m new to Arduino, I don’t know much about the code!)
I’m putting the X axis of the thumbstick potentiometer as an input to analog pin 0, and the Y axis of the thumstick/pot as an input to analog pin 1.

When the thumbstick is centred, I don’t want either motor shaft to rotate, and instead be released (Is that right?). So I understand I need to set a ‘deadzone’ which I have done from 502-522 values that are read from the joystick pot.

Next, I’ve used If statements. Is this the way that I should be doing it? If not, please correct me! As you can see, I need to do a bit of research for the code that enables the PWM to the motor controller. I’m just curious as to how it communicates with it so that the motor rotates either Clockwise or counterclockwise, and I take it the variable speed is done by PWM?

Any help would be appreciated! Thanks.

James

The concept seems OK to me. There are probably 500 other ways of doing it, but stick with something you understand that works.

You may need to experiment to find the real mid point of the joysticks and adjust your deadzone accordingly. Write a short sketch that just shows the analog values in the Serial Monitor and watch what happens as you move the sticks.

…R

Thanks for clearing that up! Again, this is my first Arduino project so I’m still exploring the language.

The joystick is still to arrive, along with the motor driver, but I think I have most of the code sorted out now. If you or anyone else out there could have a look just to clarify that it looks okay! It seems to compile well, and I’ve uploaded it to my Uno board.

int VRpan = A0;
int VRtilt = A1;

int pan1pin = 2;
int pan2pin = 4;
int panPWM = 3;
int tilt1pin = 7;
int tilt2pin = 8;
int tiltPWM = 6;

int speed = 0;
int panval = 0;
int tiltval = 0;

int ledPin = 13;

void setup()
{
  Serial.begin(9600);
  pinMode(VRpan, INPUT);
  pinMode(VRtilt, INPUT);
  
  pinMode(ledPin, OUTPUT);
  pinMode(pan1pin, OUTPUT);
  pinMode(pan2pin, OUTPUT);
  pinMode(panPWM, OUTPUT);
  pinMode(tilt1pin, OUTPUT);
  pinMode(tilt2pin, OUTPUT);
  pinMode(tiltPWM, OUTPUT);
}
void loop()
{
  digitalWrite(ledPin, HIGH);
  panval = analogRead(VRpan);
  tiltval = analogRead(VRtilt);
  
  if(panval < 502) //for the pan motor
  {
    digitalWrite(pan1pin, LOW);
    digitalWrite(pan2pin, HIGH);
    speed = (panval/4);
    analogWrite(panPWM, speed);
  }
  else if(panval > 522)
  {
    digitalWrite(pan1pin, HIGH);
    digitalWrite(pan2pin, LOW);
    speed = (panval/4);
    analogWrite(panPWM, speed);
  }
  else
  {
    digitalWrite(pan1pin, LOW);
    digitalWrite(pan2pin, LOW);
  }
  
  if(tiltval < 502) //for the tilt motor
  {
    digitalWrite(tilt1pin, LOW);
    digitalWrite(tilt2pin, HIGH);
    speed = (tiltval/4);
    analogWrite(tiltPWM, speed);
  }
  else if(tiltval > 522)
  {
    digitalWrite(tilt1pin, HIGH);
    digitalWrite(tilt2pin, LOW);
    speed = (tiltval/4);
    analogWrite(tiltPWM, speed);
  }
  else
  {
    digitalWrite(tilt1pin, LOW);
    digitalWrite(tilt2pin, LOW);
  }
}

I’m not sure about the speed for each - thinking about it now, I should have two separate speeds for both the pan and tilt, but I’m not sure if that’s right for outputting to the pins for PWM to the motor driver?

Also, I take it you read the analog pins as A0 and A1 respectively?

James

I don't know why you have pan1pin, pan2pin and panpwm. The names don't make their functions clear.

Normally if you are using PWM then that is the only signal needed for the motor - via the H-bridge.

Also it's not a good idea to try to write the whole program at the outset. Instead create some small sketches that each operate one part of the problem. Foe example reading the values from the joystick and displaying them on screen or making one motor work at different speeds where the speed value is just part of the sketch code. When you are confident that you understand them all then join them together into a whole. Small pieces make debugging and exploring new hardware much easier.

...R

Robin is right to suggest that you approach this in steps to ensure that you understand what is going on and can test them separately. Your general ideas seem OK. Read the joystick, determine which way it is pressed and how far, set the motor control pins to move the motor the way you want and apply a PWM signal to the H bridge pwm pin to control the speed of the motor.

You will need to experiment with the motor speeds. Your current approach of using the joystick input value to set the motor speed will make the speed much less at one end of the range than the other. Is that what you want ?

What happens when the pan/tilt head reaches its limits in one direction or the other ? Does it have built in limit switches ?

Sorry! I’ve just added a few comments in my code to say what those pins do. ‘pan1pin’, ‘pan2pin’, ‘panPWM’, ‘tilt1pin’, ‘tilt2pin’, and ‘tiltPWM’ are the outputs to the H-bridge on IN1, IN2, EN1, IN3, IN4, and EN2 respectively, which control the direction of the motors. I’ve been testing this out with just the Uno board and the motor controller that I got this morning with a bit of separate code that I wrote. It’s working like a charm! There are 4 LEDs on the motor controller board to show which direction the motors are set to. One way for 1 second, released for 1 second, then the other way for 1 second, then released for 1 second, and it repeats.

Here’s my code now. I’ve changed around the pins to the motor controller a bit, so all of the wires are a bit less physically tangled. (As UKHeliBob pointed out, the speed is incorrect at the moment)

int VRpan = A0; //X-axis input from joystick
int VRtilt = A1; //Y-axis input from joystick

int pan1pin = 8; //High/low output to IN1 on H-bridge
int pan2pin = 7; //High/low output to IN2 on H-bridge
int panPWM = 9; //PWM output to EN1
int tilt1pin = 4; //High/low output to IN3 on H-Bridge
int tilt2pin = 2; //High/low output to IN4 on H-Bridge
int tiltPWM = 3; //PWM output to EN1

int speed = 0;
int panval = 0;
int tiltval = 0;

int ledPin = 13;

void setup()
{
  Serial.begin(9600);
  pinMode(VRpan, INPUT);
  pinMode(VRtilt, INPUT);
  
  pinMode(ledPin, OUTPUT);
  pinMode(pan1pin, OUTPUT);
  pinMode(pan2pin, OUTPUT);
  pinMode(panPWM, OUTPUT);
  pinMode(tilt1pin, OUTPUT);
  pinMode(tilt2pin, OUTPUT);
  pinMode(tiltPWM, OUTPUT);
}
void loop()
{
  digitalWrite(ledPin, HIGH);
  panval = analogRead(VRpan);
  tiltval = analogRead(VRtilt);
  
  if(panval < 502) //for the pan motor
  {
    digitalWrite(pan1pin, LOW);
    digitalWrite(pan2pin, HIGH);
    speed = (panval/4);
    analogWrite(panPWM, speed);
  }
  else if(panval > 522)
  {
    digitalWrite(pan1pin, HIGH);
    digitalWrite(pan2pin, LOW);
    speed = (panval/4);
    analogWrite(panPWM, speed);
  }
  else
  {
    digitalWrite(pan1pin, LOW);
    digitalWrite(pan2pin, LOW);
  }
  
  if(tiltval < 502) //for the tilt motor
  {
    digitalWrite(tilt1pin, LOW);
    digitalWrite(tilt2pin, HIGH);
    speed = (tiltval/4);
    analogWrite(tiltPWM, speed);
  }
  else if(tiltval > 522)
  {
    digitalWrite(tilt1pin, HIGH);
    digitalWrite(tilt2pin, LOW);
    speed = (tiltval/4);
    analogWrite(tiltPWM, speed);
  }
  else
  {
    digitalWrite(tilt1pin, LOW);
    digitalWrite(tilt2pin, LOW);
  }
}

UKHeliBob: I see what you mean about the joystick setting the motor speed… I’ll need to work on that bit to get what I want. You probably know what I mean, but basically when the joystick is lets say at 25% pushed to the left, I want the motor shaft to rotate counter-clockwise at 25% speed. Until you said, I didn’t realise that this wouldn’t work with the code I’ve got!

There aren’t exactly any limits with the pan/tilt head. If you’re talking about rotation, it can rotate 360+. Obviously I’m going to have a few cables to my camera for the monitor, controlling the zoom/focus/record, and the cables for the motors that control the pan/tilt head, but that’s about it.

James

Okay so, I’m really confused about converting the pot value to the speed output. I’ve attached an image to help what I’m trying to do.

I’ve got a deadzone of 20 in the middle of the pot, so 502-522 is the deadzone.
When I’ve got the pot value as 0, I would like the speed to be 255 counter-clockwise, and when I’ve got the pot value as 502, I would like the speed to be 0 counter-clockwise.
When I’ve got the pot value as 522, I would like the speed to be 0 clockwise, and when I’ve got the pot value as 1024, I would like the speed to be 255.

Any help trying to do this would be great!

James

With a h-bridge you set side A high and Side B low for forward and side A low and side B high for reverse.

If you use PWM then you need to apply it to the pin which should be high which means that your code will have to apply it to one side for fwd and the other side for rev. And as far as I know you NEVER have both sides high at the same time, even for an instant - unless you want smoke. That means that the first thing to do is make the non-PWM pin low and then apply PWM to the other pin.

...R

From what I've read and watched, you apply the PWM to the Enable 1 (EN1) and Enable 2 (EN2) pins to 'enable' each of the motors. The IN1 & IN2, IN3 & IN4 pins just controls the direction of the motors.

James

Robin 2: See this video to see what I mean

https://www.youtube.com/watch?v=1Q0ZwpycbzY

I've looked at the video and I've looked (briefly) at the L298 data sheet.

You are correctly interpreting what is shown in the video but I'm not sure if that's how the device is meant to be used. It looks to me that the enable pins should be a steady high or low to enable or disable a particular motor and the "signal" should go on the appropriate input pins. Of course it's entirely possible that both ways of controlling it are acceptable.

The device I have been using doesn't have the equivalent of an enable pin.

...R

jamesbonner:
When I’ve got the pot value as 0, I would like the speed to be 255 counter-clockwise, and when I’ve got the pot value as 502, I would like the speed to be 0 counter-clockwise.
When I’ve got the pot value as 522, I would like the speed to be 0 clockwise, and when I’ve got the pot value as 1024, I would like the speed to be 255.

Have a look at using the map() function. This will show the principle

int input;
int speed;

void setup() 
{
  Serial.begin(115200);
  for (input = 0;input <= 502; input++)
  {
    speed = map(input, 0, 502 , 255, 0);
    Serial.print("input :\t");
    Serial.print(input);
    Serial.print("\tspeed :\t");
    Serial.println(speed);
  }
  
  Serial.println();

  for (input = 522;input <= 1023; input++)
  {
    speed = map(input, 522, 1023 , 0, 255);
    Serial.print("input :\t");
    Serial.print(input);
    Serial.print("\tspeed :\t");
    Serial.println(speed);
  }
}

void loop() 
{}

To use it in your program you would use the input value to set the direction pins then feed the input value to the map() function. This will give you an output value to use for the PWM output.

Robin2: Hmm… okay then. I’ll just have to experiment with it for a bit, but remembering not to set both pins high at the same time XD

UKHeliBob: So for the map() function, could I use this code (just for one motor):

if(panval < 503) //for the pan motor
  {
    digitalWrite(pan1pin, LOW);
    digitalWrite(pan2pin, HIGH);
    speed = map(panval, 502, 0, 0, 255);
    analogWrite(panPWM, speed);
  }
  else if(panval > 521)
  {
    digitalWrite(pan1pin, HIGH);
    digitalWrite(pan2pin, LOW);
    speed = map(panval, 522, 1023, 0, 255);
    analogWrite(panPWM, speed);
  }
  else
  {
    digitalWrite(pan1pin, LOW);
    digitalWrite(pan2pin, LOW);
  }

James

Robin2: as far as I know you NEVER have both sides high at the same time, even for an instant - unless you want smoke.

That's incorrect. A correctly-designed H-bridge will tie each output high or low and never both (that's the scenario that causes smoke!). Sending both outputs high or low is fine and is just a way to leave the motor un-powered. Usually when you do this the two outputs which are connected to the same voltage level form a short circuit across the motor which would apply inductive braking if the motor was moving.

So for the map() function, could I use this code (just for one motor):

Looks fine to me

My approach covers poor designs as well as proper ones with little or no extra effort. The particular h-bridge that I'm using doesn't have protection.

...R

PeterH: That's incorrect. A correctly-designed H-bridge .....

Well thanks for all the help with the code! I'll post another update once I've got everything connected and working (fingers crossed).

James

how is this project going? dont suppose you have any schematics or pics or this work at all?

keep up the good work

KR

Marc