ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
1

Arduino serial communcation via Serial1/2/3 or SoftwareSerial

asked 2015-02-24 07:44:13 -0500

FrankB gravatar image

updated 2015-03-03 02:40:27 -0500

Hello,

I want to add the Arduino Mega 2560 to a chain of Robotis Dynamixel motors (MX-106R, MX-64R and MX-28R). The Arduino will be connected through a RS-485 breakout board and Serial1 (or 2, or 3) or SoftwareSerial ( http://arduino.cc/en/Reference/softwa... ). The chain is controlled from the PC (Ubuntu 12.04 LTS, ROS Hydro) via a FTDI USB-RS485 converter. I can perfectly find the chain of Dynamixel motors, but setting up the Arduino to act as a actuator/sensor proves harder than thought.

What have I tried:

  • verified communication over RS485; 2 Putty terminals, one connected to Serial COM of Arduino and one connected to USB-RS485 COM, no problems there.
  • Tutorial of rosserial, all works fine, but only over Serial port of Arduino and not Serial1/2/3 or SoftwareSerial.

So, what would be the simplest method of setting up a node with an Arduino over serial communication other then Serial0? How to publish to Serial1/2/3 or SoftwareSerial?

Update: I have some communication. But i get publish before configure. So timing is wrong. I need RTS for RS485 to work. I define a pin and set i high when nh.initnode or nh.publish is called. I set to low after delay, but trial and error. Can someone give me timing diagram of ROS init and publish?

Update(2): I have successfully added RTS functionality by editing the new hardware class:

class NewHardware : public ArduinoHardware
{
  public:
  NewHardware():ArduinoHardware(&Serial1, 57600){};

  void init(){
    pinMode(RTS, OUTPUT);
    digitalWrite(RTS, LOW);
    iostream->begin(baud_);
  }

  int read(){
    return iostream->read();
  };

  void write(uint8_t* data, int length){
    for(int i=0; i<length; i++){
      digitalWrite(RTS, HIGH);    
      iostream->write(data[i]);
    }
    digitalWrite(RTS, LOW);
  }
};

ros::NodeHandle_<NewHardware>  nh;

now, every time a write action is initiated the RTS pin is set to HIGH, and the publishing of message works (better). But while writing the RTS pin will go LOW, as if the write action is interrupted. This will cause a sync error and the communication is far from reliable... When I add a lot of delay before releasing the RTS I can get some communication working, but the delay is dependent on the message length, and as the message length is variable, the delay will sometimes not be sufficient, causing sync errors again...

Below a picture of my scope, with top waveform TX and bottom RX of Arduino. RX should be low until TX is finished...

image description

Update(3): Solved! I fixed it by checking the flag "TXCn: USART Transmit Complete". I kept the RTS HIGH for as long as the transmit complete flag was not risen. Here is the code:

void write(uint8_t* data, int length){
    digitalWrite(RTS, HIGH);
    for(int i=0; i<length; i++){
      iostream->write(data[i]);
    }
    while(!(UCSR1A & (1<<TXC1)));
    digitalWrite(RTS, LOW);
  }
edit retag flag offensive close merge delete

Comments

Hi.

I'm doing something quite similar to what you achieved, and your post solves most of my doubts. However, the constructor for ArduinoHardware only accepts HardwareSerial instances. How could I modify the code so I can pass it SoftwareSerial instances?

toyoxx gravatar image toyoxx  ( 2016-11-01 06:29:24 -0500 )edit

2 Answers

Sort by ยป oldest newest most voted
0

answered 2016-11-01 07:00:06 -0500

toyoxx gravatar image

I got it working! I just went to ArduinoHardware and added an ifelse clause so that when a flag was defined, it would include and select SoftwareSerial as a class. Additionally I had to comment the line while(!(UCSR1A & (1<<txc1))); because="" ucsr1a="" is="" only="" defined="" on="" the="" arduino="" mega.="" it="" works!<="" p="">

edit flag offensive delete link more
0

answered 2017-04-29 15:50:44 -0500

Jefecito gravatar image

Hello Frank,

I am trying to use Rosserial over RS485 based on your solution of Update(3) but on the Python Ros client side I always get messages complaining about wrong checksum. I think this is because of incomplete sent messages because of uncomplete TX buffer reading. I just tried as well with an Arduino nano board only adjusting the name of the respective registers, the same occurs.

I am using ROS Indigo.

Do you have successful used this solution for RS485 on Rosserial?

Thank you.

edit flag offensive delete link more

Comments

Hi Jefecito,

I had the same problem and added the RTS flag. Did you do the same? See code Update(3) and add this to ArduinoHardware.h in http://docs.ros.org/kinetic/api/rosse...

FrankB gravatar image FrankB  ( 2017-05-02 05:09:11 -0500 )edit

Hello FrankB,

Actually I put this snippet on the inherited NewHardware class overwriting the method write(), like you did on Update 2. I don't see difference between this and edit the library file. It Worked with limitations. Please see http://answers.ros.org/question/26116...

Jefecito gravatar image Jefecito  ( 2017-05-05 15:07:16 -0500 )edit

Question Tools

2 followers

Stats

Asked: 2015-02-24 07:44:13 -0500

Seen: 2,422 times

Last updated: Mar 03 '15