3

I am reading the value of six potentiometers with a TX Arduino and receiving that data and applying those numbers to a motor using serial. It is working fine through TTL but I am going to need to do this over a 60 ft tether.

I have done a little research and see that I could use RS 232 but that the maximum you should go with that is 50 ft, which will not work if I'm not mistaken. I have also seen RS 485 which will give us 4000 ft, which is overkill but will work. However, that only offers one-way communication, if I'm not mistaken. What I'm wondering is which protocol should I convert it to, and how I would have to adjust my RX and TX code.

TX code:

/*
  Transmitting Code
  Reads potentiometers and sends them through serial
*/

int data [10];     // to send bytes
int start [2];
int pot0Pin = A0;  // analog pin used to connect the potentiometer
int pot0;          // variable to read the pot0ue from the analog pin
int pot1Pin = A1;
int pot1;
int pot2Pin = A2;
int pot2;
unsigned char checksum0;
unsigned char checksum1;
unsigned char checksum2;


void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
  pinMode(19, INPUT);
  pinMode(18, OUTPUT);
}


void loop() {

// READ THE POTENTIOMETERS:

  pot0 = analogRead(pot0Pin);   // reads the value of the potentiometer (pot0ue between 0 and 1023)
  data[0] = pot0 & 0xFF; //least significant 8 bit byte
  data[1] = (pot0 >> 8); //most significant 2 bits

  pot1 = analogRead(pot1Pin);
  data[2] = pot1 & 0xFF;
  data[3] = (pot1 >> 8);

  pot2 = analogRead(pot2Pin);
  data[4] = pot2 & 0xFF;
  data[5] = (pot2 >> 8);

// CREATE CHECKSUMS:

  checksum0 = ~(data[0]+data[1]) + 1;

  checksum1 = ~(data[2]+data[3]) + 1;

  checksum2 = ~(data[2]+data[3]) + 1;

// WRITE VALUES AND CHECKSUMS TO SERIAL:

  Serial1.write(data[0]); 
  Serial1.write(data[1]); 

  Serial1.write(data[2]);
  Serial1.write(data[3]); //bytes sent

  Serial1.write(data[4]);
  Serial1.write(data[5]);

  Serial1.write(checksum0);

  Serial1.write(checksum1);

  Serial1.write(checksum2); // send the checksum

 delay(10);        // delay in between reads for stability

}

RX code:

/*
  Receving Code
  Reads bytes from Transmitting Code and put thems back together
  Applies the read bytes to our motor control board
*/
unsigned char val[10];    // variable to read the value from the analog pin
int motorVal;
int coolVal;      // 0-1024 received from serial
int coolVal1;
int coolVal2;
unsigned char checksum1;
unsigned char checksum2;
unsigned char checksum3;
unsigned char checkit1;
unsigned char checkit2;
unsigned char checkit3;
int directionPin = 8;
int PWM_out_pin = 9; // works on pins 2 - 13 and 44 - 46

void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
//  Serial1.begin(9600); 
  pinMode(10, INPUT);
  pinMode(18, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
}

void loop() {

  if (Serial1.available()>5) {  

    val[0]=Serial1.read();         // least significant 8 bits
    val[1]=Serial1.read();         // most significant 2 bits   

    val[2]=Serial1.read();
    val[3]=Serial1.read();

    val[4]=Serial1.read();
    val[5]=Serial1.read(); 

    checksum1=Serial1.read();
    checksum2=Serial1.read();
    checksum3=Serial1.read();// get the checksum last

    checkit1 = val[0]+val[1]+checksum1;
    checkit2 = val[2]+val[3]+checksum2;
    checkit3 = val[4]+val[5]+checksum3; 

  if (checkit1==0);  {
    coolVal = val[1]<<8 | val[0]; }

  if (checkit2==0);  {
    coolVal1 = val[3]<<8 | val[2];}

  if (checkit3==0);  {
    coolVal2 = val[5]<<8 | val[4];
    }

    Serial.print(coolVal);
    Serial.print(" ");
    Serial.print(coolVal1);
    Serial.print(" ");
    Serial.println(coolVal2);
    delay(10);


  }


// FOR MOTOR 1 (more will be added once we achieve successful serial):   
  if (coolVal > 550) {
    digitalWrite (directionPin, HIGH);
    motorVal = map(coolVal, 550, 1023, 0, 1023);
    analogWrite (PWM_out_pin, motorVal / 4); }

  if ((coolVal < 550) && (coolVal > 500)) {
    digitalWrite (directionPin, HIGH);
    analogWrite (PWM_out_pin, 0); }

  if (coolVal < 500) {
    digitalWrite (directionPin, LOW);
    motorVal = map(coolVal, 0, 500, 1023, 0);
    analogWrite (PWM_out_pin, motorVal / 4); }


}
2

You're right that 60' exceeds the spec for RS-232. That said, distance specs are often quite conservative (as they should be, the spec is a promise that it will work and needs to account for marginal components and an unfavorable environment). I think the 50' limit for RS-232 was more observed in the breach than in practice. So for starters I'd be inclined to see if you could get 60' using RS-232 – I'd be kind of surprised if it didn't work.

Since reliability is important you're doing the right thing by checksumming and checking the data. If the checksum you use is good, it will go a long ways towards letting you detect corrupted data. Then, even if you are using a less than perfect underlying medium (e.g., RS-232 over a long distance), you can improve reliability by ignoring any corrupted values you receive. What that won't protect you from is a major data loss – for example a cut in your cable or a very noisy environment where most of your messages are getting lost. To defend against that you need a mechanism that also acknowledges your transmissions.

So, at this point you've got a choice – you could keep thinking of what might go wrong and designing solutions, or you could see if you could build on existing work. One thing you might want to look at is using something like the SLIP (Serial Line IP) protocol which was developed to run TCP/IP over a dialup modem back in the dark ages of the Internet. I found, but haven't tried out, a couple of implementations for the Arduino:

RS-485 is (can be) bi-directional, you just need a transmitter and receiver at each end. Another approach would be to use a 4-20 mA current loop.

You might also want to look into making the controller wireless. That would get you some added convenience (at the expense of a tether to help you find where you put the box) as well as a reliable two-way communication protocol.

  • I would say the same but this has to be very reliable. It seems that the farther it'll go the less reliable it'll get. What do you think? – mpgiii Jan 16 '16 at 17:00
  • Why do you need it to be very reliable? You are already adding checksums, and sending the data every 10ms. It seems to me like some loss wouldn't be that much of a problem. Though extended durations of loss would be. – Gerben Jan 16 '16 at 17:07
  • So dlu, do you think that if using the checksums RS-232 makes the most sense? We want our tether as light as possible so it would be helpful to have just the three wires from RS-232 vs. the two twisted pair on RS-485, as we plan on having the RX code also transmit some information back. – mpgiii Jan 16 '16 at 18:02
  • Also, @dlu, am I not using the checksum correctly in my portion of code that states: if (checkit1==0); { coolVal = val[1]<<8 | val[0]; } – mpgiii Jan 16 '16 at 18:10
  • 1
    9600 baud isn't very demanding by today's standards. I'd try going the 60' with RS-232. Maybe you'd need to use a shielded cable if your environment is noisy. Try sending some readable strings that you can quickly check by just reading, such as "The quick 9600 baud data string leaps over the fifty foot barrier." or some such. :) You'll know quickly whether your data got walked on or your checksum calculations are failing. – JRobert Jan 16 '16 at 18:44
0

You can do two-way communication with RS485. I have a page about RS485 with schematics and code, including calculating checksums.

You don't have to use twisted cable, that would just add to the reliability. You would need 4 cores (power, ground, A and /B) however if the other end was self-powered (ie. a battery) then you could skip that. There has been a bit of debate about whether the ground wire is needed (assuming you don't send power) but it is probably sensible to include it.

The page I linked above also describes a rolling master system, where each node has a chance to "talk" to other nodes. This demonstrates that you can send and receive on the same pair of wires.

In my test of the rolling master (using UTP cable) I had it working over 40 meters (ignore the figure on the schematic). So your 50 feet range should be easily achievable.

RS485 connection

  • Thanks, Nick. The reason we're hesitant is that we want to limit the amount of wires in the tether, because we are under a weight limitation and would like to have as much as backup weight allocation as possible. Another rule is not being able to have a power source on the other end. – mpgiii Jan 21 '16 at 3:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.