This is a in depth tutorial on how control your arduino micro-controller via serial. Unlike other tutorials I will not use the 'char' variable but 'unassigned long's' to store numbers much larger than 255 "If this dose not make sense I will explain later".

This tutorial will focus on the serial control of the digital/analog ports as well as servos but the concepts will be applicable to anything you want to control. Also I will go over how to read data from the digital and analog ports sending it back to the computer.

For this tutorial I will just use the arduino Serial Monitor to send and receive data but any language that can send and receive serial data will be interface with the arduino with no modifications to the code. Examples would be python, C, C++, Processing, an so on...

Before starting I assume you have an arduino board and have install the standard programing environment. If not the boards and the programing environment can be found here. I also assume you are familiar with the arduino, and the basics of the language so I will skip over the setup.

Also this is my first tutorial so keep that in mind while reading and please post a comment if you notice anything off.

Serial Protocol

Before we jump into code we need to think about serial Protocol. How do we tell the arduino what we want it to do?

A lot of peoples first thoughts for controlling the arduino is to send a command in the form of words. For example "digital pin 4 on". This works OK, but because the arduino isn't human it dose not understand English; so a command like that takes a lot more code to translate into an action. Also that is quite a bit of data to send over the serial port!

The best way I have found to talk to the arduino is not with words but with numbers. Each number we send will correspond to an action. In this tutorial we will group the actions into three groups a '1' will change the state of a pin "analog/digital", a '2' will read data from a pin "analog/digital", and a '3' will control or read from a servo.

By using numbers we can make it easy for the arduino to understand what we want, but what about the extra variables the arduino needs to carry out one of the above tasks? How do we tell the arduino to read an analog pin not a digital one? Actually its simple just have another group inside of the first; a '1' will read digital, a '2' will read analog.
Finally we need to get the variables the arduino needs; which in this case is pin number. All you need to do for that is read a final number from the serial port!

The full serial protocol for all the tasks I mentioned would look this:

1 = Wright:

1 = digital:

"pin number"

"1 for LOW"

"2 for HIGH"

2 = analog:

"pin number"

"frequency (0-255)"

2 = Read:

1 = digital:

"pin number"

2 = analog:

"pin number"

3 = Servo:

1 = read:

"pin number"

2 = wright:

"pin number"

" position"

You may be wondering why make a group within a group when you could make separate groups for analog read and analog wright? Really its my personal preference once you understand the concepts you can do it any way you want.

It may look complex but I found it to be the best way to do it. Also I don't have any good flow charts for it yet .

If you ever want to add a function like motor control or what ever else is not covered by these categories just add a fourth position and so on...

Like this.

1 = Wright:

1 = digital:

"pin number"

"1 for LOW"

"2 for HIGH"

2 = analog:

"pin number"

"frequency (0-255)"

2 = Read:

1 = digital:

"pin number"

2 = analog:

"pin number"

3 = Servo:

1 = read:

"pin number"

2 = wright:

"pin number"

" position"

4 = Your Function:

1 = Your Sub Function:

"your variables"

2 = Your Sub Function:

"your variables"

OK now that you have a general idea of the protocol I will be using lets jump into the code!

Code
Disclaimer: I will not go into great depth about the assigning of arrays or really any code that dose not pertain to serial "this includes the servo library". So of something like this looks foreign myservos[pinNumber] = Servo s1; you may need to read up on the arduino documentation found here before preceding. Also some of this code deals with variable scope so make sure you know the programing basics. However even if you have limited experience many of the code examples as far as getting the serial data may be extremely useful. Also at the end there is an attached file with the complete and working code and the final example will show the complete program.

Step 1:

The first step is to figure out how to receive serial data from the computer. The easiest way to do this is with the Serial.read() statement. Sending data is accomplished a similar way with the Serial.print() or Serial.println() statements. The first statement simply prints the data you want, and the other dose the same thing but with a /r/n newline characters on the end.

I'll skip over the basics like the assigning of the variable, but whats happening here is the serial is being started at a "9600" data rate Serial.begin(9600);

Next we check if there is new data available if (Serial.available() > 0)

Finally we read the data serialData = Serial.read(); and print it back over the same serial port Serial.println(serialData);

If you run this program and open the serial monitor you should have what ever you type echoed back but in ASCII . There for 1 = 49, 2 = 50 and so on... An ASCII chart is available here .

Step 2:

Now time to make things more complicated. As you may have noticed the arduino only receives 1 piece of data at a time. This works OK if we are only needed to send numbers between 0-9 but we want to be able to tell a servo to go to position 180 right? This is where we need to take multiple numbers one at a time and combine them into one big number.

This is where some very basic math comes in here is our formula.

x = number we want
n = our current number
i = number we want to add to the end

x = n * 10 + i

As you can see this simple attaches the number received to the end of the number we are making. Now we can append each new number to the end of what will be come our final number.

Lets translate this into code. The variables used through this tutorial will be:

unassigned long serialdata; Used to store the chain of numbers
int inbyte; The number we just received from the serial port

So the formula looks like this to the arduino:

Code:

serialdata = serialdata * 10 + inbyte;

This gives us a number we can use to determine which function the user wants to run 1, 2, or 3. Or we can plug it directly into a varable like pinNumber or servoPose .

This should output the combined value of numbers you input via serial. If strange numbers come up things may be being printed in ASCII. I'm not 100% sure why the arduino sometimes nor am I sure how to fix it but the variable its self is OK and everything but the Serial.println() statement will see it correctly.
You have probably noticed by now that the program just jumbles all the values you enter into one giant variable? But if it takes three numbers to read a analog pin '1' '2' '7' wouldn't the function combine that all in to '127' ? If it did that our program would fail. We need a way to tell the program when one number begins and the next ends. I like to do that with the '/' character. Because our program only receives numbers the '/' character will never be sent so we can use it as a special character. In this case it will signify the end of a number.

As you can see I migrated the all the code to a separate function. This will come in handy later when we are writing the final program. This will print the current number every time you add a number then clear the data when you send a '/' . Also it will return the variable serialdata so code in the main loop can use it.

Congrats! The serial data gathering part is over! For beginners and experts alike the above function can be very useful for getting numbers from the serial port. If you want to see how the protocol I went over way back at the beginning works and create the program for controlling the arduino keep reading.

Step 3:

Now we need to build the program that requests and handles the serial data. Remember our end goal is to control the analog/digital ports, servos, and read the analog/digital ports. So lets begin.

Now we see the serial protocol way back at the beginning come into full play. I will be using "switch/case" statements but "if" statements work just as well. Info on those can be found here and here . The reason I chose to use a switch/case statement is because it is easier to expand on.

So lets start by adding data to control analog/digital pins. I'll use the program I just made as a base to build the code on.

This may look very complex but its function is simple turn analog/digital ports on and off. As you can see every time the getSerial(); command is called the value stored in serialdata is updated. That allows us to check if it is a known command or assign it to a variable depending on what part of the loop we are at.

With this code added sending a command like '1/2/7/1/' will turn pin 7 on HIGH
Sending '1/2/7/0/' would turn it off
Sending '1/1/7/255/' would turn pin 7 on at a analog rate of 255 or full power
And so on...

Each case statement has a getSerial(); statement before it so that when it determines which case the user wants to run the data us up to date.
The first two numbers are fed into switch statements each switch branches of to the correct commands for the numbers received.
The third number received is stored in pinNumber and that is used to initialize the pin and write to the pin. The fourth number received is the state between 1-2 for digital and 0-255 for analog.

That covers the important points of that function now lets move on to reading values. As I said I will not really go over the code line by line but instead brush over the important parts concerning serial.

As you can see the same principles used in the first one apply to this.
First two numbers determine which case we want.
Third number is stored in pinNumber and used to determine which pin to read.

However a statement I introduced back at the beginning is added Serial.println(); this is used to print the sensors value back to the computer via serial. If you are using serial monitor when running a command like '2/1/7/' you should get a value.

That sums up the analog/digital read one more step to go!

The servo code is the most complex in my opinion and I may have done things poorly/strangely so feel free to leave a comment asking WTF and recommending a better way to do things.

There it is! Full serial control of analog/digital, servos, and analog/digital read. You will see in the servo code there is three cases, that is because there is an attach/write function, detach function, and a read function that returns the current position of a servo or a '0' if its not set.

I will go over the variables for the final piece of servo code just because there are so many.

int servoPoses[80] = {};
Stores the current position of all the servos

int attachedServos[80] = {};
If a servo is attached the value corresponding to the pin number is set to one; this is important so you don't attach the same servo twice.

Servo myservo[] = {};
Stores all the servo object in an array so they are easy to access

int servoPin;
Pin of the servo the user wants

int servoPose;
Position the user wants the specified servo to go to

That sums up the coding part of this tutorial.

Tips & Tricks

Finally I would like to go over some key concepts/extra information you may need.

Most importantly is the serial bus length. The arduino has a serial bus length of I believe 128bits but for the life of me I could not find it on google. If you send to many numbers at once and the arduino dose not read them fast enough it will overflow and any data you pile on it will be lost! A good method to prevent this is called handshaking where the arduino asks the computer for data then the computer sends sends it, and the process repeats... I may go over that in a new tutorial but this one is getting to long.

You may have noticed that I never really went over the computer side of the equation besides mentioning the serial monitor on the arduino IDE. The main reason is there are tons of program languages and they are all different. Making a example for each one would be very difficult.

However I will include two programs in the attached file with the arduino code made in python. On lights up lights sequentially on pins 1-13 in the "knight rider" style. The other cycles two servos between 0-180 degrees. To run the programs you will need pyserial installed. Also make sure you edit s = serial.Serial(2, 9600, timeout = 2) to reflect your serial port -1 .

Re: Complete Control Of An Arduino Via Serial

Re: Complete Control Of An Arduino Via Serial

Firmata protocol, "which I researched quickly before starting this project" seems to be only for low level control of the arduino. The intent of my project was not low level control "although it is featured in the main examples" instead when I created the the code my intent was an easy way to call and pass variables to complex "functions" on the arduino.

For example a specific motor drivers requires a specific signal type and style. Using my method all you could wright a complex unique motor control "function" for sending commands and keeping track of speed. All the computer would do is send a few numbers i.e. speed, duration, acceleration then the arduino would do all the complex calculations, pid, and communications.

It may be possible to do the same thing using firmata but with much more unnecessary computer involvement and in the end much slower speeds.

I hope this clarifies why you would choose a method like this over firmata, but I still feel I have done a bad job explaining it.

Dalton Caughell

11-21-2012

yeeho
Guest

Re: Complete Control Of An Arduino Via Serial

Thank you for the tutour, but I dont get it work. I was using command '1/2/7/1/' in arduino IDE, but cant turn on pin7

01-13-2013

sojiro
Guest

Re: Complete Control Of An Arduino Via Serial

Sir, thank you for your tutorial...why is that it doesn't have have output in my arduino! no lights "analog/digital" ! tnx..waiting for your reply!

02-09-2013

tomsteemson
Guest

Re: Complete Control Of An Arduino Via Serial

'1/2/7/1/' in arduino IDE, but cant turn on pin7

Try '1/2/7/2/' to switch on the digital pin 7

02-09-2013

tomsteemson
Guest

Re: Complete Control Of An Arduino Via Serial

Found the answer to this question.....

02-10-2013

tomsteemson
Guest

Re: Complete Control Of An Arduino Via Serial

No worries, I figured it out.

The Arduino Sketch is exactly that which has been so kindly distributed in this article.

The project uses a light-beam sensor that is sitting on analogue pin 0, with an LED that is operating as a visual indicator. When the beam is broken, the LED is lit. When the beam is clear, then the LED goes out. In this project then there are effectively only two states to worry about. However, the sensor could be anything else. A temperature sensor for example.

Because there are only two states, rather then have to constantly write to the Arduino to tell it to put the light on, or switch it off, the code to change the state of the led is only called at a change of state. That cuts down on the amount of work that everything is doing, and the amount of traffic running over the serial line. I'm using a flag <led> that remembers what state the LED was last set to. When the return value of the analogue pin <x> is interrogated, if the value has changed such that it invokes a change of state, then the signal to change the state of the LED is sent and the led variable is set to the new state level.

Let's start at the top of the Python code and work down then:

Having imported the serial and time libraries, the serial connection is set up. I'm using a Raspberry Pi to communicate with the Arduino Uno over the USB cable, hence the '/dev/ttyACM0' parameter at the beginning of the serial.Serial set-up.

I'm now setting up the variables with the code sequences I need to pass to the Arduino. Setting variables populated with the predefined codes rather then using a string of digits every time makes Python script so much easier to code up and read. I'm going to assume that the beam is open at initiation, so I'll set <x> to a high figure and <led> to a high state. I'll then pass the Digital pin 3 High code <D3High> to the Arduino and switch on the LED.

Now I'm going to loop till I drop!

I write the <A0Read> request to the Arduino, then read what comes back. I'm slowing the process down <time.sleep(0.02)> there in this example, but I'm not entirely sure that's necessary. Need a bit more experimentation there.

I'm then going to try and convert the serial string that is returned from the <arduino.readline()> request in to an integer. I found that the readline call could sometimes return some spurious answers seemingly unrelated to what I was after, especially at start-up. The <try:> statement ignores anything that's not numeric, so the balance of the program is considerably more reliable. As a result the numeric value of the analogue pin <x> is either set to a valid value, or remains set to the previous valid value.

The last block of code is the section that interrogates the value of <x> in association with the value of <led> and makes the state change to the program if required.

Some notes here:

There appears to be some conflicting advice with regards the code sequences required to operate the system in the body of the tutorial. The observant among you may have spotted that the codes I'm using to control the Arduino don't follow the pattern detailed. I've not tried using the Servo parameters, but with regards reading and writing to digital and analogue pins, the code sequencing appears to work like this:

PN = The target pin number
VA = (Digital Value is 1 for low or 2 for high) (Analogue Value is between 0 and 1024)

To WRITE / DIGITAL / PIN 3/ HIGH the code is '1/2/3/2'

Just wanted to thank ROBOTMAN for his sterling work here. I bought a Raspberry Pi a few weeks ago, and was having great fun with it, but it's limitations with regards dealing with the real world gave me some grief. Having discovered the Pi, I was quickly introduced to the Arduino. Now I've got the power of a Linux O/S driving a device that is designed specifically for dealing with the outside world. Can't wait to get deeper in to the possibilities that this combination of processing power offers. Complete Control of an Arduino Via Serial; I couldn't have wished for a more suitable marriage of technologies. Thanks ROBOTMAN.

03-10-2013

dvl12
Guest

Re: Complete Control Of An Arduino Via Serial

I found your article very useful, but I would like to ask one question on how I can personalize it for my code. How can I make it so when I write something like: 10//9/ ;the missing number between // will just leave variable as it was? This way I want to make the process of inputting variables faster and also I would not have to keep the number in my head if I just want to keep it constant. Here is my code to get better understanding of the problem: