sscanf

Last time I blogged about how to use sprintf to format output, especially with numbers, into strings. This time it is sscanf, the reverse, how to extract information, such as numbers from a formatted strings.

A lot of situations call for such a process. Say you want to command your robot to move its arm by telling it to a certain angle on a certain motor. Also you may want to set the time on your arduino’s on board real time clock, or want arduino to play an MP3 clip with a sound shield out of several clips. Maybe you want to control fan speeds of your HVAC system over the internet.

Back to the robot problem, say the arm has 3 motors, rotation around a vertical axis from the base, rotation of the arm up and down, and rotation of the grabber along the arm. A natural way is to pass such a command as “MA 150 MB 30 MC 25” to command the three motors to rotate to these angles, MA to 150, MB to 30, MC to 25. Using a string, you can either type up the command in arduino IDE’s serial monitor, or have a program on your PC generate this string to control the robotic arm. The following is pseudo code to process this:

  • Define 3 variables to store extracted numbers
  • Extract each number according to a predefined format
  • A final check to make sure extraction is successful

The more actual pseudo code:

#define expected_number_of_extracted_values 3

char input_string[]=”MA 150 MB 30 MC 25″;

int A_val, B_val, C_val;

int result;

result=sscanf(input_string, format description, list of variables to store the extracted numbers);

if (result!=expected_number_of_extracted_values) complain to user.

So let’s look at the format description. This is very similar to sprintf. The expected string has a character or string followed by space then a number, then repeat two more times for 3 parameters. This is described by the following formatting string: “%s %d %s %d %s %d”. The “%s” is a space holder for a string. The MA, MB, an MC are strings. The “%d” is a space holder for an integer. So 150, 30, and 25. So it reads “string integer string integer string integer”.

Next, you decide to not care about the actual string being MA or MB or MC because you always type them in that order. We will make a less strict assumption later. This strict requirement makes the first number always for motor MA, the second number for motor MB etc. Actually you don’t even need MA MB or MC in the string if you so decide the order of the numbers. But sometimes the string is not generated by you so there are junks and we need to extract number around them.

According to what we discussed in sprintf, the format string needs to have corresponding variables, so the actual sscanf will look like:

sscanf(input_string, “%s %d %s %d %s %d”, string1, A_val, string2, B_val, string3, C_val);

Since you don’t care about extracting the strings “MA”, “MB”, and “MC”, you can use this format string:

“%*s %d %*s %d %*s %d”

Notice the stars in front of the s. Any format term with a star makes the function extract the content and then discard it. This is different from omitting “%s” in the format string and making it “%d %d %d”. If you omit the “%s” in the format string, sscanf will try to match the first thing it sees with an integer and will fail since the first thing it sees is “MA”, which is not a number. It returns failure.

So to summarize, you need the following actual command:

sscanf(input_string,”%*s %d %*s %d %*s %d”, &A_val, &B_val, &B_val);

The ampersand or ‘&’ extracts address of the variables instead of values of them. With address, sscanf can return extracted values to variables.

Actual code:

#define expected_number_of_extracted values 3

char input_string[]=”MA 150 MB 30 MC 25″;

int A_val, B_val, C_val;

int result;

result=sscanf(input_string,”%*s %d %*s %d %*s %d”, &A_val, &B_val, &C_val);

if (result!=expected_number_of_extracted_values) fail();

For more detailed information on sscanf, read this page:

http://www.cplusplus.com/reference/clibrary/cstdio/sscanf/

Phi_prompt is upgrading to arduino 1.0

After some tireless work, my phi_prompt user interface library is upgraded to arduino 1.0 and takes full advantage of phi_interfaces library as physical layer to sense key presses. I was able to revamp my sample codes without much change at all. All call conventions are kept the same. Most change you will need as a project developer with phi_prompt is to include phi_interfaces library instead of the phi_buttons library, and set up keypads to pass to phi_prompt initialization call. An added perk is that in each sample code, I defined two input keypads, i.e. an actual keypad on arduino and a serial keypad either I can use a PC serial terminal or a bluetooth phone. I can operate the menu or any function on my arduino’s buttons, by typing in characters on my PC serial terminal, or with my bluetooth phone (adding a bluetooth shield to arduino of course). It’s super cool. You develop one interface, say a menu system, then you can interact with the menu with local buttons (on arduino), or remotely without any more coding.

Here is a depiction of what you could be doing with this new system:

Custom characters on phi-panel

You can use all custom characters on phi-panels as long as you are not using them in a long message, which uses custom characters to display the scroll bar on the right.

You can do the following:

When you need to use custom characters, follow the sample code phi_panel_big_show between lines 167 and 189. The last command in that function prints “\eZ~” to the panel to reinitialize the panel’s internal custom characters. Otherwise you will see your custom characters in place of the scroll bar 🙂

You will need the custom character definitions in your code as well so:
The code may be a bit messed up by the blog posting restrictions but you can find original code in the beginning and between lines 167 and 189 of the sample code phi_panel_big_show.

PROGMEM prog_char ch0[]={B110,B100,B100,B110,B100000,B1010,B10101,B10101,0};// cm
PROGMEM prog_char ch1[]={B11011,B10011,B11011,B11011,B11011,B11011,B10001,B11111,0};//Inverted 1
PROGMEM prog_char ch2[]={B10001,B1110,B11110,B11101,B11011,B10111,B100000,B11111,0};//Inverted 2
PROGMEM prog_char ch3[]={B100000,B11101,B11011,B11101,B11110,B1110,B10001,B11111,0};//Inverted 3
PROGMEM prog_char ch4[]={B11101,B11001,B10101,B1101,B100000,B11101,B11101,B11111,0};//Inverted 4
PROGMEM prog_char ch5[]={B10,B100,B1000,B10011,B100,B10,B1,B110,0};// /s
PROGMEM prog_char ch6[]={B100000,B100000,B100,B1110,B11111,B100,B100,B100000,0};//Up arrow
PROGMEM prog_char ch7[]={B100000,B100000,B100,B100,B11111,B1110,B100,B100000,0};//Down arrow
PROGMEM const char *ch_item[] = {ch0, ch1, ch2, ch3, ch4, ch5, ch6, ch7};

byte ch_buffer[10];

void demo_custom_char()

{
for (byte i=0;i {
strcpy_P((char*)ch_buffer,(char*)pgm_read_word(&(ch_item[i])));
Serial.print(“\eS”); // Start custom character sequence
Serial.print(i,DEC); // Indicate the custom character to create
for (byte j=0;j {
Serial.write(ch_buffer[j]|0x80); // Add a 1 to MSB to make sure the custom character definition is always beyond a numerical value of 31 to avoid a confusion with control characters.
}
Serial.write(‘~’);
}
Serial.print(‘\f’); // Clear screen
Serial.print(“Custom character “);
for (byte i=0;i {
Serial.write(i);
}
delay(5000);
Serial.print(“\eZ~”); // Reinitialize phi_prompt since the long message requires custom characters;

}

HVAC project

One phi-panel user is using the panel to control his DIY HVAC system at home. Here is a video of his project in progress:

This is very cool!

He is nearly done so I expect more videos 🙂

Using functions in your code

This is for beginners. If you are an advanced programmer, you can skip this post 🙂

If you perform a common task in several parts of your program, instead of repeating the code several times in your code, you make that task a function to call.

Say if that common task is to play a Happy Birthday tune, which involves various tones and pauses, then you can define a function to do that.

void sing_happy_bday()

{

}

Now say some of your tasks involve playing this tune and other stuff, you can use a switch-case structure:

#define over_phone 1

#define home_visit 2

#define restaurant_celebration 3

int mode=over_phone;

void celebrate_bday()

{

  switch (mode)

  {

     case over_phone:

     call_bday_mom();

     chat();

     sing_happy_bday();

     hang_up();

     break;

     case home_visit:

     knock_on_door();

     hug();

     light_candle();

     sing_happy_bday();

     hug();

     say_bye();

     break;

     case restaurant_celebration:

     drive_to_restaurant();

     wait_mom();

     hug();

     order_bday_cake();

     light_candle();

     sing_happy_bday();

     hug();

     pay();

     exit_restaurant();

     break;

  }

}

 

In the above pseudo code, there are multiple functions that are called more than once, such as hug(), light_candle(), sing_happy_bday(). They are the smallest functional modules that are used many times in various parts of the code. Making them into functions makes the code easier to understand and avoid repeating code, which wastes memory space. Also, if you want to change how sing_happy_bday() is implemented, say from just singing into singing with a guitar, all you need to do is to change the sing_happy_bday() function. If you didn’t turn this module into function and repeated it several times in your code, you will need to modify several places to add the guitar. Mistakes happen when you have to modify several places. Maybe in a rare case, you will sing without the guitar, surprising the bday girl 🙂

Benefits of making modules into functions:

*No repeating code so saves memory

*Easy to modify code since the code only has one copy

*Program is easy to understand than packets of details

Drawbacks:

*Program runs slightly slowly (you won’t notice) since a jump is needed to get to the function and a jump is needed to return from the function

*I want to say more but came up short. Rarely do you need to think of the drawbacks 😉

Phi_interfaces library 1.0 released

After much work and documentation, the phi_interfaces library is finally released with full documentation and example code on every class.

This library unites all input devices in an unprecedented way. You can sense a matrix keypad the same way as push buttons, rotary encoders, or analog buttons, or serial keypads, or simulate key presses on arduino serial monitor or even use your smart phone to generate key presses to control your arduino projects. You could create multiple operating interfaces, one on arduino project, one on a remote server and one on your smartphone. You can then control your project wirelessly from meters away or from world away and it feels like you’re controlling it right on your desk.

What is more exciting is that you don’t need to make any change on your code to do all the above. Start your project with a few push buttons and later decide to control your project on your smartphone with bluetooth serial, and finally settle for dual interface, with keypad on the project and with smartphone using bluetooth serial. No need to change any code while you are making all these hardware changes. Interfaces should be just like that, snap on and snap off, all with standard plugs and no fuss.

I will be using this as the physical layer for my phi_prompt user interface library soon.
http://code.google.com/p/phi-prompt-user-interface-library/downloads/detail?name=phi_interfaces_V100.zip&can=2&q=#makechanges

Here are a few nicely done figures in the documentation:

I will be posting videos and tutorials soon!

phi_interfaces library beta release

As a friend online asked for it, I am not going to procrastinate on the release and instead provide a beta release. I uploaded the beta version of the library with sample code on every class, buttons, keypads, rotary encoder, analog button arrays (yes! you can use more than one analog pins and each pin hooks up to several buttons but all pins have to have identical resistor networks).

Here it is, with library, example code and an auto-doc. I’m writing an overview for beginners at the moment. Someone is already testing the code smiley

http://code.google.com/p/phi-prompt-user-interface-library/downloads/detail?name=phi_interfaces.zip#makechanges

With this library, you can arbitrarily change your interface without changing code. Say you start with matrix keypads and then decide go with 6 single buttons and two rotary encoders for the look. You don’t have to change you code. Say you start with no buttons (too scared to hook up buttons and then decide to go with keypads?!), and you can use serial port to type in characters. The library has an object to streamline serial inputs into button outputs for your code so your code thinks it has a keypad. Then later you find out you only need like 4 buttons for everything you programmed and actually hooked up 4 buttons and change one line in the code (instantiate a phi_button_arrays object instead of phi_serials object), you’re done!:)

 

sprintf

I notice that lots of arduino fans are not coming from a C programming background. Even the C++ people may not know such a neat C feature, the sprintf function. I use it so often in my codes and libraries thus it demands a small introduction.

The following is a link to the sprintf function (I’ll be adding this link to my sample codes):
http://www.cplusplus.com/reference/clibrary/cstdio/sprintf/

Essentially the sprintf function takes in a few parameters, such as integers, floats etc. and then follow a format string, output a formatted string that involves the parameters. Since arduino doesn’t print float (to reduce compiled file size), you may need to print two integers for a float. Say if I want to print on LCD the current time in the following format:

13:02:00

I have three variables:

int hour=13;
 int min=2;
 int sec=0;

If I do the simple print, I have to do the following:

 lcd.print(hour);
 lcd.print(":");
 lcd.print(min);
 lcd.print(":");
 lcd.print(sec);

And the result is less than perfect:
13:2:0

So how do I demand the formatting of the numbers to have a maximal 2 integer digits and no missing leading zeros? I have to tell the print function so by means of a format string. Let’s start from simple and add all details step-by-step:

A format string is just a string.
First I want to output integer (not float or else), so integer output is “%d”, or “%ld” for long integer.
Next I want 2 digit integer so “%2d”, or “%4d” if I wanted 4 digit integer.
Next I want to keep leading zero so my time looks right, so”%02d”. If I used “%2d” then leading spaces are provided so I get 13:(space)2:(space)0

Now I’m done with format string, it’s time to call the sprintf:

char[9] buffer=""; ///< This is the buffer for the string the sprintf outputs to
sprintf(buffer, "%02d:%02d:%02d", hour, min, sec); ///< This has 3 2-digit integers with leading zeros, separated by ":" . The list of parameters, hour, min, sec, provides the numbers the sprintf prints out with.
lcd.print(buffer); ///< You will get "13:02:00"

This will get you:

13:02:00

From the above example you can see that you can mix regular texts such as “:” or else with the format string in a complex output. Say we want to output a count-down number like “You have XX minutes left.”, then we do:

sprintf(buffer, "You have %2d minutes left.", min);

You always need to have a buffer char array long enough to hold the output. Count the characters before you define the length of the buffer array and add 1 to the count for string terminator. For the above string, the output is 25 characters, the “%2d” counts as 2 characters. Then you do:

char [26] buffer="";

It’s worth mentioning that sprintf is just for the look. There is no reason to use it if you don’t care about the look of your output.

Now that you have read so much about sprintf, you may also want to know sscanf, which is the opposite. It picks out number from a complex string so if you have a string like “13:02:00”, you can extract hour, min, and sec from the string. This is especially useful when accepting parameters from serial port. If you want to know about this function, read here or reply to this post saying you are interested in a post about the sscanf.

http://www.cplusplus.com/reference/clibrary/cstdio/sscanf/

Happy New Year!

Happy New Year 2012 and thank you for all your visits! Below is the last few months of blog visits.

A total of more than 62,000 visits over the last year and 386 visits per day during the busiest day! In the last few months I was very busy with work and didn’t update enough of my blog as often. I hope with next semester I can spare more time on updates of my blog, open-source software libraries and hardware designs. It is going to an exciting year. I plan to make some devices for teaching labs, and I have a new and upgraded interface library to roll out in a few days to unite all libraries such as buttons, matrix keypad, analog buttons, rotary encoders etc. Please keep tuned!

 

In case you want to know the visit per month in December, it was 7,919, or 255 visits per day!

%d