EasyTransfer Arduino Library

Posted in Arduino Libraries by Bill
30 May 2011
EasyTransfer Arduino Library

The purpose of this library is to make it easy for the everyday Arduino user working on projects with multiple Arduinos communicating with each other and sharing data. I had many people ask me for the code I used in my PS2X library example that sent PS2 Controller values wirelessly to my SAGAR robot. It got to be tiresome answering the questions and I had an idea to write a library to help the inexperienced with micro controller communications. This is a easy to use and no frills way to send data between two Arduinos.

In most of my own projects I define and write my own NMEA standard communication protocols. This makes communications human readable and easy to debug, but proves wasteful with bandwidth and processing power so it’s not right for every application. Binary communications is much more efficient and versatile, but requires careful handling. This library abstracts the finer points of packetized serial communication away from the user so it easy to use and understand.

To use the library, simple define all the data types you want to share inside a data structure. This keeps all the data stored together in memory.

struct SEND_DATA_STRUCTURE{
  //put your variable definitions here for the data you want to send
  //THIS MUST BE EXACTLY THE SAME ON THE OTHER ARDUINO
  int blinks;
  int pause;
};

When requested, the library will send all the binary data in the structure to another Arduino via serial with a checksum to avoid transfer errors.

void loop(){
  //this is how you access the variables. [name of the group].[variable name]
  mydata.blinks = random(5);
  mydata.pause = random(5);
  //send the data
  ET.sendData();
  delay(10000);
}

The receiving Arduino will verify the checksum, and copy the new data onto a identical structure in it’s memory.

void loop(){
  //check and see if a data packet has come in. 
  if(ET.receiveData()){
    //this is how you access the variables. [name of the group].[variable name]
    //since we have data, we will blink it out. 
    for(int i = mydata.blinks; i>0; i--){
      digitalWrite(13, HIGH);
      delay(mydata.pause * 100);
      digitalWrite(13, LOW);
      delay(mydata.pause * 100);
    }
  }

  delay(2500);
}

It’s important to make sure the structure is the same on both Arduinos for this to work. Now sharing data between Arduinos is easy without having to define and program your own communications protocol and have to worry about syncing or transmit errors. EasyTransfer will do that for you.

Using Structures to hold the data allows for versatile communications by allowing any type and number of data points to be shared, as long as the whole structure is under 255 bytes. You could define int’s, arrays, longs, etc inside the structure and share the data. It’s also possible to create two way communications by defining two sets of structs on each end and creating two objects using the library. I will have an example of that up shortly.

You can download the library and example below. The example requires two Arduino boards to be connected to each other via their Uarts. One will create two random numbers and send the data to the other that will flash out a sequence of flashes based on those numbers. The first one will also flash out the same sequence.

Now it’s easier to pick which Serial port to use; Serial, Serial1, etc. AND support for the NewSoftSerial library for creating software serial ports on any pin. EasyTransfer is for hardware serial, SoftEasyTransfer is for software; each has there own set of examples. There’s also an example for two way communications using the library.

Source Code available on GitHub project pages.

 

Or Direct Download

 

UPDATE

Thanks to Kumy, there’s now an I2C version of EasyTransfer. There’s also an experimental VirtualWire version for use with those cheap low frequency radios. All are in the single download zip file above.

 

To install the Library, open the zip file and transfer the EasyTransfer folder into your Arduino ‘libraries’ folder. Then follow the examples to add the code to your project. If you have any problems or questions, let me know in the Support Forum.

Need Help?

Please use the Support Forum to ask for help. Don’t use the comments below.

 

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.

Share

Trackbacks / Pingbacks

  1. Library makes Arduino to Arduino serial communications dead simple - Hack a Day
  2. Arduino Blog » Blog Archive » Easytransfer Library Makes Arduino2Arduino Communication Easy
  3. EasyTransfer Arduino Library « The Mind of Bill Porter | SpikenzieLabs Blog
  4. Easytransfer Library Makes Arduino2Arduino Communication Easy | dev.SquareCows.com
  1. 443 Comments.

    • […] make things easy for the common user, he wrote a library called EasyTransfer which abstracts packetized serial communications between two Arduino boards. The process is pretty […]

      • BillNo Gravatar says:

        Thanks? I guess that is a complement?

        • Anthony LinNo Gravatar says:

          Hey Bill, there seems to a problem with this library and the PS2x.library. I do not think they are compatible with each other since I can only include one of them before it stops working.

          • BillNo Gravatar says:

            They shouldn’t interfere but I haven’t tried it. What error do you get?

            • Anthony LinNo Gravatar says:

              So if I call the EasyTransfer library first and then the PS2x lib, It will give me an arrow that PS2X does not name a type. While if I call the PS2X.lib first and then the Easy Transfer, i get the EasyTransfer does not name a type.

            • BillNo Gravatar says:

              Anthony, zip up your sketch and email it to me at the address on the bottom of the page and I will take a look when I get off work today.

            • BillNo Gravatar says:

              All fixed Anthony, give it a try now.

    • […] Porter] took care of this problem by creating a library called EasyTransfer In most of my own projects I define and write my own NMEA standard communication protocols. This […]

    • […] EasyTransfer Arduino Library « The Mind of Bill Porter. This entry was posted in Arduino, Electronics, Interesting and tagged ardunio communication. Bookmark the permalink. ← Geared Motor Emporium […]

    • RodrigoNo Gravatar says:

      God joob! 😉

    • […] Porter] took care of this problem by creating a library called EasyTransfer In most of my own projects I define and write my own NMEA standard communication protocols. This […]

    • CedricNo Gravatar says:

      Hi Bill, thanks for this library! But I am currently still having problems with serial communication =( I have got two ultrasonic sensors which I connected to the Arduino and I want to send those 2 measurements through xBee to my Linux and get those readings as 2 separate integers or floats. But I always get weird readings. (i.e. 2 readings combine together, incorrect readings) Do you know what can be the problem? =(

      I have been stuck for about 2 weeks now! =(

      • BillNo Gravatar says:

        Cedric, are you porting my code to your linux enviroment?

        The linux PC and your Arduino store numbers in memory differently, so if you try to do raw digital communications between them without correcting their differences, you will get random results.

        For your situation, it would be easier to do ASCII text communication, and have the linux computer parse the data.

    • KenNo Gravatar says:

      Is there a way to modify this approach so that one “master” Arduino can talk to say, 6 others, selectively (ie. not all at once but in a sequence)? I have a situation where I am using individual Arduinos to run PID temperature control loops and I want to send the set points from from a master Arduino

      • BillNo Gravatar says:

        Ken,

        I’d suggest having the “Master” UART TX line connected to all the slaves RX lines. In the data structure, have the first declaried variable be something like ‘ID’. Program the slaves to only change their setpoints if thier ID number matches the one that was transmitted.

        Every slave will ‘hear’ every message, but only the one that matches ‘ID’ will act on the data.

        If you want to have data go the other way, that’s a different problem. Though it could be solved with clever code.

        • KenNo Gravatar says:

          Thanks Bill. So “electrically” no problem daisy-chaining all the RXs back to the master TX? Total distance is 6 Ardunos distributed evenly over @ 40 ft., master at the end.

          • BillNo Gravatar says:

            Electrically no problem other then the length of wire. Quick googling shows people are ok up to 100 feet. You would have to stick to low baud rates.

    • sebastianNo Gravatar says:

      can i use a different serial, like the softwareserial or the newsotfwareserial libraries instead of use the real serial port. and how to do that??

      • BillNo Gravatar says:

        You can, but not easily. When I get time, I plan to add features including easy integration with software serial libraries, but right now you would have to edit the .ccp and .h files.

        • sebastianNo Gravatar says:

          but how can i do it? i really need it, i was looking the .cpp and the .h files, but didn´t get a clue of how to do it.

          • BillNo Gravatar says:

            I can’t guarantee this will work but you can try it.

            in the .h file, you should see this line:

            #define SERIALPORT Serial

            try changing ‘Serial’ to the name of the software serial port you are trying to use. So if you setup your software serial port like this:

            NewSoftSerial gps(4,3);

            change the line in the EasyTransfer.h file to look like this:

            #define SERIALPORT gps

            Make sure you do all the calls and setups of the software serial port before the EasyTransfer setups.

            • sebastianNo Gravatar says:

              ok, thank you so much, i´ll try it, i´ll let you know later, again thank so much.

            • BillNo Gravatar says:

              Did it work?

            • sebastianNo Gravatar says:

              No, it didn’t work,but i already know what to do, you have to put the .cpp and the .h files of the newsoftwareserial next to the easytransfer files, then you have to moify the .cpp and the .h files like this:

              .H:

              #include “EasyTransfer.h”

              #include
              NewSoftSerial arduinoGPRS(9,10);
              #define SERIALPORT arduinoGPRS

              void EasyTransfer::serialportd(){
              arduinoGPRS.begin(9600);
              }
              //here continue everyhing as it was.

              .CPP:

              #ifndef EasyTransfer_h
              #define EasyTransfer_h
              //Change the Serial port here. Choices Serial, Serial1, Serial2, Serial3.

              //i remove the serial from here.

              //make it a little prettier on the front end.
              #define details(name) (byte*)&name,sizeof(name)

              //Not neccessary, but just in case.
              #include “WProgram.h”
              #include
              #include
              #include
              #include

              class EasyTransfer {
              public:
              void init(uint8_t *, uint8_t);
              void sendData();
              void serialportd(); //this method is for set //the serail’s boud rate.
              boolean receiveData();

              private:
              uint8_t * address; //address of struct
              uint8_t size; //size of struct
              uint8_t rx_len; //RX packet length according to the packet
              uint8_t rx_array[255]; //RX packet parsing buffer
              uint8_t rx_array_inx; //index for RX parsing buffer
              uint8_t calc_CS; //calculated Chacksum
              };
              #endif

              all the methods of the newsoftwareserail must be public. it´s a little sloppy, if you can improve it let me know.

            • sebastianNo Gravatar says:

              modified files are the easytransfer .h and .cpp

          • BillNo Gravatar says:

            sebastian,

            see the update above. New version supports newsoftserial.

    • CedricNo Gravatar says:

      Hi Bill,

      I was trying to figure it out for the past few days and I think I finally know what you mean by ASCII test communication! =)

      In other words, I should send my numbers (int16 for Arduino’s case) into a byte(char) array first before sending it to the other side and get the data by reading the byte(char) array?

    • BUzzNo Gravatar says:

      Hi Bill,

      I was reading through the .h and .cpp files, and I think I discovered a bug in EasyTransfer. It’ll only affect users that get occassional serial corruption and have the requirement for guaranteed delivery…but I thought it worth mentioning it.

      Problem:
      In the implementation of receiveData() you are discarding all serial data until you see the header value of 0x06, but it occurred to me that if there is serial corruption of that exact byte, then it causes the entire next “packet” to be ignored/discarded.
      So, given a packet size of max 255 bytes, that means a 1-in-255 chance of a corrupted byte causing a packet of otherwise valid data to be “lost” without the TX end, or the RX end ever knowing.

      My Proposed solution:
      Adding a sequence number to each header (it would then become: 0x06, 0x85, seq, size, data ) would allow the RX end to at least become aware of the fact that has lost a packet or packets.
      eg:
      Host sends packet with seq 123 … client gets it and remembers ‘last recieved seq = 123’

      Host send packet with seq 124 … corruption causes client to ignore it.

      Host sends packet with seq 125 … client get it and compares with ‘last recieved + 1’, and compare fails, so it becomes aware of “packet loss”.

      This does nothing to implement packet re-transmission, and that sort of thing, but I’m pretty sure that can be considered ” out of scope” for this. 🙂

      • BillNo Gravatar says:

        Hi Buzz,

        This is not really a bug but a reason my library shouldn’t be used for someone with a “requirement for guaranteed delivery”.

        The reason I trash all before finding a header is for synchronization. For example, if the receiving Arduino was reset during a transmission it would be seeing serial data with no context of what it was or where it goes. It has to be dumped until the next binary frame is found and aligned correctly. Yes, this also means if the header is corrupted the whole packet is ignored; but I’d rather that be the case. Any form of corruption in the packet should result in the packet getting dropped.

        You do have an interesting suggestion for someone who would want to be notified of corruption. Though I don’t see much of a point of it without also having some sort of retransmit implemented.

        Someone needing guaranteed delivery could do it pretty easily right now. Since the receiving function returns a TRUE when a packet is received successfully, you could have it send a response byte back the the sender that it got the packet ok. The sender would keep trying to send the same packet until it got the ‘ACK’ message back. I may just implement something like this behind the scenes in a future release.

        • BuzzNo Gravatar says:

          As far as a “use case” for my idea ( ie identifying packet loss without retransmissions), I was simply thinking that once the RX end has the ability to identify if there is packet loss occurring, it could use that information to turn on a LED for a period or similar.
          Eg a red “bad cable” led could be turned on for 1 second each time a packet is lost….. and this gives the user a strong indication that the link reliability is good/bad. how may times have you been caught out by dodgy serial cables? 🙂

          Just an idea, I hope you like it.
          Buzz.

          • BillNo Gravatar says:

            If that’s the case you could just put in a third return state for the receive function.

            In a perfect scenario and clear comms, no bytes are trashed before the header and the checksum passes. If any bytes are trashed before the header or a checksum fails, return a -1 or something. That would indicate poor connection without adding more overhead in the packet transmission.

            The only case that would not cover is complete communications dropout and the loss of a whole packet with nothing received at all. But if the channel is that bad, there would be other signs of trouble.

    • jeromeNo Gravatar says:

      hi bill! Works really nice but
      establishing connection is sometimes hard. this is what i did:
      removed blinking stuff
      added some analog data
      send data with 100 ms intervals. This works ok but:
      When the receiving arduino is fed with serial data while starting up it wont work anymore.So if i start the receiving one and then the sending one all is ok.
      Starting up both and then connect them is ok too.
      So i thought it is something with the uart overrun and added a Serial.flush() at the end of the setup but alas that wont help.
      Next step i would like to add return data and then both arduino’s
      become receiving ones. I think that can give troubles.
      Any suggestions?
      grtngs jerome

      • BillNo Gravatar says:

        Hi Jerome,

        Hmm, I’ll have to think about your problem. I thought I had it written so if it starts in the middle it should clear itself out and the receiver shouldn’t get stuck. Maybe I missed a situation.

        As far as two way data, you can create two objects with the library. Have an ET1 and a ET2. If I can get to it tonight, I’ll create a sample sketch that shows this.

        • jeromeNo Gravatar says:

          well-just as i get your reply i found out this:
          Two way data IS working now but here is the funny thing:
          Both arduino’s stop receiving and updating their data after about 80
          packets.They keep sending though…
          So if i reset one it picks up data from the other and after a while it stops.If i reset them together they really stop at the same moment.

          • BillNo Gravatar says:

            Man, you are really hitting me with the odd bugs.

            This may be related to your first bug. How often are you calling the receive function? If you are transmitting every 100ms, you should be calling your receive function every 25-50ms. If both are running at the same rate, you may start ‘drifting’ out of sync till the buffer overruns and loses data. So you should call receive at least twice as often as transmit to make sure everything stays synced.

            • jeromeNo Gravatar says:

              🙂
              ahh-well since they both become receiver i thought i better make the delaytimes the same just to prevent something like that.
              It gives me a good clue about where to look and what to experiment with. Maybe a delay is not good as this stops any other activity?
              So for every sent i have to call receive twice is the idea.
              That should not be too hard to try.

            • BillNo Gravatar says:

              The problem with having them the same time is the Arduino isn’t a perfect time-keeper.

              Let’s say when the receiver means delay 100ms it really delays for 99ms. That means it will miss the first message and it will be buffered till the second time receive is called. Now the receiver is one message behind the transmitter. After a while, another message will miss it’s time slot, and the receiver will then be two messages behind. This will keep happening till the buffer overruns.

              SO it’s better to call receive more often to avoid this buildup of messages.

    • BillNo Gravatar says:

      UPDATE

      I found a glaring bug where the first time the checksum fails the buffers are not dumped and the library crashes. Jerome, this is your problem. Give v1.6 a try and see if it stays running.

    • SmokedNo Gravatar says:

      Any chance this could be used with the Wire/SPI libraries for faster comms.

      Got a project on the go where i need exactly this library and every millisecond is precious

      Atm i’m getting 3/4 of the data i need at 250kbaud

      • BillNo Gravatar says:

        No Wire/SPI support yet, but there’s been enough requests that I’ll be looking into it soon.

        I’m curious, what do you mean you are only getting 3/4 of what you need? Is the comm too slow(you can go as fast as 1Mb/sec) or are you suffering data loss?

        • SmokedNo Gravatar says:

          ive got one arduino recieving dmx (hence 250kbaud) which mucks with the data a little and then forwards it on to another to control some leds and servos

          data loss has also been a slight problem but the data changes so often that it hasnt been a real issue

          cant run any software serial, spi or i2c because all the hardware timers are occupied

          • BillNo Gravatar says:

            I’ve never looked into DMX + Arduino, I’m guessing it takes up the serial port?

            Does the DMX’ing Arduino ever need to hear back from the second Arduino, or is it just one way?

            • SmokedNo Gravatar says:

              purely one way

              dmx takes up the hardware uart and because of some tricky timing i needed timer2, dmx defines pretty loose therefore difficult to predict timing between frames, plus its 8n2 just for the extra challenge

              to run the leds and servos i needed both timers

            • BillNo Gravatar says:

              Hmm, ok, let me see If I got this straight. One Arduino is the DMX relay using timmer 2 and a hardware uart. It sends the received DMX data to another Arduino to do something with: move servos and blink lights.

              And your are using Wire/SPI right now to send the data?

              I’ll look into an SPI version of the library shortly.

    • LarryNo Gravatar says:

      Trying to read the source with a little difficulty (my shortcommings). Does the library limit the total size of the structure to be sent or received to 255 bytes? Is there a reason for that, or could it be increased for larger structures?

      Thanks;

      Larry

      • BillNo Gravatar says:

        The limit of 255 exists in two ways. The length of the buffer is a byte type in all the function calls, and the size of the struct is sent between arduinos as a single byte. It would be easy to change the data types in the function calls and data types for buffer length, but changing the communications protocol to increase the size of the size value to two bytes (int type) would be tricker for a beginner.

        The reason I send the struct size is to confirm on both ends that the structs were set up with similiar data. If the user added an extra variable in one but not the other, the library would compare sizes and ignore communications instead of producing random behavior.

        I wrote the library quickly and figured no one would need more data sent then that, (it is a lot!) but it sounds like thats a problem for you. Do you need to send more? If so, i’ll try to update the library tonight with a higher limit.

        • jeromeNo Gravatar says:

          well we sure know how to keep you busy ey? 😉
          The updated library works better but two way comms is still a bit tricky.
          irregular updates makes it hang and then continue.
          I did not have time to experiment a lot tough so maybe this weekend i’ll give it another try.
          But even if it is not going to work smooth in full duplex i thought of a workaround,
          it might be an ugly solution but i have to know that i have a fresh
          package and the rest is luxury.
          I can sent a square wave on 1 input -say 1 hz- and look for it at the receiving end.
          No transition for 1 sec=no comms=block outputs in neutral.
          That must be easy to build in hardware and gives some extra safety i think.

          • BillNo Gravatar says:

            Hmm, still hanging? If you could give me anymore details about what you are doing at the time and what the Arduinos do in response I’ll see if I can figure out what’s going on.

            You can already figure out if you got a fresh package, the receive function will return a ‘TRUE’ when a fresh package has been received.

            • JeromeNo Gravatar says:

              Good tip,did not see that!
              Didn’t have much time but i did a short test : every pass i can set or reset the onboard led
              depending on the result. I can detect a lost connection-quite important cause i am working wireless. It flickers , i can clean that up with a monoflop or 555.
              That way all will stop in something like half a second after the connection is lost.

Leave a Reply