Receive Pelco commands from cctv system, move servo's

Anyone know of a sketch for the arduino that can receive pelco D or P commands, as used in CCTV systems for pan, tilt, zoom camera's, and translate the pan and tilt commands into servo commands???

I have a few static camera's in my aviary that i would like to move about a little, i already have a couple of proper (and expensive) PTZ dome camera's in the roof, and i use the fixed camera's pointed at the nest sites,

I want to mount the camera's on a couple of standard hobby servo's, and control the servo's using my existing CCTV systems joystick controller, which sends the Pelco commands in RS485 format down a twisted pair cable.

so i guess first thing i need is an RS485 to RS232 converter for the arduino?

But as usual i have no idea how to do the coding, or if it can even be done, i've searched and only found other wanting to do similar, but no solutions.

I've got a wireless IP camera which has built-in pan/tilt/zoom and can be controlled via a web interface that supports multiple cameras. It wasn't expensive and a few of these might give you a better and easier solution than using your existing CCTV system.

If you decide you want to stick with CCTV then you need to convert the RS485 down to TTL levels (not RS232) in order for the Arduino to interface to it. I'm sure there are shields and boards to do that although I haven't used any. You'd need to find or write a library to decode the 'Pelco' (?) command protocol. This doesn't sound as if it would be complicated to write, as long as you can find and understand the specs for the protocol.

Decoding the Pelco commands looks very simple to me. Just 7 bytes in a frame:

http://www.commfront.com/RS232_Examples/CCTV/Pelco_D_Pelco_P_Examples_Tutorial.HTM#1

Also converting RS485 is very simple. The main difference is the physical interface (differential and different voltages.) The protocol layer is different really only the ability to address and daisy-chain connections. Using a driver IC, you only need a few passive components. There are example circuits in the datasheets. Here's one: http://cds.linear.com/docs/en/datasheet/486fc.pdf

The output will already be TTL compatible.

I put the word "Pelco" into the search facility.

AWOL: I put the word "Pelco" into the search facility.

So did i... well, i think i put pelco and servo, and i found people wanting to do similar, but not getting anywhere,

I need to keep it all running on my existing system really, as i not only use the cctv dvr's keyboard/joystick to operate the camera's, but an infra red controller, plus web interface, central management software and mobile phone viewer,

i'll keep looking and check the links out, i read somewhere someone had found servo's that had been modified to accept pelco commands rather than the standard varying pulses from a RC system, but it was just a comment someone made, and no more info given.

Right, i've found there are RS485 shields available, in america it seems so far, but i'll keep looking for a uk supplier... tho TBH it does look pretty simple to make my self.

http://www.robotshop.com/rs485-shield-arduino-3.html

That should get me the signal from the cctv system into the arduino safely, i just need to figure out that complicated part of writing code to make the arduino do something with it

(i am not a coder, making pcb's, soldering, modifying hardware, no probs, but writing stuff to make the hardware do stuff is very very hard for me, not least because my spelling is atrocious, and slow due to arthritis, so many many mistakes are made)

Anyway, i believe that the pelco command for say pan right is sent once, and the cam pans untill the stop command is sent (the tx/rx led's on my joystick seem to veryify that) So i need to listen for commands in hex format, then translate them to servo commands, i assume the stock servo library will handle the max rotation part of the servo, i.e. even if the pan right command hasnt been nulled with a stop command, the servo will not try to move past 180 degrees,

I don't need variable speed on the servo's, they are only going to move the camera's a little bit so i can view into the nests when the parents are blocking the view of the chicks where the cam is pointing to start with, but my joystick sends the variable speed commands... the more i move the joystick in a direction, the faster the cam pans... again i can see the tx/rx led's showing the commands are sent on each speed step i pass as the joystick moves over more,

So should i do something to ignore another pan right command after the first, thus ignoring the speed steps, untill a stop command has been recieved?

My thinking is thus, upon recieving the pan right command.... 'FF 03 00 01 01' i believe FF= sync bit, 03= cam address (already got 2 ptz's on the system, 01 and 02) 00= the first command.. not used this time, 01= pan right, 01= speed slowest, plus the checksum i imagine... then the arduino starts sending the pan servo pulses to rotate it right, increasing the pulse count so the servo moves round???

please dont laugh too hard, this is confusing and im struggeling.

I want to mount the camera's on a couple of standard hobby servo's, and control the servo's using my existing CCTV systems joystick controller, which sends the Pelco commands in RS485 format down a twisted pair cable.

If the distance isn't too far, might be simpler to make your own joystick/pot control setup for the servos and just use the existing wiring.

gazz: Right, i've found there are RS485 shields available, in america it seems so far, but i'll keep looking for a uk supplier... tho TBH it does look pretty simple to make my self.

Hobbytronics have the Sparkfun RS485 http://www.hobbytronics.co.uk/components/breakout-boards/rs485-breakout I have ordered stuff from them several times and had no problems. Proto-Pic is another UK supplier that has the same item http://proto-pic.co.uk/rs-485-breakout/ CoolComponents is another UK supplier of decent stuff though a quick search did not find RS485. And if your prepared to maybe wait a bit there is always eBay

@gazz

Did you find any way to decode Pelco Commands?

I managed to decode Pelco D commands

Used this information:

I’m not finished yet to control all the hardware but I can read all the commands if I want to :slight_smile:
I use the Checksum to be sure wrong received commands are ignored.
Just finished testing to control the PAN speed. Use PWM to set the right speed.
Not happy with it. Searching for another way to control the motor speed. With light (low current) motors it works Ok.

For recieving RS-485 commands I use a MAX485 IC. For testing you can use the serial comport of the Ardiuno.

/*
This program is used for an Arduino to receive and decode PELCO-D PTZ Commands

Thanks to Michael Blaylock for his sketch. Learning how to read and procces serial data

*/

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 9, 8, 7, 6);

byte outArray[7]; // read data Pelco Command
unsigned stopcheck; // For checking when a STOP command is received (257 Decimal)
int checksum; // For Calculating Checksum. Sum of the payload bytes (bytes 2 through 6) in the message
int ByteNumber;
int MotorSpeed;

void setup(){

lcd.begin(16, 2); // set up the LCD’s number of columns and rows:

Serial.begin(9600); // baud rate 9600 can be 1200,2400 or 4800

pinMode(3, OUTPUT);
pinMode(5, OUTPUT);
pinMode(13, OUTPUT);

digitalWrite(3, HIGH);
digitalWrite(5, HIGH);

}

void displayData() // Display the array in serial monitor for debugging
{
for (int j = 0; j<7; j+=1){
Serial.println(outArray[j],HEX);}
Serial.println(“Data Printed”);}

void loop()
{
if ( Serial.available () > 0) {
outArray[ByteNumber ++] = Serial.read();}

if ( ByteNumber > 6){ // process it
ByteNumber = 0; // ready for next time
// displayData(); // for debugging

stopcheck = outArray[0] + outArray[1] + outArray[2] + outArray[3] + outArray[4] + outArray[5] + outArray[6] ; // Calculate if STOP Command is received
if ( stopcheck == 257){ // When stopcheck is 257 decimal a STOP command is received
StopActions();} // Stop all PTZ Actions

else{ printCommand();} // Print Pelco command on LCD

if ( bitRead(outArray[3],0) == 0 ){ // When BIT 0 = 0 command 2 than data is Normal command (PTZ)
Decoderen();} // Try to decode the Pelco Command

if ( bitRead(outArray[3],0) == 1 ){ // When BIT 0 = 1 command 2 than data is an Extended command
ExtendedCommands();} // Try to decode the Extended Pelco Command

} // end if full
} // end of loop

void Decoderen()
{

lcd.setCursor(0,1);

MotorSpeed = map (outArray[4], 0, 0x3F, 255, 0);
// PAN TILT:
if ( bitRead(outArray[3],1) == 1 ){
analogWrite(3 , MotorSpeed);
// digitalWrite(3, HIGH);
lcd.print("RIGHT SPEED: ");
lcd.print(outArray[4]);}

if ( bitRead(outArray[3],2) == 1 ){
analogWrite(5, MotorSpeed);
// digitalWrite(5, HIGH);
lcd.print("LEFT SPEED: ");
lcd.print(outArray[4]);}

if ( bitRead(outArray[3],3) == 1 ){
lcd.print("UP SPEED: ");
lcd.print(outArray[5]);}

if ( bitRead(outArray[3],4) == 1 ){
lcd.print("DOWN SPEED: ");
lcd.print(outArray[5]);}

// ZOOM IRIS FOCUS:
if ( bitRead(outArray[2],2) == 1 ){
lcd.print(“Iris Close”);}
if ( bitRead(outArray[2],1) == 1 ){
lcd.print(“Iris Open”);}
if ( bitRead(outArray[2],0) == 1 ){
lcd.print(“Focus Near”);}
if ( bitRead(outArray[3],7) == 1 ){
lcd.print("Focus Far ");}
if ( bitRead(outArray[3],6) == 1 ){
lcd.print("Zoom Wide ");}
if ( bitRead(outArray[3],5) == 1 ){
lcd.print("Zoom Tele ");}

}

void ExtendedCommands()
{

lcd.setCursor(0,1);

if ( outArray[2] == 0 ){ // Only continu when Word 3 is 0

if ( outArray[3] == 0x03 ){ // SET PRESET
lcd.print("Set Preset: ");
lcd.print(outArray[5]-1);} // PRINT Preset. -1 to calculate right preset

if ( outArray[3] == 0x05 ){ // Clear Preset
lcd.print(“Clear Preset:”);
lcd.print(outArray[5]-1);} // PRINT Preset. -1 to calculate right preset

}}

Made some improvements.

Now I can control trough Pelco commands a Sony Visca camera!
This is only the Part for reading the Pelco commands.

/*
This program is used for an Arduino to receive and decode PELCO-D PTZ Commands

  • Read Pelco-D commands 2400/4800/9600 Baud on software serial port
  • Checksum calculation to prevent wrong decoding
  • First Pelco Byte check (FF) to prefent wrong serial data is being read
  • Transmit Visca commands on main serial port

Pelco-D Command:
outArray[0] = Byte 0 = Always FF
outArray[1] = Byte 1 = Camera Number
outArray[2] = Byte 2 = Control word 1
outArray[3] = Byte 3 = Control word 2
outArray[4] = Byte 4 = Data
outArray[5] = Byte 5 = Data
outArray[6] = Byte 6 = Checksum

*/

#include <LiquidCrystal.h> // LCD
#include <SoftwareSerial.h> // Software serial port

#define rxPin 2 // second software serial port RX on pin 2 and TX on pin 4
#define txPin 4

SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin); // activate software serial port

LiquidCrystal lcd(12, 11, 9, 8, 7, 6); // connect to 4 Bit LCD screen

byte outArray[7]; // Serial buffer
int stopcheck; // For checking when a STOP command is received (0)
int checksum; // For Calculating Checksum. Sum of the payload bytes (bytes 2 through 6) in the message
int ByteNumber; // Counter for reading the serial buffer

void setup(){

lcd.begin(16, 2); // set up the LCD’s number of columns and rows:
lcd.setCursor(0,0);
lcd.print(“Ready”);

Serial.begin(9600); // Visca Baudrate 9600
mySerial.begin(9600); // Pelco baud rate 9600 can be 1200,2400 or 4800

}

void loop()
{
if ( mySerial.available () > 0) {
outArray[ByteNumber ++] = mySerial.read();
if ( outArray[0] != 0xFF ) { ByteNumber = 0;}} // When Byte 0 isn’t 0xFF (Pelco 1st Byte) reset Bytenumber to 0 preventing the serial port being blocked.

if ( ByteNumber > 6){ // process it
ByteNumber = 0; // ready for next time

checksum = outArray[1] + outArray[2] + outArray[3] + outArray[4] + outArray[5] ; // calculate checksum

if ( checksum == outArray[6]) { // Procces data only when the checksum is valid

stopcheck = outArray[2] + outArray[3] + outArray[4] + outArray[5] ; // Calculate if STOP Command is received
if ( stopcheck == 0){ // When stopcheck is 0 a STOP command is received
StopActions();} // Stop all PTZ Actions

else{ printCommand();} // Print Pelco command on LCD

if ( bitRead(outArray[3],0) == 0 ){ // When BIT 0 = 0 command 2 than data is Normal command (PTZ)
Decoding();} // Try to decode the Pelco Command

if ( bitRead(outArray[3],0) == 1 ){ // When BIT 0 = 1 command 2 than data is an Extended command
ExtendedCommands();} // Try to decode the Extended Pelco Command
} // proces when checksum is Ok
} // end if buffer full
} // end of loop

1 Like

Hello,

I’m new to this forum and made my registration to solve exactly the problem, described in this thread. Unfortunately my Arduino and programming skills in general are - to put it mildly - poor… as this thread didn’t come to a good-working end I need some more help.
First I want to describe the initial situation:

I have a small chip-camera, that understands Pelco-D commands via RS-485 and I also have a cheap Pelco-D controller with a joystick. The camera has no motors for Pan & Tilt. For this purpose I want to use two 9g-servos with a cheap Pan&Tilt-Mount (about 7$) and an Arduino…

Sathoppers sketch is unfortunately not working, because he posted it incomplete. I tried to combine it with other sketches I found (see below). The links to my sources are in the sktetch’s first comment.

/*
 * http://forum.arduino.cc/index.php?topic=18119.0
 * http://forum.arduino.cc/index.php?topic=155693.0
 * 
 * YourDuino SoftwareSerialExample1
   - Connect to another Arduino running "YD_SoftwareSerialExampleRS485_1Remote"
   - Connect this unit Pins 10, 11, Gnd
   - Pin 3 used for RS485 direction control
   - To other unit Pins 11,10, Gnd  (Cross over)
   - Open Serial Monitor, type in top window. 
   - Should see same characters echoed back from remote Arduino

   Questions: terry@yourduino.com
 */

/*-----( Import needed libraries )-----*/
#include <Servo.h>
#include <SoftwareSerial.h>    // Software serial port

/*-----( Declare Constants and Pin Numbers )-----*/
#define SSerialRX        10  //Serial Receive pin
#define SSerialTX        11  //Serial Transmit pin
#define SSerialTxControl 3   //RS485 Direction control
#define RS485Transmit    HIGH   // not needed here, the servos attached to the arduino will not transmit any data to the Pelco-D controller
#define RS485Receive     LOW
#define Pin13LED         13

/*-----( Declare objects )-----*/
SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // RX, TX
Servo servo1;
Servo servo2;

/*-----( Declare Variables )-----*/
byte byteReceived[7];
int byteNumber = 0;
int byteSend;
int minPulse1     =  0;   // minimum servo position
int maxPulse1     =  180; // maximum servo position
int turnRate1     =  1;  // servo turn rate increment (larger value, faster rate)
int minPulse2     =  0;  // minimum servo position
int maxPulse2     =  180; // maximum servo position
int turnRate2     =  1;  // servo turn rate increment (larger value, faster rate)
/** The Arduino will calculate these values for you **/
int centerServo1;
int centerServo2;
int pulseWidth1;          // servo pulse width
int pulseWidth2;          // servo pulse width


void setup() {
  servo1.attach(6);
  servo2.attach(7);
  centerServo1 = maxPulse1 - ((maxPulse1 - minPulse1)/2);
  centerServo2 = maxPulse2 - ((maxPulse2 - minPulse2)/2);
  pulseWidth1 =  centerServo1;
  pulseWidth2 =  centerServo2;
  Serial.begin(2400);      // opens serial port, sets data rate to 2400 bps
  Serial.println("Arduino Serial Servo Control with Pelco D");
  // Serial.println("Press a, s, d, or w to move or spacebar to center"); // this sketch shall interpret commands from the incoming RS485Serial, not from the keyboard...
  Serial.println();
  pinMode(Pin13LED, OUTPUT);   
  pinMode(SSerialTxControl, OUTPUT);    
  digitalWrite(SSerialTxControl, RS485Receive);  // Init Transceiver   
  // Start the software serial port, to another device
  RS485Serial.begin(2400);   // set the data rate 
}//--(end setup )---


void loop() {
  // check for serial input
  // if (Serial.available() > 0) {
  if (RS485Serial.available() > 0)  //Look for incoming data from Pelco-D controller
   {
    digitalWrite(Pin13LED, HIGH);  // Show activity
    byteReceived[byteNumber ++] = RS485Serial.read();    // Read received byte
    //Serial.println(byteReceived[byteNumber], DEC);        // Show on Serial Monitor
    delay(10);
    digitalWrite(Pin13LED, LOW);  // Show activity
    if ( byteReceived[0] != 0xFF ) {byteNumber = 0;}}   // When Byte 0 isn't 0xFF (Pelco 1st Byte) reset byteNumber to 0 preventing the serial port being blocked.
    if ( byteNumber > 6 )                                 // process it
    {                 
      Serial.println(byteReceived[3], DEC);        // Show on Serial Monitor
      byteNumber = 0;                                   // ready for next time
      int data = byteReceived[4];       // read the incoming byte:
      switch(data){
          case 4 :  pulseWidth1 = pulseWidth1 - turnRate1;  break;
          case 2 :  pulseWidth1 = pulseWidth1 + turnRate1;  break ;    
          // case ' ' :  pulseWidth1 = pulseWidth2 = centerServo1;  break;  
          case 16 :  pulseWidth2 = pulseWidth2 - turnRate1;  break;
          case 8 :  pulseWidth2 = pulseWidth2 + turnRate1;  break ;
        }
       
        // stop servo pulse at min and max
        if (pulseWidth1 > maxPulse1) { pulseWidth1 = maxPulse1; }
        if (pulseWidth1 < minPulse1) { pulseWidth1 = minPulse1; }
        // stop servo pulse at min and max
        if (pulseWidth2 > maxPulse2) { pulseWidth2 = maxPulse2; }
        if (pulseWidth2 < minPulse2) { pulseWidth2 = minPulse2; }
        
        servo1.write(pulseWidth1);
        servo2.write(pulseWidth2);    
   /*
    // print pulseWidth back to the Serial Monitor (uncomment to debug)
    Serial.print("Servo 1: ");
    Serial.print(pulseWidth1);
    Serial.print(" Servo 2: ");
    Serial.print(pulseWidth2);
    Serial.println("degrees");
    */
  }
}

As discussed here, a Pelco-D command consists of 7 bytes, whereby the first byte is for synchronisation. It’s always FF (HEX). For my purpose only byte 4 (byteReceived[3]) is of interest, because that one describes the direction, the panning and tilting should go. Decimal the values are as follows:

4: left
2: right
8: up
16: down
12: up-left
10: up-right
20: down-left
18: down-right

To simplify it more, I only used 2, 4, 8, 16 (right, left, up & down) in the sketch.

When I open the serial-monitor, I can watch just that numbers. In the sketch it’s the line “Serial.println(byteReceived[3], DEC); // Show on Serial Monitor”.

So that work’s! Great!!
Unfortunately the servos don’t move as expected. They show a reaction to moving the small joystick of the Pelco-D controller, but that’s just jittering back and forth…

I guess it’s just sth. stupid simple…

I'm new to this forum

Welcome! two things I see in your post, first is don't power servos from the arduino, you need a separate power supply for them. Second, see #7 below on how to use code tags:

http://forum.arduino.cc/index.php/topic,148850.0.html

Hello zoomkat,

thank’s for your reply!

I fiddled around with the code a little and now it works significantly better, even if not entirely satisfactory.
What did I change? Firstly I use HEX in the switch statement. Before it was

case 4 :
case 2 :
case 16 :
case 8 :

and now it’s

case 0x00 : break;
case 0x02 : …
case 0x04 : …
case 0x10 : …
case 0x08 : …

After that change, the servos turned into the right direction, however with a lot of erratic movement.

Secondly I changed the baud rate from 2.400 to 38.400 and that made the movement much better, although not perfect. There are still some erratic movements - the servos seem to hang sometimes and then quickly catch up on the delay. Furthermore the servos are droning a little.
Perhaps I can solve that problems by using digital servos??? I will try.
I suppose, there are some timing problems during run time.
Powering the servos from a second power supply as zoomkat suggested made that even worse, indeed completely impractical. No idea why…

Here is the complete sketch:

/*
 * http://forum.arduino.cc/index.php?topic=18119.0
 * http://forum.arduino.cc/index.php?topic=155693.0
 * 
 * YourDuino SoftwareSerialExample1
   - Connect to another Arduino running "YD_SoftwareSerialExampleRS485_1Remote"
   - Connect this unit Pins 10, 11, Gnd
   - Pin 3 used for RS485 direction control
   - To other unit Pins 11,10, Gnd  (Cross over)
   - Open Serial Monitor, type in top window. 
   - Should see same characters echoed back from remote Arduino

   Questions: terry@yourduino.com
 */

/*-----( Import needed libraries )-----*/
#include <Servo.h>
#include <SoftwareSerial.h>    // Software serial port

/*-----( Declare Constants and Pin Numbers )-----*/
#define SSerialRX        10  //Serial Receive pin
#define SSerialTX        11  //Serial Transmit pin
#define SSerialTxControl 3   //RS485 Direction control
#define RS485Transmit    HIGH   // not needed here, the servos attached to the arduino will not transmit any data to the Pelco-D controller
#define RS485Receive     LOW
#define Pin13LED         13

/*-----( Declare objects )-----*/
SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // RX, TX
Servo servo1;
Servo servo2;

/*-----( Declare Variables )-----*/
byte byteReceived[7];
int byteNumber = 0;
int byteSend;
int minPulse1     =  0;   // minimum servo position
int maxPulse1     =  180; // maximum servo position
int turnRate1     =  4;  // servo turn rate increment (larger value, faster rate)
int minPulse2     =  0;  // minimum servo position
int maxPulse2     =  180; // maximum servo position
int turnRate2     =  4;  // servo turn rate increment (larger value, faster rate)
/** The Arduino will calculate these values for you **/
int centerServo1;
int centerServo2;
int pulseWidth1;          // servo pulse width
int pulseWidth2;          // servo pulse width


void setup() {
  servo1.attach(6);
  servo2.attach(7);
  centerServo1 = maxPulse1 - ((maxPulse1 - minPulse1)/2);
  centerServo2 = maxPulse2 - ((maxPulse2 - minPulse2)/2);
  pulseWidth1 =  centerServo1;
  pulseWidth2 =  centerServo2;
  Serial.begin(38400);      // opens serial port, sets data rate to 38400 bps
  Serial.println("Arduino Serial Servo Control with Pelco D");
  Serial.println();
  pinMode(Pin13LED, OUTPUT);   
  pinMode(SSerialTxControl, OUTPUT);    
  digitalWrite(SSerialTxControl, RS485Receive);  // Init Transceiver   
  // Start the software serial port, to another device
  RS485Serial.begin(38400);   // set the data rate 
}//--(end setup )---


void loop() {
  if (RS485Serial.available() > 0)  //Look for incoming serial data from Pelco-D controller
   {
    // digitalWrite(Pin13LED, HIGH);  // Show activity
    byteReceived[byteNumber ++] = RS485Serial.read();    // Read received byte
    // Serial.println(byteReceived[byteNumber], DEC);        // Show on Serial Monitor
    // delay(10);
    // digitalWrite(Pin13LED, LOW);  // Show activity
    if ( byteReceived[0] != 0xFF ) {byteNumber = 0;}   // When Byte 0 isn't 0xFF (Pelco 1st Byte) reset byteNumber to 0 preventing the serial port being blocked.
   }
    if ( byteNumber > 6 )                                 // process it
    {                 
      // Serial.println(byteReceived[3], DEC);        // Show on Serial Monitor
      byteNumber = 0;                                   // ready for next time
      byte data = byteReceived[3];       // read the incoming byte:
      Serial.println(data, HEX);        // Show on Serial Monitor
      switch(data)
        {
          case 0x00 : break;
          case 0x02 :  pulseWidth1 = pulseWidth1 - turnRate1; servo1.write(pulseWidth1); servo2.write(pulseWidth2); break;
          case 0x04 :  pulseWidth1 = pulseWidth1 + turnRate1; servo1.write(pulseWidth1); servo2.write(pulseWidth2); break;    
          case 0x10 :  pulseWidth2 = pulseWidth2 - turnRate1; servo1.write(pulseWidth1); servo2.write(pulseWidth2); break;
          case 0x08 :  pulseWidth2 = pulseWidth2 + turnRate1; servo1.write(pulseWidth1); servo2.write(pulseWidth2); break;
        }
        // stop servo pulse at min and max
        if (pulseWidth1 > maxPulse1) { pulseWidth1 = maxPulse1; }
        if (pulseWidth1 < minPulse1) { pulseWidth1 = minPulse1; }
        // stop servo pulse at min and max
        if (pulseWidth2 > maxPulse2) { pulseWidth2 = maxPulse2; }
        if (pulseWidth2 < minPulse2) { pulseWidth2 = minPulse2; }
    /*
    // print pulseWidth back to the Serial Monitor (uncomment to debug)
    Serial.print("Servo 1: ");
    Serial.print(pulseWidth1);
    Serial.print(" Servo 2: ");
    Serial.print(pulseWidth2);
    Serial.println("degrees");
    */
   }
}

Powering the servos from a second power supply as zoomkat suggested made that even worse, indeed completely impractical. No idea why…

The arduino and servo grounds need to be connected together like in the attached pix.

servo-wire.jpg

Hi zoomkat,

thank's again - you were faster :wink:

Just a few minutes ago I found CrossRoads answer in this thread, tried that and now it works with 5V external power. In the same thread it's suggested to use a 100nF capacitor... that could help to stop the droning, right?!

Here is an actual schematic:

|500x265

AN update regarding the erratic movements: I closely monitored the servos, while sending data from the pelco controler, that should cause no reaction, whilst holding the controler's joystick in the down-left position (0x20, not implemented in the code). Periodically every 3-4 seconds the servos make a small movement back and forth (about 2 angular degrees, independent from the turnRate adjusted in the sketch).

Any idea??

regards, Martin

Hello,

finally it works!!

The reason for the jittering servos was, that the softwareserial.h library can’t coexist with the servo.h library, due to timing problems (that’s what I found in another forum). For my special adaptation the softwareserial.h is not necessary, why I changed the sketch…

Here it is:

/*
 * http://forum.arduino.cc/index.php?topic=18119.0
 * http://forum.arduino.cc/index.php?topic=155693.0
 */


/*-----( Import needed libraries )-----*/
#include <Servo.h>

/*-----( Declare Constants and Pin Numbers )-----*/
#define RS485lTxControl 3   //RS485 Direction control 
#define RS485Transmit    HIGH   // not needed here, the servos attached to the arduino will not transmit any data to the Pelco-D controller  
#define RS485Receive     LOW
#define Pin13LED         13

/*-----( Declare objects )-----*/
Servo servoPAN;
Servo servoTILT;

/*-----( Declare Variables )-----*/
byte byteReceived[7];
int byteNumber = 0;
int byteSend;
int minPulse1     =  0;   // minimum servo position
int maxPulse1     =  180; // maximum servo position
int turnRate1     =  3;  // servo turn rate increment (larger value, faster rate)
int minPulse2     =  0;  // minimum servo position
int maxPulse2     =  180; // maximum servo position
int turnRate2     =  3;  // servo turn rate increment (larger value, faster rate)
/** The Arduino will calculate these values for you **/
int centerservoPAN;
int centerservoTILT;
int pulseWidth1;          // servo pulse width
int pulseWidth2;          // servo pulse width


void setup() {
  servoPAN.attach(6);
  servoTILT.attach(7);
  centerservoPAN = maxPulse1 - ((maxPulse1 - minPulse1)/2);
  centerservoTILT = maxPulse2 - ((maxPulse2 - minPulse2)/2);
  pulseWidth1 =  centerservoPAN;
  pulseWidth2 =  centerservoTILT;
  Serial.begin(38400);      // opens serial port, sets data rate to 38400 bps
  Serial.println("Arduino Serial Servo Control with Pelco D");
  Serial.println();
  pinMode(Pin13LED, OUTPUT);   
  pinMode(RS485lTxControl, OUTPUT);    
  digitalWrite(RS485lTxControl, RS485Receive);  // Init Transceiver   
}//--(end setup )---


void loop() {
  if (Serial.available() > 0)  //Look for incoming serial data from Pelco-D controller
   {
    digitalWrite(Pin13LED, HIGH);  // Show activity
    byteReceived[byteNumber ++] = Serial.read();    // Read received byte
    // Serial.println(byteReceived[byteNumber], DEC);        // Show on Serial Monitor
    // delay(10);
    digitalWrite(Pin13LED, LOW);  // Show activity
    if ( byteReceived[0] != 0xFF ) {byteNumber = 0;}   // When Byte 0 isn't 0xFF (Pelco 1st Byte) reset byteNumber to 0 preventing the serial port being blocked.
   }
    if ( byteNumber > 6 )                                 // process it
    {                 
      byteNumber = 0;                                 // ready for next time
      byte data = byteReceived[3];       // read the incoming byte:
      Serial.println(data, HEX);        // Show on Serial Monitor
      switch(data)
        {
          case 0x00 :  break;
          case 0x02 :  pulseWidth1 = pulseWidth1 - turnRate1; servoPAN.write(pulseWidth1); break; // right
          case 0x04 :  pulseWidth1 = pulseWidth1 + turnRate1; servoPAN.write(pulseWidth1); break; // left   
          case 0x10 :  pulseWidth2 = pulseWidth2 - turnRate1; servoTILT.write(pulseWidth2); break; // down
          case 0x08 :  pulseWidth2 = pulseWidth2 + turnRate1; servoTILT.write(pulseWidth2); break; // up
          case 0x0C :  pulseWidth1 = pulseWidth1 + turnRate1; servoPAN.write(pulseWidth1); pulseWidth2 = pulseWidth2 - turnRate1; servoTILT.write(pulseWidth2); break; // left-up
          case 0x0A :  pulseWidth1 = pulseWidth1 - turnRate1; servoPAN.write(pulseWidth1); pulseWidth2 = pulseWidth2 - turnRate1; servoTILT.write(pulseWidth2); break; // right-up
          case 0x14 :  pulseWidth1 = pulseWidth1 + turnRate1; servoPAN.write(pulseWidth1); pulseWidth2 = pulseWidth2 + turnRate1; servoTILT.write(pulseWidth2); break; // left-down
          case 0x12 :  pulseWidth1 = pulseWidth1 - turnRate1; servoPAN.write(pulseWidth1); pulseWidth2 = pulseWidth2 + turnRate1; servoTILT.write(pulseWidth2); break; // right-down
        }
        
        // stop servo pulse at min and max
        if (pulseWidth1 > maxPulse1) { pulseWidth1 = maxPulse1; }
        if (pulseWidth1 < minPulse1) { pulseWidth1 = minPulse1; }
        // stop servo pulse at min and max
        if (pulseWidth2 > maxPulse2) { pulseWidth2 = maxPulse2; }
        if (pulseWidth2 < minPulse2) { pulseWidth2 = minPulse2; }
       
    // print pulseWidth back to the Serial Monitor (uncomment to debug)
    Serial.print("Servo 1: ");
    Serial.print(pulseWidth1);
    Serial.print(" Servo 2: ");
    Serial.print(pulseWidth2);
    Serial.println("degrees");
   }
}

Martin

@HansImGlueck I am curious about your pan tilt system, how snappy is the Pelco controler to motors, is it some noticiable lag? Also i never used such controler, does it allow variable speed?

Thanks

Daniel

sathopper: Made some improvements.

Now I can control trough Pelco commands a Sony Visca camera! This is only the Part for reading the Pelco commands.

That is exactly what I would like to do!! I have a DVR that does Pelco-D PTZ over RS-485, and a Sony EVI-D30 PTZ VISCA camera that I want to control with the DVR.

I am a total newbie with Arduino, and lousy at programming, but good with hardware and soldering etc... so this will be an excellent first project for me to do with Arduino.

I would be grateful if you could share your hardware selection and guide me to the point of being able to install the code to get this up and going.

Hi First time to post so not sure how this will turn out.
I ran the latest code with the removed libraries and found that nothing worked, No RS485 commands were being read by the UNO board. I was still using the picture posted earlier showing the wiring of the servos, ardrino etc. Any ho after much checking of code and i found that the original pin IN assignment on 9 and 10 had to be moved to pins 0 and 1 the default TX RX for the board. Result it works a treat and full control is restored. only took a day… LOL…

Merhaba HansImGlueck en son paylaştığın kodları çalıştırdım. Ancak Serial Monütörde sadece 0000000 görüyorum. Hangi yönlendirmeyi yaparsam yapayım ekrana sadece 0000000 yazıyor. Hex formatında görüntü alamyorum. Yardımcı olursan sevinirim.