Home arrow Tutorials arrow Software arrow Tutorial - Using CmdArduino
Tutorial - Using CmdArduino | Print |
Written by Akiba   
Friday, 23 July 2010

The Arduino Command Line Interface, aka CmdArduino, is a simple shell that can be run on an Arduino. It's nothing fancy and its main purpose is to allow users to easily call their functions on a running Arduino via a simple serial terminal. It also allows users to pass in arguments from the command line into the functions they wrote so they can easily toggle pins, set blinking speed, set pwm duty cycles, or whatever else might need command line user input. Using it is fairly simple and just requires unzipping the files into the "Arduino/libraries" sub-directory in the Arduino program folder. The following is a tutorial that goes into more detail about how to implement CmdArduino in a sketch and easily add user functions to the command table. 

Before we start, I need to mention that you'll need to use a serial terminal program to access the Arduino. The Serial Monitor built into the Arduino IDE does not allow carriage returns, ie: the Enter key, to be passed through the serial interface. For Windows, I'd recommend using a free program like Teraterm Pro or RealTerm . For Linux, I'd recommend picocom . And for Mac, you can simply use the "screen" command built into Mac OSX. You don't really need all that fancy scripting either ;)

Now, let's get started...

  • Unzip files into Arduino /libraries sub-folder:

     

 

  • Next, start up the Arduino application and check out the examples. They can be found in: “Files/Examples/Cmd/”

     

     

You’ll find that there are multiple examples. This tutorial will be skipping between different examples but I’d personally recommend starting from the beginning. Let’s start off with Example 1 (cmd_line_ex1_hello).

Example 1 is your standard “hello world” example, but applied to the command line interface. The goal of this example is just to print “hello world” when you type “hello” at the command line. Let’s dissect the code. Here's a shot of what it does:

It's a very simple sketch, but it demonstrates how a function can be called from a command line shell running on the Arduino. Now let's take a look at some of the important points of implementing CmdArduino in your sketch. Here's the complete code listing, minus comments, from Example 1:

#include <Cmd.h>

void setup()
{
  cmdInit(57600);
 
  cmdAdd("hello", hello);
}

void loop()
{
  cmdPoll();
}

void hello(int arg_cnt, char **args)
{
  Serial.println("Hello world.");

Let's dissect this code:

1) The first thing you need to do is include the Cmd library into the sketch. This tells the sketch that the functions being called can be found in the files inside the Cmd folder. You would add this at the top of the sketch:

#include <Cmd.h>

2) The next thing that needs to be done is to initialize the Cmd library. The main thing to do is to set up the serial port speed. You can use any of the standard serial port speeds. In this case, I’m using 57,600 bits per second.

3) You’ll also see that the commands are added in the setup() portion of the code. The cmdAdd function takes two arguments. The first argument is the “friendly” name that gets used on the command line. The second argument is the name of the function in the sketch that will get executed when you type in the “friendly” name at the command line. You can add multiple commands to the command line, but in this example, we’re only adding one. 

void setup()
{
  cmdInit(57600);
 
  cmdAdd("hello", hello);
}

4) In the loop() portion of the code, the function cmdPoll() is called. It just checks to see if any commands have been typed into the command line.

void loop()
{
  cmdPoll();
}

5) This is the actual function that will get executed when you type “hello” at the command line. The “friendly” name and the function name do not need to match. In this example, they do, but in other examples, you’ll see that they’re completely different. One thing you’ll probably notice is that the function has a specific format. All functions that get called from the command line need to have this particular format because the command line will use the two function arguments to send data into the function. Let’s take a look at the function arguments and why they’re needed:

void hello(int arg_cnt, char **args)
{
  Serial.println("Hello world.");
}


Actually, I could have simplified things a lot by not requiring any function arguments. In that case, the format for any function would look something like this:

void func_name()

The only problem is that this is of limited use. At the command line, you could type in the function name and the function would get executed. That’s fine for something like the “hello” function that prints “hello world” because its static. But in many cases, you’ll want to pass in command line arguments to the function you’re calling. An example would be a function that changes the PWM duty cycle of an LED (cmd_line_ex4_pwm).

Rather than just typing in:

pwm 

and having the LED turn on at a fixed brightness, the function becomes much more useful when you can also send in a command line argument. If you could change the PWM duty cycle on the fly, then you can experiment with different brightnesses to see which one suits your application:

pwm 50 
pwm 100
pwm 255

If you could support command line arguments, then you can experiment with the different brightnesses dynamically rather than having to re-code the function and download it into the board.

To support generic command line arguments that can be used in any function, I used the convention that’s commonly found in command line shell code. Shells usually pass in two pieces of data to any function called by the shell

  • The number of arguments,
  • An ASCII list of the arguments.
Its up to the individual functions to interpret how these arguments are used. If no command line arguments are needed by the function, then it can just ignore the data passed into it.


So in order to support passing in arguments to the function from the command line, I made the command line function template like this:

void func_name(int arg_count, char **args)


The arg_count is the number of arguments typed into the command line and this includes the command itself. The second variable requires more explanation. Truthfully, I would have liked to avoid something that looked like

char **args 

because it scares people off. However I’m hoping that a bit of explanation will help clear things up.

In C, when you see something like “char *something”, that just means that you have an array of characters, ie: a string. When you see something like “char **something”, that means you have an array of an array of characters, in other words, an array of strings. That’s all that “char **args” is. It’s the complete list of the command line arguments that the user typed in. The command line chops up whatever’s typed in at the command line, based on spaces (space-delimited), and then puts them in a string array. It then counts how many items are in the array and passes both to the function.

In Example 2, there’s a command line function that just shows how the chopping occurs and what the data passed into the functions look like. The output is just the raw output of the “char **args” data that’s passed to the function. The command line, aka “friendly”, name in Example 2 is called “args” and here’s what it does:

CMD >> args 3 45 67 hello world i love you yay
Arg 0: args
Arg 1: 3
Arg 2: 45
Arg 3: 67
Arg 4: hello
Arg 5: world
Arg 6: i
Arg 7: love
Arg 8: you
Arg 9: yay

As the implementor of the function, its up to you to decide which arguments you want to use and which to ignore.

One more thing that you need to know to use the arguments that get passed into the function is that the numeric arguments are passed in as ASCII strings. They’ll need to be converted to integers to be used in the actual application. I’ve also implemented a function that does this:
int cmdStr2Num(string, base);
The string variable is just the numeric string that you want to convert to a usable integer value and the base is the numeric base you want to use for the conversion. So for a decimal number, you’ll want base=10 and for a hexadecimal number, you’ll want base=16. Here’s an example of how to use it. It’s actual Example 3 (cmd_line_ex3_led_blink) from the library:
led_blink_delay_time = cmdStr2Num(args[1], 10);
If you run Example 3 and type this in at the command line:
blink 100
then the command line arguments passed into the led_blink function look like this:
args[0] = “blink”
args[1] = “100”

We’ll need to convert the ASCII string “100” to a usable integer and to do that, the function “cmdStr2Num” is used as shown above. Once we have a usable integer, then we can use it inside the sketch. You’ll also see an example of how to control PWM from the command line in Example 4.

Hopefully that helps in understanding how to use the command line. If you have any questions, you can post a comment or post in the forums.

Hope you enjoy this lib. Here's a quick reference on what functions exist and their arguments:

 

CmdArduino Reference

 

  • void cmdInit(speed)

     

    Usage: This goes into the setup() loop and initializes the command line interface's serial speed. 

    Example:

    cmdInit(115200); 
  •  

  • void cmdPoll()

     

    Usage: This goes into the loop() function and checks if there are any new commands that have been entered.

    Example:

    cmdPoll(); 
  •  

  • void cmdAdd(cmd_line_name, function_name)

     

    Usage: This is used in the setup() section and adds a command to the command table. The cmd_line_name is the alias that is used at the command line to trigger the execution of the function. The function_name is the name of the function that will be executed.

    Ex:

    cmdAdd("pwm", pwm_led); 
  •  

  • int cmdStr2Num(numeric_string, base)

     

    Usage: This is used to convert a numeric string to an integer. numeric_string is a number in ASCII string form. base is the numeric base. Most people will probably only set base to 10 (decimal) or 16 (hexadecimal).

    Ex:

    pwmVal = cmdStr2Num(args[1], 10);
  •  

  • Command Line Function Template

     

    All functions that will be called from the command line must follow this format.

    void func_name(int arg_cnt, char **args) 
  • Link to Download CmdArduino

    Note: You'll notice that the source code has a .cpp extension but is really written in C. There was some weird error messages for the Arduino Serial library when I compiled with a .c extension as opposed to when I used a .cpp extension. There's probably something I'm missing, but since I'm still getting used to the Arduino dev environment (it's only my second day using an Arduino, ya know), I decided to go with the .cpp extension. This will probably get fixed in a later release.

Hits: 25483
Trackback(0)
Comments (10)Add Comment
good tutorial and a handy Arduino library
written by Greg Peek, July 24, 2010
I'm going to start using this right away.

cmdStr2Num uses strtol, which will also handle base 2 (binary) and base 8 (octal). But it does return a long type variable. Does the magic of C make that work with Arduino functions like DigitalRead(), which expects an int type variable?
report abuse
vote down
vote up
Votes: +0
...
written by Akiba, July 24, 2010
Thanks for the kind words smilies/smiley.gif

In regards to your question, cmdStr2Num() returns a 32-bit variable (long int on an AVR). An int on an AVR is 16-bits so if you assign an int to the cmdStr2Num() function, you will get the bottom 16-bits of the value.

Ex:
int myVal;
...
myVal = cmdStr2Num("50000", 10);

It seemed that using the int type is quite common which is why I used that for my example. However the cmdStr2Num() function, or strtol() in C, can handle char, int, and long int types.

As you mentioned, it can also handle binary and octal, as well as any base from 2 to 36. But I'd feel sorry for anyone using base 36.
report abuse
vote down
vote up
Votes: +1
wooot
written by Jan, December 01, 2010
hey Akiba,
thank you for this great piece of code! I think you should submit it to the arduino playground.
I am going to use this right away to help me develop my stuff. Actually i thought of something like this but was too lazy to implement it.. will save me a lot of time, to thx again!
report abuse
vote down
vote up
Votes: +0
...
written by Akiba, December 01, 2010
Glad you like it smilies/smiley.gif
Yeah, I've been meaning to add it in there but am just lazy. I'll check out how to submit to the playground right now.
report abuse
vote down
vote up
Votes: +2
Alternative with a few more features
written by MikeSmith, January 30, 2011
I implemented something similar for the CLI on ArduPilot Mega. The major differences really just boil down to using program memory for strings and pre-parsing arguments into integer and float values. Look for menu.cpp and menu.h here:

http://code.google.com/p/arducopter/source/browse/trunk/libraries/AP_Common
report abuse
vote down
vote up
Votes: +2
Michael Kors Handbags Outlet
written by Michael Kors Handbags Sale , February 03, 2012
HYCJL18565V3 Thank you for taking the time to publish this information . Michael Kors Shining Leather Crystal Nickel Handbag is an American leisure style handbag. Michael Kors Handbags Sale This type of fashion MK handbag sends out elegant and temperament which can enhance the confident feeling to women. Michael Kors Tote Bags Simple and personal style is super nice choice for femal. Michael Kors Wallet Take MK Shining Leather Crystal Nickel Handbag to your home, you will like it when you own it. http://www.michaelkorshandbagssale.net
report abuse
vote down
vote up
Votes: -4
INT vs POLL
written by RobD, January 19, 2013
Hi,

How could I make the UART int driven rather than being POLLed?
This would make the command line more responsive.

Had an issue with compiling while using Arduino 1.0.3. To fix it change the #include "WProgram.h" to " Arduino.h"
report abuse
vote down
vote up
Votes: +0
thanks
written by miceuz, January 28, 2013
Thanks for this piece of code, now I don't have to write it myself smilies/smiley.gif

You should put the code on some public code repository like github, so we could submit fixes (like Wprogram.h -> Arduino.h)
report abuse
vote down
vote up
Votes: +0
Glitch with too many commands
written by jjz, June 12, 2013
Thanks for this code. It works great but seems to have a problem. When there are more than 5 commands it says "Command not recognized" for any command after the first. Any suggestions?
report abuse
vote down
vote up
Votes: +0
...
written by Akiba, October 06, 2013
It sounds like you might be low on RAM in your sketch. I've run it with around 10 commands with no problem. If you're low on RAM, then cmdArduino might start acting weird (as well as other parts of your sketch).
report abuse
vote down
vote up
Votes: +0

Write comment

busy
  No Comments.

Discuss...
< Prev   Next >