Help sending ASCII commands to Pan & Tilt

Hi,

I a newbie in programing and the Arduino world.
I'm trying to get a Pan & Tilt to work with Arduino and a Joystick by sending the commands in ASCII using a RS232 Shield, as per the technical information from the Pan&Tilt manufacturer.
But I'm running into some troubles and I'm trying to figure what I'm doing wrong.

First I've tested the program by using a simple Serial.print function and verifying the results on the serial monitor. So far so good: When I move the joystick the serial monitor displays the right command according to the position of the joystick.

Then I replaced the Serial.print for mySerial.print and connected and then connect the Pan & Tilt, nothing happens.
I've been doing a few test but nothing seems to work.

From what I understand I can not have USB connected to the Computer, so I did that.
Since the manufacturer says Data + and Data - instead of Rx and Tx. I tried that also both ways.
Nothing

I want to share the information of what I'm doing and maybe some one can catch what I'm doing wrong.

Thank you!!

The code

#include <SoftwareSerial.h>

// Defines new serial Port not to interfeer with USB Digital Pin 2 = RX, Digital Pin 3 = TX
SoftwareSerial mySerial =  SoftwareSerial(2, 3);

int Xpin = A0;             // Joystick X (horizontal)
int Ypin = A1;             // Joystick Y (vertical)
int Xval;
int Yval;
int restX = 512;                 // Joystick X rest position value
int restY = 512;                 // Joystick Y rest position value
int deadZoneX = 40;        // Dead zone for X (without movement)
int deadZoneY = 40;        // Dead zone for Y (without movement)
int dt = 200;                      // Delay time, This should be 200 (ms)

void setup() {

// open serial comunication
  Serial.begin(9600);

// Define pin modes for Xpin and Ypin
  pinMode(Xpin, INPUT);
  pinMode(Ypin, INPUT);

// Define pin modes for TX and RX
  pinMode(2, INPUT);
  pinMode(3, OUTPUT);

// Set the baud rate for the SoftwareSerial object
  mySerial.begin(9600);

}

void loop() {
  Xval = analogRead(Xpin);
  Yval = analogRead(Ypin);
  delay(dt);

// Set Pan Tilt Speed
  mySerial.println("!BMSP0001W\r\n");          // Sets motor speed value 1 (slowest); change this value up to 12 for faster speed
  
// if Joystick is moved left or right, move Horizontal stepper (Pan)
  if (Xval > (restX + deadZoneX)) {                      // Xval < 512 + 40 = 552
    mySerial.print("#AMMF0000W\r\n");          // Pan clockwise
  }
  else if (Xval < (restX - deadZoneX)) {                // Xval < 512 - 40 = 472
    mySerial.print("#AMMB0000W\r\n");           // Pan anti-clockwise
  }
  else {
    mySerial.print("#AMST0000W\r\n");           // Pan Motor Stop
  }

// if Joystick is moved up or down, move Vertical stepper (Tilt)
  if (Yval > (restY + deadZoneY)) {                       // Yval < 512 + 40 = 552
    mySerial.print("$AMMF0000W\r\n");           // Tilt Forward
  }
  else if (Yval < (restY - deadZoneY)) {               // Yval < 512 - 40 = 472
    mySerial.print("$AMMB0000W\r\n");           // Tilt Backward
  }
  else  {    // YVal >= 472 $$ YVal <= 552
    mySerial.print("$AMST0000W\r\n");             // Tilt Motor Stop
  }
}

Pan & Tilt Information

Pin 1 = GND
Pin 2 = +24VDC
Pin 3 = Spare
Pin 4 = DATA +
Pin 5 = DATA -

Pan&Tilt RS232/RS485 Communications Protocol

  • Supports device addressing, up to 52 instances of each of 4 types of equipment.
  • All communications in ASCII characters (dumb terminal compatible).
  • All commands and responses are same length- 12 bytes.
  • All commands and data are echoed by the device being addressed.
  • Devices never respond unless prompted first by host.
  • RS485 hardware interface.
  • No error correction except for echo from addressed device.
  • Only a single command is allowed per command string.
  • Default to 9600,N,8,1.

| Movement description | ASCII | Hex |
I Pan Motor I # I 0x23h I
I Tilt Motor I $ I 0x24h I
I Pan Motor I ! I 0x21h I

Examples of strings
(These may be entered using a ‘dumb’ terminal with line feeds and carriage returns enabled.)

Desired Action / Command String
Pan motor ‘A’ forward / #AMMF0000W

Schematics

You need an RS485 adapter. The figure shows what appears to be an RS232 adapter.

Hey jremington,

You are correct: I'm using a RS232 shield.
Since the documentation mentions the Pan&Titl as "compatible with RS232 and RS485 protocols and I already had a RS232 at home, I thought it could work.

I guess, also, it did not tick in my head until now, the part that says: "RS485 hardware interface." :confused:

I will then get a RS485 shield

But do you think the code is correct though?
I'm still unshure if I'm sending the commands the correct way.

Thanks

There is not enough information in your post to guess (post a link to the user manual).

Try it and see, once you have the correct adapter installed.

1 Like

The pan tilt driver may be RS232 compatible, but likely you have to use different pins, or set some DIP switches etc.

RS232 and RS485 have the same information transfer protocol, but very different electrical interfaces.

If the manual states "RS485 interface", then RS232 simply won't work.

1 Like

Just so the OP knows what the difference is and why the electrical interface is NOT compatible. The RS-232 electrical is + and - compared to the signal ground of the interface. The RS-485 electrical is + and - to just a pair of wires. No signal ground is necessary. The polarity of the two wires swap to indicate a 0 or a 1 bit.

1 Like

Yea, for sure I will get the RS485 shield and try.

I just wanted to also check on the code too, cause I have been unsure of the proper way to send the command. I've been reading a lot and looking at this forum for a while.
So, I think I finally got it but I could be missing something.

And sorry, I though I had posted enough info for that to be possible to be verified.

Here is the manual if you feel like looking at it:

Thanks a lot

I just got an email back from the manufacturer confirming I need a RS485 shield.
I think I go into a tunel vision concentrating to much on how to code this.

I will this thread posted with further results.

Thank you Paul,

That is a good an easy way to put it and to undestand

That’s sad, because the datasheet you quoted says it supports both 232 and 485

oh well

Update

So I got a MAX485 which is TTL to RS485 and followed the instruction to set the shield just as a transmitter as the Pan&Tilt does not need to respond (according the manufacturer).

The Pan&Tilt is not moving.

Then...
I've tried to send the comand with pin 1 tx with Serial.print("ASCII_Command") and changing it to Serial.write("ASCII_Command") eventhough from what I've understood that last function to send commands in HEX.
Also, I've tried the same as above with mySerial.print and mySerial.write. on pin 4(rx) and 5(tx)
And finally I've tried sending the command in HEX.

With all the above, I've tried sending a "Motor brake release" before the commands to PAN & TILT in case this could be stopping the movement....
And a delay after each command.... nothing

No results..... And I feel lost on what is wrong

The New Schematic is:

The code is:

#include <SoftwareSerial.h>

// Defines new serial Port not to interfeer with USB Digital Pin 4 = RX, Digital Pin 5 = TX
SoftwareSerial mySerial(4, 5);  // RX, TX

int Xpin = A0;             // Joystick X (horizontal)
int Ypin = A1;             // Joystick Y (vertical)
int Xval;
int Yval;
int restX = 512;           // Joystick X rest position value
int restY = 512;           // Joystick Y rest position value
int deadZoneX = 40;        // Dead zone for X (without movement)
int deadZoneY = 40;        // Dead zone for Y (without movement)
int dt = 200;              // Delay time, This should be 200 (ms)

void setup() {

  // open serial comunication
  Serial.begin(9600);

  // Set the baud rate for the SoftwareSerial object
  mySerial.begin(9600);

  // Define pin modes for Xpin and Ypin
  pinMode(Xpin, INPUT);
  pinMode(Ypin, INPUT);

  // Define pin modes for TX and RX
  pinMode(4, INPUT);
  pinMode(5, OUTPUT);

}

void loop() {
  Xval = analogRead(Xpin);
  Yval = analogRead(Ypin);
  delay(dt);

  // if Joystick is moved left or right, move Horizontal stepper (Pan)
  if (Xval > (restX + deadZoneX)) {            // Xval < 512 + 40 = 552
    Serial.println("Pan Clockwise");
    mySerial.print("#AMBR000W\r\n");           // Break Release
    delay(1000);
    mySerial.print("#BMSP0001W\r\n");          // Set Speed to 1
    delay(1000);
    mySerial.print("#AMMF0000W\r\n");          // Pan clockwise
    delay(1000);
  }
  else if (Xval < (restX - deadZoneX)) {        // Xval < 512 - 40 = 472
    Serial.println("Pan Anti-Clockwise");
    mySerial.print("#AMBR000W\r\n");           // Break Release
    delay(1000);
    mySerial.print("#BMSP0001W\r\n");          // Set Speed to 1
    delay(1000);
    mySerial.print("#AMMB0000W\r\n");           // Pan anti-clockwise
    delay(1000);
  }
  else {
    Serial.println("Pan Stop");                 // 472 < Xval < 552
    mySerial.print("#AMST0000W\r\n");           // Pan Motor Stop
    delay(1000);
  }

  // if Joystick is moved up or down, move Vertical stepper (Tilt) Using the mySerial.write instead of mySerial.print
  if (Yval > (restY + deadZoneY)) {             // Yval < 512 + 40 = 552
    mySerial.write("$AMBR000W\r\n");           // Break Release
    delay(1000);
    mySerial.write("$AMMF0000W\r\n");           // Tilt Forward with out setting the speed like for X
    delay(10);
  }
  else if (Yval < (restY - deadZoneY)) {        // Yval < 512 - 40 = 472
    mySerial.write("$AMBR000W\r\n");           // Break Release
    delay(1000);
    mySerial.write("$AMMB0000W\r\n");           // Tilt Backward with out setting the speed like for X
    delay(10);
  }
  else  {    // YVal >= 472 $$ YVal <= 552
    mySerial.write("$AMST0000W\r\n");           // Tilt Motor Stop
    delay(10);
  }
}

One more thing I tried:
I've tried to send the commands manual instead of using the joystick by using the following code:

#include <SoftwareSerial.h>
SoftwareSerial mySerial(4, 5); // RX, TX

String input;

void setup() {

  // Define pin modes for TX and RX
  pinMode(4, INPUT);
  pinMode(5, OUTPUT);

  Serial.begin(9600);
  mySerial.begin(9600);
  Serial.println("Serial Start");
  Serial.println("Type Command");
  delay(10);
}

void loop() {
  if (Serial.available()) {
    input = Serial.readStringUntil('\n');
    Serial.print("You typed: ");
    Serial.print(input);
    mySerial.print(input);
  }
}

Documentation for the Pan&Tilt

Any Ideas?

It is possible that you damaged the pan/tilt platform by exposing the RS485 inputs to negative RS232 voltages.

We don't think much of Fritzing diagrams on this forum, because they are very difficult to interpret, often wrong and usually misleading. It is not clear from yours exactly how you have connected the Software Serial port.

You should be checking for character echo to test the connection, via Arduino pin 4, but no connection is shown to that pin.

Please post a pic of a hand drawn wiring diagram showing ALL the connections, with pins clearly labeled.

Also post a link to the product page for the RS485 adapter.

Try this echo test program, to use the serial monitor as a dumb terminal.

#include <SoftwareSerial.h>

SoftwareSerial mySerial(4, 5); // (RX, TX) check correct pin assignments and baud rate

void setup() {
  mySerial.begin(9600);
  Serial.begin(9600);
  Serial.println("Echo test start");
}

void loop() {
  while(Serial.available()) {
  mySerial.write(Serial.read());
  }
  while (mySerial.available()) {
    Serial.write(mySerial.read());
  }
}
1 Like

You might want to try the "Motor report location" command and see if you get a reply. That command doesn't rely on any motor moving or stopping and/or whether the brake is applied.

Using the sketch that @jremington gave you above, you should be able to send commands from your IDE serial monitor like those in the examples section of your document. Just remember to set the line ending to "Both NL & CR" in the serial monitor.

The manual indicates that the device address can be changed. Do you know what your device address is?

If you still get no joy, then you may have to write a simple sketch that sends out a command stepping through each valid address until you get a response as a way of discovering your device address.

1 Like

hahaha, first tank you for telling me I should not us Fritzing diagrams. I was not aware and I though that way it would be clearer. I will steer away from that.
I will send later a "hand made" diagram that is hopefully clearer.

Now, the reason there is nothing on pin 4 is because this RS485 is a Simplex communication and I though from reading or possibly misreading the manual there was no need for a response I tested like that (also my lack of expertise / understanding of the protocol).

In order to switch from Transmit to Receive, you can use another pin and change is state from HIGH to LOW.

You can see some info here and example here:

So, If I want to get this to work I THINK should adapt the code you send me (thanks by the way) to something like this:

#include <SoftwareSerial.h>

SoftwareSerial mySerial(4, 5); // (RX, TX) check correct pin assignments and baud rate

void setup() {
  pinMode(3, OUTPUT);          // this pin will be used to change the RS485 from Transmit mode to Receive mode
  mySerial.begin(9600);
  Serial.begin(9600);
  Serial.println("Echo test start");
  digitalWrite(3, HIGH);      // Put RS485 in Transmit mode
}

void loop() {
  while (Serial.available()) {
    mySerial.write(Serial.read());
    delay(1);                  // Wait before going to Receive mode
    digitalWrite(3, LOW);       // Put RS485 in Receive mode
  }
  while (mySerial.available()) {
    Serial.write(mySerial.read());
    delay(1);                  // Wait before going back to Transmit mode
    digitalWrite(3, HIGH);     // Put RS485 in Transmit mode
  }
}

Correct??

As for the damaging the pan/tilt with my first Rs232 coms... I hope not. (let's cross fingers)

Thanks for the extra Ideas!

You are totally right about the addressing. Some how I was just assume the Address Character Byte (ID) as "A" but the manual state is can be anything from A-Z and a-z.
I wrote to the manufacturer to see if they can answer that. Other wise, like you said I will have to test each valid address. :fearful:

As for "Motor Report Location" command, I should also try that.
Just need to make sure the modification I suggested to @jremington Sketch for a half duplex communication would work.

Will keep reporting...
Thanks

I have no idea whether that code would work in half duplex mode, as it depends on character echo timing by the pan/tilt device. You may need the full duplex interface.

The "manual" you posted for the platform is pretty sparse.

1 Like

Your control of the RS485 RE/DE pins are not correct. Assuming that RE & DE are connected together and also connected to pin 3, then the code may look like this:

void loop() {
  digitalWrite(3, LOW);       // Put RS485 in Receive mode
  while (Serial.available()) {
    digitalWrite(3,HIGH);     // Put RS485 into tx mode
    mySerial.write(Serial.read());
  }
  while (mySerial.available()) {
    Serial.write(mySerial.read());
  }
}

Untested and a bit of a hack i'm afraid, but give it a go.

1 Like

Hi,
I have been thinking and searching about this last bit of suggested code.
2 questions here:

1- shouldn't the digitalWrite(3, LOW) be before the while (mySerial.available()) line to make the MAX485 be in receive mode before hand?

2- I've read some people running into troubles as some times the last byte is not yet sent before the status is change from Tx mode to Rx mode.
Solutions could be
a-

 delayMicroseconds (660);

b-

  while (!(UCSR0A & (1 << UDRE0)))  // Wait for empty transmit buffer
      UCSR0A |= 1 << TXC0;  // mark transmission not complete
  while (!(UCSR0A & (1 << TXC0)));   // Wait for the transmission to complete

To me it could look like this (with delay function):

void loop() {
  while (Serial.available()) {
    digitalWrite(3, HIGH);    // Put RS485 into tx mode
    mySerial.write(Serial.read());
    delayMicroseconds (660);
  }
  digitalWrite(3, LOW);       // Put RS485 in Receive mode
  while (mySerial.available()) {
    Serial.write(mySerial.read());
  }
}

or like this (with ``` "Wait for empty transmit buffer"

void loop() {
  while (Serial.available()) {
    digitalWrite(3, HIGH);    // Put RS485 into tx mode
    mySerial.write(Serial.read());
    while (!(UCSR0A & (1 << UDRE0)))  // Wait for empty transmit buffer
      UCSR0A |= 1 << TXC0;  // mark transmission not complete
    while (!(UCSR0A & (1 << TXC0)));   // Wait for the transmission to complete
  }
  digitalWrite(3, LOW);       // Put RS485 in Receive mode
  while (mySerial.available()) {
    Serial.write(mySerial.read());
  }
}

Could you let me know what you guys thing of this ?

Forgot to mention I based this from reading this link

https://www.gammon.com.au/forum/?id=11428