Voice Operated Internet Control of a PICAXE (Part II)

Objectives

Experiment with more advanced features offered by Picaxe microcontroller. Measure temperature through a Maxim  DS18B20   sensor and obtain interactivity with recourse to audio response using text to voice offered by Google translate.

The electronic setup

AXE050 board with Picaxe18M microcontroller is used just as in Part I. Here is a picture of AXE050:

AXE050 Board

Temperature sensor Maxim  DS18B20  is added to the AXE050 board reads temperatures. The advantage of using Picaxe18M is that the same ports are used for control and programming.

DS18B20 Pinout

PICAXE-18M and DS18B20 connections

Reading and control of AXE050 board is done using RS232 protocol. The onboard connections are used for RS232 control.

Pre-Requirements

Before carrying out this part of project, Voice Operated Internet Control of a PICAXE (Part I) must have been implemented, i.e. experimented already with simple switching of a LED on the AXE050 board. The firmware on the chip will be the same as in Part I, and the same as in Internet Control of a Picaxe published here long time ago.

RS232 control is done again in DOS environment, using Kermit for DOS. Kermit scripts are run by PHP, to control AXE050. Kermit’s executable MSK316.exe is installed in same directory as all files. As mentioned in part I, all files will be in c:\xampp\htdocs.

Note: COM2 is used  at baudrate of 4800 setup in Control Pannel of Windows XP.

Now the scripts…

STATUS Kermit script (name it status.ksc):

set port 2
set baud 4800
clear
output c=s
input /nowrap

The new command is input /nowrap, being used to obtain output from Kermit and pipe it into the server.

This script is called in a BATCH file (name it sta.bat):

@echo off
c:\wamp\www\msk316 take status.ksc
exit

TEMPERATURE Kermit script (name it gettemp.ksc):

set port 2
set baud 4800
clear
output c=t
input /nowrap

Again we use new command input /nowrap.

This script is called in a BATCH file (name it temp.bat):

@echo off
c:\wamp\www\msk316 take gettemp.ksc
exit

All batch files are then converted into .exe using Bat_to_Exe_Converter. As result, will have two new executables sta.exe and temp.exe in the folder htdocs, besides the previous part I executables ledon.exe and ledoff.exe.

Finally again the html and php codes…

Substitute index.html of Part I with new one as shown below, again within htdocs folder of Windows-based XAMPP server.

index.html

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-language" content="en-US">
<meta charset="utf-8">

<title>Voice Operated Control </title>
<script type="text/javascript">
function checkSpeechSupport(){
var element=document.createElement("input");
if (!('webkitSpeech' in element)) {
alert("Sorry! Your browser does not support the Speech Input");
}
}
function checkanswer() {
var answer = document.getElementById('q2answer').value;

if (answer == 'light on') {

window.location.href = "http://localhost/processing.php?action=on";
}

else if (answer == 'lights on') {

window.location.href = "http://localhost/processing.php?action=on";
}

else if (answer == 'light off') {

window.location.href = "http://localhost/processing.php?action=off";
}

else if (answer == 'lights off') {

window.location.href = "http://localhost/processing.php?action=off";
}

else if (answer == 'temperature') {

window.location.href = "http://localhost/processing.php?action=tem";
}

else if (answer == 'temperatures') {

window.location.href = "http://localhost/processing.php?action=tem";
}

else if (answer == 'status') {

window.location.href = "http://localhost/processing.php?action=sta";
}

else {
window.location.href = "alert.php";
}
}
</script>
</head>
<body onLoad="checkSpeechSupport()">
<form id="speechform">
<fieldset id="inputs">
<font face="arial, verdana"><legend><h2>Voice Control of Picaxe AXE-050U:</h2></legend>
<label for="q2answer">Say commands: "light on", "light off"<br>"temperature" and "status":</label></font>
<input id="q2answer" name="q2answer" type="text" x-webkit-speech onwebkitspeechchange="checkanswer()"/><br/>
<img src="http://localhost:8888/out.jpg">
</fieldset>
</form>
</body>
</html>

Substitute processing.php of Part I with new one as shown below, again within htdocs folder

processing php

<?php
// numerical to text class included
include 'num2text.class.php';
//check the GET actions variable to see if something needs to be done
    if (isset($_GET['action'])) {
    //Action has been requested
    //Issue the command we wish to send to the Picaxe

    if ($_GET['action'] == "on") {
        //Turn LED on - for this simple script we are just looking for either a 1 or 0
    $page = "index.html";
    header("Refresh: 4; URL=\"" . $page . "\"");
          exec ('sta.exe',$report);
           // check waht is in array $report
           // print_r($report);
          $pieces = explode(' ',$report[0]);
          if ($pieces[1] == 1) {
                echo "<font face=\"arial, sans-serif\"><b>LIGHT IS ALREADY ON</b></font><br>";
                echo "<iframe src=\"http://translate.google.com/translate_tts?tl=en&q=light+is+already+on!\" name=\"top\" width=\"320\" marginwidth=\"0\" height=\"50\"></iframe>";
          }
          else {
          exec('ledon.exe');
          echo "<hr align='center' size=\"4\" color=\"orange\"><br>";
          echo "<font face=\"arial, sans-serif\"><b>LIGHT IS NOW ON</b></font><p>";
          echo "<iframe src=\"http://translate.google.com/translate_tts?tl=en&q=light+is+now+on!\" name=\"top\" width=\"320\" marginwidth=\"0\" height=\"50\"></iframe>";
      }

      }

     else if ($_GET['action'] == "off") {
     //Turn LED off
     //Now we "open" the serial port so we can write to it
     $page = "index.html";
     header("Refresh: 4; URL=\"" . $page . "\"");
           exec ('sta.exe',$report);
           // check waht is in array $report
           // print_r($report);
           $pieces = explode(' ',$report[0]);
           if ($pieces[1] == 0) {
                echo "<font face=\"arial, sans-serif\"><b>LIGHT IS ALREADY OFF</b></font><br>";
                echo "<iframe src=\"http://translate.google.com/translate_tts?tl=en&q=light+is+already+off!\" name=\"top\" width=\"320\" marginwidth=\"0\" height=\"50\"></iframe>";
           }
           else {
           exec('ledoff.exe');
           echo "<hr align='center' size=\"4\" color=\"orange\"><br>";
           echo "<font face=\"arial, sans-serif\"><b>LIGHT IS NOW OFF</b></font><p>";
           echo "<iframe src=\"http://translate.google.com/translate_tts?tl=en&q=light+is+now+off!\" name=\"top\" width=\"320\" marginwidth=\"0\" height=\"50\"></iframe>";
           }
      }

      else if ($_GET['action'] == "tem") {
           exec ('temp.exe',$report);
           $pieces = explode(' ', $report[0]);
           $n2s = new num2text($pieces[1]);
           $page = "index.html";
           header("Refresh: 4; URL=\"" . $page . "\"");
           echo "<hr align='center' size=\"4\" color=\"orange\"><br><b><font face=\"arial, sans-serif\"><font color=blue>LOCAL TEMPERATURE:</b></font></font><br>";
           echo "<font face=\"arial, sans-serif\"><b>".$pieces[1]."&nbsp;ºC</b></font><p>";
           echo "<iframe src=\"http://translate.google.com/translate_tts?tl=en&q=local+temperature%+is+".$n2s."+degrees+celsius.\" name=\"top\" width=\"320\" marginwidth=\"0\" height=\"50\"></iframe>";

        }

      else if ($_GET['action'] == "sta") {
      $page = "index.html";
      header("Refresh: 4; URL=\"" . $page . "\"");
           exec ('sta.exe',$report);
           // check waht is in array $report
           // print_r($report);
           $pieces = explode(' ',$report[0]);
           // check what is in $pieces
           // echo $pieces[1]."<br>"; // piece1
           //echo $pieces[2]."<br>"; // piece2
           echo "<hr align='center' size=\"4\" color=\"orange\"><br><b><font face=\"arial, sans-serif\"><font color=blue>LOCAL STATUS:</b></font></font><p>";

                if ($pieces[1] == 1) {
                echo "<font face=\"arial, sans-serif\"><b>LIGHT IS ON</b></font><br>";
                echo "<font face=\"arial, sans-serif\"><b>TEMPERATURE IS ".$pieces[2]."&nbsp;ºC</b></font><p>";
                $n2s = new num2text($pieces[2]);
                echo "<iframe src=\"http://translate.google.com/translate_tts?tl=en&q=light+is+on.+local+temperature+is+".$n2s."+degrees+celsius+.\" name=\"top\" width=\"320\" marginwidth=\"0\" height=\"50\"></iframe>";
                }
                else if ($pieces[1] == 0) {
                echo "<font face=\"arial, sans-serif\"><b>LIGHT IS OFF</b></font><br>";
                echo "<font face=\"arial, sans-serif\"><b>TEMPERATURE IS ".$pieces[2]."&nbsp;ºC</b></font><p>";
                $n2s = new num2text($pieces[2]);
                echo "<iframe src=\"http://translate.google.com/translate_tts?tl=en&q=light+is+off.+local+temperature+is+".$n2s."+degrees+celsius+.\" name=\"top\" width=\"400\" marginwidth=\"0\" height=\"50\"></iframe>";
                }
        }
      }
?>

NOTE: iframe is used to avoid opening a new page and also problems in starting automatically Google’s voice file not starting automatically. 

The following php class is courtesy of Jay Gilford, it is included in above processing.php and is used to convert numerals into text, to avoid any problems in Google tanslate not recognising numerals as by default %20 is added by the Chrome in the URL

num2text.class.php

<?php
class num2text {
    private $_original = 0;
    private $_parsed_number_text = '';
    private $_single_nums = array(1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five', 6 => 'six', 7 => 'seven', 8 => 'eight', 9 =>
        'nine', );

    private $_teen_nums = array(0 => 'ten', 1 => 'eleven', 2 => 'twelve', 3 => 'thirteen', 4 => 'Fourteen', 5 => 'fifteen', 6 => 'sixteen', 7 =>
        'seventeen', 8 => 'eighteen', 9 => 'nineteen', );

    private $_tens_nums = array(2 => 'twenty', 3 => 'thirty', 4 => 'forty', 5 => 'fifty', 6 => 'sixty', 7 => 'seventy', 8 => 'eighty', 9 =>
        'ninety', );

    private $_chunks_nums = array(1 => 'thousand', 2 => 'million', 3 => 'billion', 4 => 'trillion', 5 => 'quadrillion', 6 => 'quintrillion', 7 =>
        'sextillion', 8 => 'septillion', 9 => 'octillion', 9 => 'nonillion', 9 => 'decillion', );

    function __construct($number) {
        $this->_original = trim($number);
        $this->parse();
    }

    public function parse($new_number = NULL) {
        if($new_number !== NULL) {
            $this->_original = trim($new_number);
        }
        if($this->_original == 0) return 'Zero';

        $num = str_split($this->_original, 1);
        krsort($num);
        $chunks = array_chunk($num, 3);
        krsort($chunks);

        $final_num = array();
        foreach ($chunks as $k => $v) {
            ksort($v);
            $temp = trim($this->_parse_num(implode('', $v)));
            if($temp != '') {
                $final_num[$k] = $temp;
                if (isset($this->_chunks_nums[$k]) && $this->_chunks_nums[$k] != '') {
                    $final_num[$k] .= ' '.$this->_chunks_nums[$k];
                }
            }
        }
        $this->_parsed_number_text = implode(', ', $final_num);
        return $this->_parsed_number_text;
    }

    public function __toString() {
        return $this->_parsed_number_text;
    }

    private function _parse_num($num) {
        $temp = array();
        if (isset($num[2])) {
            if (isset($this->_single_nums[$num[2]])) {
                $temp['h'] = $this->_single_nums[$num[2]].' Hundred';
            }
        }

        if (isset($num[1])) {
            if ($num[1] == 1) {
                $temp['t'] = $this->_teen_nums[$num[0]];
            } else {
                if (isset($this->_tens_nums[$num[1]])) {
                    $temp['t'] = $this->_tens_nums[$num[1]];
                }
            }
        }

        if (!isset($num[1]) || $num[1] != 1) {
            if (isset($this->_single_nums[$num[0]])) {
                if (isset($temp['t'])) {
                    $temp['t'] .= ' '.$this->_single_nums[$num[0]];
                } else {
                    $temp['u'] = $this->_single_nums[$num[0]];
                }
            }
        }
        return implode(' and ', $temp);
    }
}

?>

alert.php

<?php
$page = "script.html";
    header("Refresh: 4; URL=\"" . $page . "\"");
    echo "<hr align='center' size=\"4\" color=\"orange\"><br><b><font face=\"arial, sans-serif\"><font color=blue>OOPS! TRY AGAIN!</b></font></font><p>";
    echo "<iframe src=\"http://translate.google.com/translate_tts?tl=en&q=oops!try+again!\" name=\"top\" width=\"320\" marginwidth=\"0\" height=\"50\"></iframe>";
?>

 

YAWCAM

In order to view the LED switiching on and off a webcam setup is required as in Part I.

Trying out

We are now ready to open index.html. Point your Chrome 11 browser to http://localhost/index.html. Tou may now see the following (after you have directed your webcam to the AXE050 board):

Main Page Showing PICAXE050

Simply click on the microphone and this should prompt you to speak.

Say the words “light on” and if the answer is right processing.php link will be opened. The browser records your voice input, it contacts Google Servers to do the translation into text for you, and the value will be put in the text field. The page processing.php will be opened if everything is OK as shown below:

Page showing LIGHT is on and voice message

In backgroung status.exe and edon.exe will be run for a short duration and a LED on the AXE050 will switch on. The processing page will automatically redirect to index.html page which will now show a live image of AXE050 with a LED switched on:

Main page shows a duly lit LED

If the command is not recognised you will prompted to say it again, as page alert.php will open and you will hear the robotic voice from Google saying “Oops! Try again!”:

Alert of Unrecognised Speech

The page will be shown briefly redirecting to main page index.html. If the command “light on” is repeated, even tough the LED is already on, the following page will be shown:

Already on alert and message

This page will redirect also to index.html.

Now try out the voice command “status” and the page will show the actual status of LED and local temperature:

Local status of LEd and temperature and message

Finally, try voice commands “light off”, “temperature” and “status” when light is both “on”! and “off”. If all is functioning correctly. all these voice commands will be recognised, and there will be interactivity when commands are repeated for cases such as of “light on” and “light off”.

Further work

More vocabulary  of voice recognition can be added improving speech recognition. Databases can be set up, not only to log issued commands, but also to obtain local conditons, and general status. Additional sensors can be added, such as humidity and light (LDR on AXE050 can be used to measure light at certain extaint). Graphs can be displayed, and trigger points set, adding support for email and/or sms when  events or alarms occur.

Conclusions

Voice recognition has been achieved and demonstrated using Google servers (that effectively are becoming Cloud voice servers), obtaining control and interactivity with a real world application. In less than a decade, voice recognition is starting to come to age, although is still not there fully yet. An exciting perspective that opens up, is the near future availability of speech recognition in mobile phones and more and more devices responding to voice commands.

Posted in Uncategorized | 3 Comments

Voice Operated Internet Control of a PICAXE (Part I)

Objectives

Experiment with speech recognition in order to control an electronic device remotely through Internet, and demonstrate new functionalities of Google Chrome 11 browser supporting voice-to-text and HTML5.

Introduction

In April 2011, Google released version 11 of the Chrome browser. One of the most important addition to the new version of Chrome browser is the support for speech recognition. One can enable speech recognition with a simple tag <input type=”text” x-webkit-speech />.

Google is effectively using the WebKit layout engine,  first released as a beta version by Microsoft Windows in September 2008, and the public stable release was released in December 2008.

The electronic setup

AXE050 board with Picaxe18M microcontroller is used. Picaxe products are manufactured by Revolution Education. Here is a picture of AXE050:

AXE050 Board

Note: AXE027 programming serial cable is required. Picaxe-18M uses the same port for programming and serial communication with PC.

The firmware in AXE-050 is the same as we used in Internet Control of a Picaxe (check the link). The idea behind using the same firmware without modifications, is to use it in future voice operated projects (if I get time for them…)

The main server

A Windows-based XAMPP server is installed in the PC. The server is hooked to a local network with a fixed local IP. The application is situated in a network that has no fixed public IP, hence DynDNS services is used. The router routes all external demands to the fixed local IP.

Windows XP and later do not allow easy RS232 control through Internet. To  overcome such a blockage, RS232 control is done through DOS, using Kermit for DOS. Kermit scripts are run by PHP, to control AXE050. Kermit’s executable MSK316.exe is installed in same directory as all files. They will be all in c:\xampp\htdocs (rename the servers default index page to another name)

Note COM2 is used  at baudrate of 4800 setup in Control Pannel of Windows XP.

LED ON Kermit script (name it ledon.ksc):


set port 2
set baud 4800
output c=n
exit 0

This script is called in a BATCH file (name it ledon.bat):


@echo off
c:\xampp\htdocs\msk316 take ledon.ksc
exit

LED OFF Kermit script (name it ledoff.ksc):


set port 2
set baud 4800
output c=f
exit 0

This script is called in a BATCH file (name it ledon.bat):


@echo off
c:\xampp\htdocs\msk31 take ledoff.ksc
exit

All batch files are then converted into .exe using Bat_to_Exe_Converter. So we will have two executables ledon.exe and ledoff.exe in the folder htdocs

Finally the html and php codes…

The html code is based on Romin Irani’s Voice Enabled Web Applications via x-webkit-speech example, that has been adapted to suit the requirements of this actual project.

index.html


<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-language" content="en-US">
<meta charset="utf-8">

<title>Voice Operated Control </title>
<script type="text/javascript">
function checkSpeechSupport(){
var element=document.createElement("input");
if (!('webkitSpeech' in element)) {
alert("Sorry! Your browser does not support the Speech Input");
}
}
function checkanswer() {
var answer = document.getElementById('q2answer').value;

if (answer == 'light on') {

window.location.href = "http://localhost/processing.php?action=on";
}

else if (answer == 'light off') {

window.location.href = "http://localhost/processing.php?action=off";
}

else {

window.open('http://translate.google.com/translate_tts?tl=en&q=oops!%20try%20again%E2%80%9D');

}
}
</script>
</head>
<body onLoad="checkSpeechSupport()">
<form id="speechform">
<fieldset id="inputs">
<font face="arial, verdana"><legend><h2>Voice Control of Picaxe AXE-050U:</h2></legend>
<label for="q2answer">Say "light on" or "light off" command:</label></font>
<input id="q2answer" name="q2answer" type="text" x-webkit-speech onwebkitspeechchange="checkanswer()"/><br/>
<img src="http://localhost:8888/out.jpg">
</fieldset>
</form>
</body>
</html>

processing.php

<?php
//check the GET actions variable to see if something needs to be done
    if (isset($_GET['action'])) {
    //Action has been requested
    //Issue the command we wish to send to the Picaxe
    if ($_GET['action'] == "on") {
        //Turn LED on - for this simple script we are just looking for either a 1 or 0
    $page = "script.html";
    header("Refresh: 2; URL=\"" . $page . "\"");

          echo "<font face=\"arial, sans-serif\"><b>LIGHT ON</b></font>";
          exec("ledon.exe");

     }

     else if ($_GET['action'] == "off") {
     //Turn LED off
     //Now we "open" the serial port so we can write to it
     $page = "script.html";
     header("Refresh: 2; URL=\"" . $page . "\"");

        exec('ledoff.exe');
          echo "<font face=\"arial, sans-serif\"><b>LIGHT OFF</b></font>";
      }

      }
?>

We are almost ready. We need to add video to the main index.html page, In the form section you will see http://localhost:8888/out.jpg. In fact we need to run a video server. Yawam is chosen to show a live image of the status of our AXE050 board.

YAWCAM

In order to view the LED switiching on and off a webcam setup is required. YAWCAM freeware is advised.  Having the requirements mentioned on the YAMCAM website one can easily establish a streaming server on port 8888. If the PC is behind a router the video streaming server port must be opened on the router.

Once YAWCAM is duly working you will need to enable Http and Stream in COntrol Panel of YAWCAM as the following image shows:

Http and Stream enabled

Trying out

We are now ready to open index.html. Point your Chrome 11 browser to http://localhost/index.html. Tou may now see the following (after you have directed your webcam to the AXE050 board):

Main Page Showing PICAXE050

Notice the little microphone shown at the end of the input text field. You will need a duly set up microphone in your PC (I have used an USB microphone). Do not write anything in the input field. Simply click on the microphone and this should prompt you to speak as shown below:

Chrome 11 prompting to speak

Once the browser records your voice input, it contacts Google Servers to do the translation into text for you, and the value will be put in the text field. Say the words “light on” and if the answer is right processing.php link will be opened:

In backgroung ledon.exe will be run for a short duration and a LED on the AXE050 will switch on. The processing page will be automatically redirected to index.html page which will now show a live image of AXE050 with a LED switched on:

Image shows a LED duly lit

If the command is not recognised you will prompted to say it again, as you will hear the robotic voice from Google “Oops! Try again!”. You can disable popup in your Chrome 11 browser if you don’t want popoups that you have to close.

Now we are ready to switch off the LED with voice command “light off”. If the command is recognised, processing.php will be opened again, and the following page will be shown:

In backgroung ledoff.exe will run for a short duration and the LED on the AXE050 will switch off. The processing.php page will be redirected to index.html page which will now show a live image of AXE050 with LED duly off, as we were in our first initial stage.

Conclusion

We have experimented with voice (speech) recognition. The technology has not come to age yet. One has different accents and pronunciations (mine is a big mixture ;) ) and it is a huge task to recognise all of differing human voices. The interaction with devices adds an extra dimension to voice recognition. Chrome 11 browser’s support for speech to text is not well domumented. but gradually its potential is being discovered and shared.

NOTE: Check part II of this project!

Acknowledgements

A special thanks to Max Carter for sharing the orignail PICAXE firmware, and to Romin Irani for his above mentioned  index.html code (duly adapted for purpose of this project).

Posted in Uncategorized | 2 Comments

Fixing: Fatal Error Call To Undefined Function Json_decode

Introduction

On moving to my new CentOS server (with php version 5.1.6), the php code for automatically twitting latest posts from my forums to Twitter stopped working (check the php code here  A Twitbot Using OAUTH).

I will explain below how the errors were determined and fixed. This post may help others to fix a similar problem.

Determine the symptoms

  1. Enable error messages to be shown by writing ini_set( ‘ display_errors ‘,  ‘ 1′);  in your PHP code.
  2. If the error message is “Fatal Error Call to Undefined Function Json_decode ()”, read on… 

The solution by installing JSON PHP Extension

1 . Ssh into your webserver with root privileges

2 .  Install gcc make:
          # yum install gcc make

3 .  Install php-pear and php-devel :
          # yum install php-pear php-devel   

4 .  Install  json:
          # pecl install json

If there are no dependency errors, or other, and all packages duly install you will next:
<

  1. Open your php.ini file  (ex. nano /etc/php.ini)
  2. Find in php.ini a section called Dynamic Extensions
  3. Add a line: extension = json.so
  4. Save php.ini and restart Apache (ex. service httpd restart)

You can check if json is enabled, installing in your httpdocs folder a php file (ex. test.php) with the following code:

<?php
phpinfo();
?>

If you open this page in your browser, you will see information on what your server’s php supports, and surely json will be one fo them:

phpinfo() showing json enabled

Finally test json, with following php code (ex. test_json.php) in your httpdocs folder as shown in  php.net website

<?php
$json = ‘{“a”:1,”b”:2,”c”:3,”d”:4,”e”:5}’;
var_dump(json_decode($json));
var_dump(json_decode($json, true));
?>
 

If you open the file in your browser, the result will be:

object(stdClass)#1 (5) {
["a"] => int(1)
["b"] => int(2)
["c"] => int(3)
["d"] => int(4)
["e"] => int(5)
}
array(5) {
["a"] => int(1)
["b"] => int(2)
["c"] => int(3)
["d"] => int(4)
["e"] => int(5)
}

Json_decode is now working in your server, and there will be no more error reports such as “Fatal Error Call to Undefined Function Json_decode()”.

Posted in Uncategorized | 8 Comments

A Simple Home Alarm System with DAQ and Labview

We all like peace of mind knowing that our home is safe when we are away, at work, or for whatever other reasons. The system here is a simple home alarm system with a motion sensor. The Labview virtual instrument (VI) described here can be easily expanded to a full-fledged alarm system with several sensors, and strategies of detection.

Objectives:

Design a simple alarm system using a PIR (Passive InfraRed) motion sensor that will detect movement on digital input of a DAQ device, and then output an alarm sound using the computer speakers,  sending at the same time a message of intrusion.

Background:

A Passive InfraRed sensor (PIR sensor) is an electronic device that measures infrared (IR) light radiating from objects in its field of view. PIR sensors are often used in the construction of PIR-based motion detectors (see below). Apparent motion is detected when an infrared source with one temperature, such as a human, passes in front of an infrared source with another temperature, such as a wall.(source)

Pre-Requirements:

Labview and DAQmx softwares  installed in your PC, and the DAQ device duly working, and recognised by Labview.

Required Equipment:

NI Labview 2010 Student
NI DAQmx 9.0.2
NI USB-6009 DAQ device
PIR movement sensor C-7288 or similar
Wiring leads


Basic Knowledge:

It is required to have basic knowledge in setting up a simple VI, such as the VI in the project Internet Control of a Labview VI.

The PIR Connections:

The Labview VI:

Build a Labview VI such as shown below. It uses an email SubVI that sends an email notification using SMTP service:

The Labview VI and all the components are available here.

Before Running the VI:

You need to have your DAQ Assistant function correctly set for your DAQ device. Check the above mentioned project Internet Control of a Labview VI.

Next, you need to open the Email_alert_subVI.vi contained in the zipped file just downloaded. You need to set up the SMTP details correctly.

Test the subVI running it, and checking whether you receive the email sent by the subVI. Please note that you have to be online to test the subVI.

 In order to make default the set up constants of SMTP, make current value default in the Block Diagram (e.g. for Sender’s Name constant, right click onto it with mouse, choose Data Operations, and next choose Make Current Value Default, and so on for each constant).

After setting up all constants, save the subVI, and open it, and check if the values you have chosen are shown on your subVIs’s Front Panel. Double check, testing again the subVI ensuring email is sent to you by the subVI.

How it works:

When running continuously the VI, the DAQ device detects motion with PIR sensor. The detected signal generates a 400Hz sinal that is sounded in your PC speakers, and the Intrusion LED on Front Panel of Labview VI is switched on.

The detected signal sends an email alert, using the subVI already set up by you with your SMTC account detals.

The alarm latches, and can be only stopped if you reset it by pressing the RESET button on the Front Panel. After resetting the VI will be ready to detect any new motion.

Tips and Tricks:

  • You can modify the VI in order log each intrusion time to file using a ‘Write To Spreadsheet File.vi’ express VI. There are plenty of examples on Internet on how to do it.
  • Expand your application by integrating more logic into the VI.  Possible scenarios might include a wait of a few seconds after clicking run to give you time to exit your home before the alarm starts to detect motion.
  • You can sent text messages to your cell phone using email to text servies (SMS) such as Clickatell, and many other such services. Normally these services are not free, but they are reliable. They all allow free credit to test your system.
  • You can add an arming feature with keyboard input such as the Home Alarm at Student Projects page  found here.
  • You can also add webcam as a motion detector and record any intrusion. You can find a tutorial with Yawcam. The system will send you also a text message (SMS) making use of a cheap webcam. Press here to see the tutorial.

Acknowledgments:

A special thanks is due to NI Developper Zone for inspiration. The actual project is based on article Dorm Room Alarm System Using a PIR Motion Detector, and following resources:


Posted in Uncategorized | 6 Comments

Internet Control of a Labview VI (Part II)

In part I we have built a simple VI that controls a LED, switching it on or off through a virtual pressure button. We will now show step by step how to launch the application in the Internet and control it remotely.

STEP 23 -  Before anything else, we need to prepare the VI for multiple viewing. To do so in File menu we choose VI proprieties

A new window will open and in this select in Categories drop down menu Execution

A new widow will open and select Reentrant execution as shown in image

Press OK

 STEP 24 -  Next we prepare the webserver. In menu Tools choose Options

In Options window, choose Web Server: Configuration

Enable server by clicking in the choice box on the right of the phrase Enable Web Server.

Press OK.

STEP 25 - Choose now Web Server – Visible VIs, and add switched_usb6009.vi as shown, in the field below the phrase Visible VI. Keep all other defaults as they appear

Press OK

 STEP 26 - We will next prepare the webpage and launch it. Choose Tools -> Web Publishing Tool

In Web Publishing Tool window choose the VI

Press Next after the VI is selected

STEP 27 - Write the title and HTML content as suggested in the image

Press NEXT

STEP 28 - In the next window change the default name of the html file to index. Press Save to Disk button

A new window will open Document URL, press Connect button and then OK

STEP 29 - The webpage will be published and the browser will open

Now with the right button of the mouse placed onto the published VI choose Request Control of VI

STEP 30 - The grayed buttons of the image will now show up. Press the run continuously button

STEP 31 - Now press the virtual button on the VI

The virtual LED on the switch button will light up

The LED Circuit connected to DAQ device will also light up, having thus achieved remote control of the circuit

STEP 32 - Knowing the IP of the PC (and better fixing the IP)  one ought to be open the Labview’s page on the Internet.  If the PC is behind a router, one needs to make the adequate changes in the router, in order toall external demands to the local fixed IP.

One last thing

In order to view the LED switiching on and off a webcam setup is required. In order to stream video YAWCAM freeware is advised.  Having the requirements mentioned on the YAMCAM website one can easily establish a streaming server. If the PC is behind a router the video streaming server port must be opened on the router.

Conclusions

Having designed a VI we have controlled a real world circuit with a virtual button on the VI. We next have achieved Internet control of the VI using the tools that Labview offers.

Posted in Uncategorized | 13 Comments

Internet Control of a Labview VI (Part I)

Introduction

Labview from National Instruments (NI) is build upon a purely graphical, general-purpose programming language, G, with extensive libraries of functions, an integral compiler and debugging, and an application builder for stand-alone applications. The concept of VIs (Virtual Instruments), invented by National Instruments, permits the building of powerful instrumentation and control to run anywhere and everywhere.

Objectives

Making use of Labview and DAQ (Data Acquisition) device, build a VI (Virtual Intrument) with a switch that lights up a LED.  The project is next extended to control the VI from Internet.

Pre-Requirements

Installed Labview and DAQmx softwares, and a DAQ device duly working and recognised by Labview.

Required Equipment

NI Labview 8.6 Student or higher
NI DAQmx 8.6 or higher
NI USB-6009 DAQ device
200 ohms 1/4W resistor
5mm red LED

The Electronic Circuit

Circuit diagram with indications of connections to USB-6009

A Simple VI

STEP 1 - Start Labview

STEP 2 – A new window is opened Getting Started

Getting Started window

STEP 3 – Under Files menu, start a new VI pressing on Blank VI link. It will open the Front Panel of a new untitled blank VI.

Frontal Panel

STEP 4 - On the Front Panel workspace, right click with mouse and choose Controls, Buttons & Switches -> Push Button

Adding push button

Now place the Push Button on the Front Panel workspace

Push button on Front Panel

STEP 5 – On Window menu of Front Panel choose Show Block Diagram

Block Diagram window will be opened. It will already contain the Push Button function

STEP 6 – Right click with mouse the Block Diagram workspace and choose Functions – > Input -> DAQ Assistant

Place adequately the DAQ Assistant function on the Block Diagram workspace. DAQ Assistant will be immediately initialized

STEP 7 - Create New Express Task window will be opened. Choose Generate Signals

STEP 8A sub-menu will be opened. Choose Digital Output

STEP 9 - Another sub-menu will be opened. Choose Line Output.

STEP 10 - A new window will opened. Under Supported Physical Channels choose port0line0

Press Finish

STEP 11 - A new window of DAQ Assistant will be opened

Leave all default values as they are, and press OK.

STEP 12 - Block Diagram will be opened, and VI will be build.

STEP 13 - Block Diagram will have now configured DAQ device.

STEP 14 - Connect Boolean function with data input of DAQ Assistant

The link will be broken with an error message:

“You have connected a scalar type to an array of that type. The type of the source is Boolean (TRUE or FALSE). The type of the sink is 1-D array of Boolean (True or False)”

Hence we need to place the Boolean function in an Array.

STEP 15 - Press the right button of the mouse on the link, and delete the link

The Wire Branch will be removed

Before doing anything else, it is safe to save the VI. Under File menu of the Block Diagram, choose Save as and save the VI as switchled_usb6009.vi

STEP 16 - Press the right button of mouse and choose extra set of Controls clicking the button on the arrow pointing downwards, just below RF Communications controls

Choose Modern -> Array, Matrix & Cluster -> Array

STEP 17 - Place it on the Front Panel workspace

After selecting the Push Button Boolean, drag it and drop into Array box. The Push Button will become part of the Array

STEP 18 - Now select the Block Diagram

Connect the new Array function (containing the Boolean Push Button) to data input of DAQ Assistant function. This time the link will show no error.

STEP 19 - It is a good practise to place the functions within a While Loop with a STOP button.  Right click with mouse button on the Block Diagram, and choose Execution Control – > While Loop

Place the While Loop around Array and DAQ Assistant functions, starting from just on top left of Array function, and ending below DAQ Assistant function allowing automatic placing of stop button that comes with While Loop.

STEP 20 - The Front Panel will contain now a STOP button. Place it appropriately and resize it

STEP 21 - Hopefully it is all OK now and we can save the VI, in Front Panel with File ->  Save

STEP 22Press the virtual button run continuously

and then press the virtual button and the arrow with light up

And so will light up the LED in the real circuit

Conclusions

With just a couple of electronic components and NI tools, we have build step by step a Virtual Instruments (VI).  It is is is quite easy with the graphic programming language of Labview.

We will next control the VI from Internet using the tools that Labview offers.

Posted in Uncategorized | 2 Comments

Access Control with RFID Tags

Introduction

It is quite easy to read IDs of RFID tags, using Parallax’s serial or USB RFID card reader. If you have two RFID cards at least, and of course Parallax RFID reader, you can set up, without hassle, the below described project. This blog contains several articles that show how easy it is, to control and communicate with electronic devices with Processing.

Objectives

Read RFID cards, using serial communications of Processing and Parallax RFID Card Reader, and show  useful information on-screen with user interaction.

Pre-Requirements

Installed Processing environment, RFID Card Reader USB #28340 from Parallax, at least 2 RFID Cards, and a USB cable for connecting between RFID Card Reader and PC.

 

The Experimental Set

 

Connecting to PC

The RFID Card Reader when correctly installed will be shown as a serial device.  Check the port number where the RFID reader is connected in Control Panel - > System – > Hardware tab -> Device Manager button -> Ports (COM and LPT). In this experiment the serial port was COM4. After cheking the port number you just need to take note of it to be introduced into next Processing sketch.

The Processing Sketch

Start a new sketch in Processing, and save it as rfid.pde.

The code for rfid.pde:


// Sketch code based on the one found in "Reading RFID Tags in Processing" chapter
// of the book Making Things Talk published by O'Reilly

import processing.serial.*;

Serial myPort;
String tagID="";

void setup() {
size(350,150);
myPort = new Serial(this, "COM4", 2400);
myPort.buffer(12);

PFont myFont = createFont(PFont.list()[2], 24);
textFont(myFont);
}

void draw(){
background(0);
text(tagID, width/4 + 12, height/2 - 24);
}

void serialEvent(Serial myPort) {
tagID = trim(myPort.readString());
}

Make the adequate COM port changes in your sketch line 8 myPort = new Serial(this, “COM4″, 2400);
to your PC’s installed RFID Card COM port number. Run the sketch and check the TagIDs of both cards. In this case the codes obtained were 34009EA5AF and 0F00296C9FF. The former was chosen as valid card for next sketch. In your case it will be another number.

We will next produce our final sketch. Start a new Sketch in Processing and save it as rfid1.pde

TTS library is required to add voice to the project. TTSLib from GuruBlog is used. Install the unzipped file into your libraries folder of Processing. The library will be imported by Processing. Add image (in this case 100×100 tayeb.jpg is used) to your Processing projects folder, usually found under my Documents\Processing.

Our folder here will be rfid1.

So here is the code for our final rfid1.pde sketch:

// Sketch code based on the one found in "Reading RFID Tags in Processing" chapter
// of the book Making Things Talk published by O'Reilly
// Library TTSLib from GuruBlog found at http://www.local-guru.net/blog/pages/ttslib is required

import processing.serial.*;
import guru.ttslib.*;

TTS tts;
Serial myPort;
String tagID="";

void setup() {
size(350,150);
myPort = new Serial(this, "COM4", 2400);
myPort.buffer(12);

PFont myFont = createFont(PFont.list()[2], 24);
textFont(myFont);
smooth();
tts = new TTS();

}

void draw(){
background(0);

if (tagID.equals("34009EA5AF")) {
PImage b;
b = loadImage("tayeb.jpg");
image(b, 20, 20);
text(tagID, width/2 - 6, height/2 - 24);
text("TAYEB", width/2 - 6, height/2);
}
else {
text(tagID, width/4 + 6, height/2 + 12);
}
}
void serialEvent(Serial myPort) {
tagID = trim(myPort.readString());
if (tagID.equals("34009EA5AF")) {

tts.speak("Hi! Welcome Tayeb!");
}

else {
tts.speak("Invalid Card!");
}
}

Make the adequate changes as shown below in following images:

 

Port number of installed RFID reader

 

Other required changes

 

Now run the sketch. If you read the cards you will hear voice. In this case “Invalid card!” or “Hi Welcome Tayeb!”., or whatever name you have chosen. In our project with sketch code as above, the follow results were drawn on the PC’s screen:

 

Valid card

 

Invalid card

 

In fact any other RFID card, besides the chosen one, will be considered invalid.

Conclusions

Though this actual project is quite simple and the code is not neat, bub it can ve improved. As something extra and quite simple one could add a serial controlled relay or another micrcontroller controlled device.

Of course projects with Visual C#, and other programming languages, can be made to talk to RFID cards, and be quite sophisticated. Some useful RFID projects can be attendance control, stock control, livestock identification, etc.

RFIDs are here to stay, and are everywhere these days. It is quite important to learn to work with them.

Acknowledgements

A special thanks is due to Tom Igoe, author of O’Reilly’s  book“Making Things Talk” for the code with Processing.

Posted in Uncategorized | 2 Comments

Bluemote – remote control of a 8051 robot with bluetooth

Pedro Vicente

About the author:

Pedro Vicente, 21 years old,  is a 3rd year Electrical Engineering student at Institutto Superior Tecnico (IST), Lisbon, Portugal. During the Summer of 2010 spent a month at ALIATRON as a trainee, when among other projects did the one being presented here.  His main interestes are obviously electronics and robotics. His hobby is to play music: he plays piano, and trombone. Pedro is also member of a choir group.

 Introduction

The aim of this project was to experiment with a control system using bluetooth communication, firstly with simple PC control, and then with web control, after setting up a webserver.

A practical example was used: a 8051 robot “Robo-51“, from Inex, and distributed in Portugal by Aliatron. The bluetooth device used was a serial type “ZX-Bluetooth“, also from Inex, and a product sold by Aliatron.

The Experimental Setup

 - Robot-51, Inex
-  Zx-Bluetooth, Inex
-  Bluetooth Micro Adapter Class I, Sweex
-  BlueSoleil 5.4 (software)
-  Termite 2.4 (software)
-  SerialTerm (software)
-  XAMPP server (software)
-  RIDE 51 V6.1 compiler, Raissonance (software)
-  FLIP V2.2, programmer Atmel (software)

Robo-51

Robo-51 from Inex

ZX-Bluetooth

Serial Bluetooth "ZX-Bluetooth" from Inex

Bluetooth Micro Adapter

Class I Bluetooth Micro Adapter from Sweex

The Experiment Itself

An original library of “Robo-51″ for infrared control was modified to interpret the data received from serial bluetooth device “ZX-Bluetooth”. The library named as remoteb.h, has the following code:


/*--------------------------------------------------------------------------*/

// Program             : Decode command from Bluetooth

// Description       : receive command from Bluetooth to control robot

// Filename            : remoteb.h

// C compiler         : RIDE 51 V6.1

// Adapted to bluetooth with baudrate 9600 bps by Pedro Vicente

/*--------------------------------------------------------------------------*/

sbit irm_data = P3^2;          // Define port input remote sensor

unsigned char ir_command=0;         // Define for buffer command from Easy remote

/*****************************************************************************/

/****************** Function Delay for baudrate 9600 *************************/

/*****************************************************************************/

void delay_baud9600()      {                              // Delay baudrate 9600 bps

                unsigned int x,a;                                 // Keep for counter loop

                for(x=0;x<1;x++) {

                                for(a=0;a<91;a++);              // Loop for delay 104 us  // inicially at 833 us

                }

}

/*****************************************************************************/

/****************** Function Delay for baudrate 9600(for start bit) **********/

/*****************************************************************************/

void start_9600()  {                                            // Delay baudrate 9600 while start bit

                unsigned int x,a;                                 // Keep for counter loop

                for(x=0;x<1;x++) {

                                for(a=0;a<46;a++);              // Loop for delay 53us //inicially at 416 us

                }

}

/*****************************************************************************/
/************* Service interrupt routine for receive command ******************/
/*****************************************************************************/
void service_ex0(void) interrupt 0 {
unsigned char i;   // Define for counter loop
if(irm_data==0) {   // Check start bit true?
  		start_9600();  		// Delay for start bit
  		for(i=0;i<8;i++)  {		// For loop count 8 time(for receive data 8 bit)
  			delay_baud9600(); 		// Delay for data 1 bit
  			ir_command = ir_command>>1;		// Shift data bit to right 1 time
  			if(irm_data)				// If data bit = high
  			ir_command = ir_command | 0x80;		// Config data bit = "1"
  		}
		delay_baud9600();				// Delay for stop bit
	}
}
/*****************************************************************************/
/************** Function read Command from Bluetooth ***********************/
/*****************************************************************************/
unsigned char get_remote(void) {
	return(ir_command);		// Return command
}
/*****************************************************************************/
/*********************** Function clear command ******************************/
/*****************************************************************************/
void clear_remote() {
	ir_command = 0;         // Clear command
}

/*****************************************************************************/
/*********************** Function initial for Bluetooth ********************/
/*****************************************************************************/
void remote_init(void) {
	irm_data = 1;   	// Configuration input P3.2
	EX0 = 1;        	// Enable External interrupt0
	IT0 = 1;         	 // Detect falling edge
	EA = 1;		// Enable interrupt all
}

Next a firmwware program in C was written for the 8051 microcontroller in “Robo-51″, named as act19_bl.c:


/*--------------------------------------------------------------------------*/

// Program: Remote control robot

// Description : Robot controlled by Bluetooth control

//Robot receive command  from bluetooth by serial communication at baudrate 9600 bps 

// Filename: Bluemote.c

// C compiler: RIDE 51 V6.1

/*--------------------------------------------------------------------------*/

#include <C51ac2.h>                          // Header include register of T89C51AC2

#include <delay_robo51.h>              // Module function delay process

#include <dc_motor.h>                      // Module function drive DC motor

#include <remoteb.h>                        // Module function for remote

#include <sound_robo51.h>            // Module function drive sound

#include <lcd_robo51.h>                   // Module function LCD

#define pow 200                                  // Define constant for power drive DC motor

void run_fd(int time_spin) {

                motor_fd(2,pow);                                // Motor channel 2 forward

                motor_fd(1,pow);                                // Motor channel 1 forward

                delay_ms(time_spin);                        // Delay time for robot drive forward

}

void run_bk(int time_spin) {

                motor_bk(2,pow);                               // Motor channel 2 backward

                motor_bk(1,pow);                               // Motor channel 1 backward

                delay_ms(time_spin);                         // Delay time for robot drive backward

}

void turn_left(int time_spin) {

                motor_fd(2,pow);                                // Motor channel 2 forward

                motor_bk(1,pow);                               // Motor channel 1 backward

                delay_ms(time_spin);                         // Delay time for robot spin turn left

}

void turn_right(int time_spin) {

                motor_bk(2,pow);                               // Motor channel 2 backward

                motor_fd(1,pow);                                // Motor channel 1 forward

                delay_ms(time_spin);                         // Delay time for robot spin turn right

}

void main() {

beep();                                                  // Sound beep 1 time

                remote_init();                                       // Initial remote

                lcd_init();                                             // Initial Lcd

                while(1)  {                                            // Infinite loop

                                switch(get_remote()) {       // Check command for receive

                               case 'a'  :run_bk(100);         // Drive robot backward when receive command "a" 

                                               clear_remote();     // Clear command

                                               break;                    // Out from case

                               case 'b' : turn_right(100);                   // Turn right when receive command "b"

                                               clear_remote();                    // Clear command

                                               break;                                    // Out from case

                               case 'c' : turn_left(100);                      // Turn right when receive command "c"

                                               clear_remote();                    // Clear command

                                               break;                                    // Out from case

                               case 'd' : run_fd(100);                         // Turn right when receive command "d"

                                               clear_remote();                    // Clear command

                                               break;                                    // Out from case

                               case 's':  motor_stop(all);                  // robot stop

                                               clear_remote();                    // Clear command

                                               break;                                    // Out from case

                               default:  break;                                    // Out from case

                               }

}

For more details on the main program, plus programming the robot “Robo-51,” and many other applications for the robot, check the “Robo-51″ manual  found at Inex’s online site. You will find there the other required libraries which will be needed to be included into the project.

We use the software RIDE from Raissonance to compile the above *.c file (plus the library *.h), and the Atmel’s software FLIP from Atmel to load the program into the 8051 microcontroller of “Robo-51″.

To test the program in 8051, Termite 2.4 and SerialTerm were used. Both programs are used to test serial communications in micrcontrollers, and were quite handy in this case. Commands were sent to the robot, by writing on the keyboard. (check below first part of the video)

Important Note:  Set serial ports with baudrate at 9600 bps as ZX-Bluetooth works only at this baud rate. In our case the serial port used was COM2.

 The next step would be to make automatic the sending of commands, instead of writting the commands and pressing Click or ENTER. We used the following Visual Basic Scripts (VBS) to send the commands. This VBS  procedure was proposed by Bill Blanton in the GNT forum. These VBS send commands with ley letters “d”  for foward, “a” for backward, “c” for turning leftwards, “b” for turning rightwards and “s” for stopping.


/*--------------------------------------------------------------------------*/

// Program: Send letter to serial port

// Description: Send “d” to serial port to move foward

// Filename: fw.vbs

/*--------------------------------------------------------------------------*/

Set oShell = WScript.CreateObject("WScript.Shell")

oShell.Run("C:\r51\serialterm com2 9600")

WScript.Sleep(500) 'wait (0.5 seconds (# milliseconds))

oShell.Sendkeys "d"

oShell.Sendkeys"{ESC}"

 


/*--------------------------------------------------------------------------*/

// Program: Send letter to serial port

// Description: Send “a” to serial port to move backward

// Filename: bk.vbs

/*--------------------------------------------------------------------------*/

Set oShell = WScript.CreateObject("WScript.Shell")

oShell.Run ("C:\r51\serialterm com2 9600")

WScript.Sleep(500) 'wait (0.5 seconds (# milliseconds))

oShell.Sendkeys "a"

oShell.Sendkeys"{ESC}"

 


/*--------------------------------------------------------------------------*/

// Program: Send letter to serial port

// Description: Send “b” to serial port to turn rigth

// Filename: rg.vbs

/*--------------------------------------------------------------------------*/

Set oShell = WScript.CreateObject("WScript.Shell")

oShell.Run ("C:\r51\serialterm com2 9600")

WScript.Sleep(500) 'wait (0.5 seconds (# milliseconds))

oShell.Sendkeys "b"

oShell.Sendkeys"{ESC}"

 


/*--------------------------------------------------------------------------*/

// Program: Send letter to serial port

// Description: Send “c” to serial port to turn left

// Filename: lf.vbs

/*--------------------------------------------------------------------------*/

Set oShell = WScript.CreateObject("WScript.Shell")

oShell.Run ("C:\r51\serialterm com2 9600")

WScript.Sleep(500) 'wait (0.5 seconds (# milliseconds))

oShell.Sendkeys "c"

oShell.Sendkeys"{ESC}"

 


/*--------------------------------------------------------------------------*/

// Program: Send letter to serial port

// Description: Send “s” to serial port to stop

// Filename: st.vbs

/*--------------------------------------------------------------------------*/

Set oShell = WScript.CreateObject("WScript.Shell")

oShell.Run ("C:\r51\serialterm com2 9600")

WScript.Sleep(500) 'wait (0.5 seconds (# milliseconds))

oShell.Sendkeys "s"

oShell.Sendkeys"{ESC}"

Having achieved PC control of  “Robo-51″, a web server was setup in order to control de robot though Internet. The Internet control of “Robo-51″ was achieved with an approach based on published work here Internet Control of a Picaxe by Tayeb Habib.

The main server

A Windows-based XAMPP server was installed in a PC. The server was hooked to a local network with a fixed local IP. The application being situated in a network that had no fixed public IP, DynDNS services were used. The router routes all external demands to the local fixed IP.

Windows XP and later do not allow easy RS232 control through Internet. To  overcome such a blockage, RS232 control was done through DOS, using SerialTerm as mentioned above. The VB scripts of above were run in php, and used to command “Robo-51″. All of following files were placed in c:\xampp\htdocs

index.php

<? php
echo "<head><title>Internet Control of a 8051 Robot</title></head>
<body>
<center>
<font face=\"arial, sans-serif\" color=>
<h2 align='center'><font color=\"#4992BB\">Internet Control of a 8051 Robot</font></h2>
<hr align='center' size=\"4\" color=\"#4992BB\"><center>
<TABLE WIDTH=150 BORDER=0 CELLPADDING=0>
<TR> <TH COLSPAN=3><font face=\"arial, verdana\" color=\"#4992BB\">Bluemote</font></TH> </TR>
<TR> <TD></TD>      <TD><a href='processing.php?action=fw'>
<img src='forw.gif' border='0'></a></TD> <TD></TD>   </TR>
<TR> <TD><a href='processing.php?action=rg'> <img src='right.gif' border='0'></a></TD>     
<TD> <a href='processing.php?action=st'><img src='stop.gif' border='0'></TD>
<TD><a href='processing.php?action=lf'> <img src='left.gif' border='0'></a></TD></TR>
<TR> <TD></TD>  <TD><a href='processing.php?action=bk'>
<img src='back.gif' border='0'></a></TD> <TD></TD></TR>
</TABLE></center>
<hr align='center' size=\"4\" color=\"#4992BB\">

</center>
</body>

processing.php


<?php 

//check the GET actions variable to see if something needs to be done 

if (isset($_GET['action'])) { 
//Action has been requested 

  
  if ($_GET['action'] == "fw") { 

    $page = "index.php"; 

     header("Refresh: 2; URL=\"" . $page . "\""); 

     exec ('C:\r51\fw.vbs'); 

      echo "
          <hr align='center' size=\"4\" color=\"#4992BB\"><center>
      <font face=\"arial, sans-serif\"><b>Moving Forward</b></font>"; 

      } 

     else if ($_GET['action'] == "bk") { 

     $page = "index.php"; 

     header("Refresh: 2; URL=\"" . $page . "\""); 

     exec ('C:\r51\bk.vbs'); 

    echo "
    <hr align='center' size=\"4\" color=\"#4992BB\"><center>
    <font face=\"arial, sans-serif\"><b>Moving Backward</b></font>"; 
    }
     else if ($_GET['action'] == "st") { 

     $page = "index.php"; 

     header("Refresh: 2; URL=\"" . $page . "\""); 

     exec ('C:\r51\st.vbs'); 

    echo "
    <hr align='center' size=\"4\" color=\"#4992BB\"><center>
    <font face=\"arial, sans-serif\"><b>Stopping...</b></font>"; 
    }  
     else if ($_GET['action'] == "rg") { 

     $page = "index.php"; 

     header("Refresh: 2; URL=\"" . $page . "\""); 

     exec ('C:\r51\rg.vbs'); 

    echo "
    <hr align='center' size=\"4\" color=\"#4992BB\"><center>
    <font face=\"arial, sans-serif\"><b>Turning Right</b></font>"; 
    }
     else if ($_GET['action'] == "lf") { 

     $page = "index.php"; 

     header("Refresh: 2; URL=\"" . $page . "\""); 

     exec ('C:\r51\lf.vbs'); 

    echo "
    <hr align='center' size=\"4\" color=\"#4992BB\"><center>
    <font face=\"arial, sans-serif\"><b>Turning Left</b></font>"; 
    }  
    }
?>

Please note that *.vbs files must be in c:\r51  as can be seen in above VB scripts.

Finally the XAMPP server must be tested pointing the browser to http://localhost. If all is OK the server can be put online.

Hull report is available at:

http://aliatron.com/download/Bluemote_English.pdf (18MB)

A simulation of the application (useful to see how the appplication will look like) can be viewed at:

http://aliatron.dynalias.com/r51

The following video shows the application with “Robo-51″:

Acknowledgments

A special thank you is due to Tayeb Habib owner of Aliatron and my supervisor for Summer traineeship at that portuguese company. Also I thank my former workmate at Aliatron, Raquel, for all the support and her welcome spirit.

Published in RedAcacia by Tayeb

Posted in Uncategorized | 2 Comments

Controlling a robot with bluetooth-enabled cell phone

Tested on Nokia N97 and Blackberry Bold 9700.

Introduction

After having recently designed a virtual gamepad to control a robot, making use of a serial bluetooth device, I thought why not do the same with a cell phone.

My Nokia N97 has bluetooth and using it to control the robot seemed to be the most attractive proposal.

My first development tool was Psy60 (Nokia’s Python), to control the robot, but soon I found out that the bluetooth libraries seemed to be geared towards controlling a PC.

So, effectively having gained experience with Processing, my next immediate thought was to use Mobile Processing, after having read about a Roomba hacking and a patch for serial bluetooth library.

Please check addenda below: tested and verified on Blackberry Bold 9700.

Required equipment

 A 8051 robot “Robo-51” (could be a robot with any other micrcontroller) with ZX-Bluetooth module, running a firmware for bluetooth control (or any other serial control), and PC with Windows and Mobile Processing software.

Robo-51
8051-based robot “Robo-51″
Serial bluetooth module “ZX-Bluetooth”

Please check the Virtual Gamepad project. The sketch as explained in the first part of code is based on the Roomba hacking and ideas from a NXT Symbian project.  It uses the patched bluetooth library of Roomba project. All the patch does is to allow one to specify short UUIDs when searching bluetooth devices.

Mobile Processing Sketch

So here is the sketch:

// Based on original code Tic-Tac-Toe code by Francis Li, found at
// http://mobile.processing.org/learning/example.php?name=tictactoe
// and on roombaCtrl by Tod E. Kurt, tod@todbot.com
// http://roombahacking.com, and extra coding ideas from
// Pedro Miguel, ap0cn3t@gmail.com http://nxt-symbian.sourceforge.net
// code adapted for Robo-51 by Tayeb Habib, tayeb.habib@gmail.com
// http://redacacia.wordpress.com (check the site for more projects)
// compatibility tested for Nokia N97

// This needs my patched bluetooth library that allows short UUIDs
// found at http://roombahacking.com

import processing.bluetooth.*;

// state machine sates
final int STATE_START    = 0;
final int STATE_FIND     = 1;
final int STATE_DRIVE    = 2;

// state machine state var
int state;

// bluetooth library
Bluetooth bt;
// discovered services
Service[] services;
// status message
String msg;
// connection to robo51
Client cl;

PFont font;

// ------------------------------------------------------------------
// robo51 opcodes
// ------------------------------------------------------------------

byte[] fwd = new byte[]{ (byte)0x64 };   // ascii key letter "d"
byte[] bwd = new byte[]{ (byte)0x61 };   // ascii key letter "a"
byte[] left = new byte[]{ (byte)0x63 };   // ascii key letter "c"
byte[] right = new byte[]{ (byte)0x62 };   // ascii key letter "b"
byte[] stop = new byte[]{ (byte)0x73  };   // ascii key letter "s"

///
void setup() {
  font = loadFont();
  textFont(font);
  bt = new Bluetooth(this, Bluetooth.UUID_SERIALPORT);
  state = STATE_START;
}

void destroy() {
  background(255);
  fill(0);
  text("Exiting...", 2, 2, width - 4, height - 4);
  bt.stop();
}

//
void draw() {
  background(0xcc,0xcc,0xff);

  if (state == STATE_START) {
    fill(0);
    textAlign(LEFT);
    text("Welcome to Robo-51\n\nPress a key to search the robot", 2, 2, width - 4, height - 4);
  }
  else if (state == STATE_FIND) {
    fill(0);
    textAlign(LEFT);
    if (services == null) {
      text("Looking for Robo-51...\n\n" + msg, 2, 2, width-4, height-4);
    }
    else {
      String list = "Ports found:\n";
      for (int i = 0, len = length(services); i < len; i++)
        list += i + ". " + services[i].device.name + "\n";
      text(list, 2, 2, width-4, height-4);
    }
  }
  else if (state == STATE_DRIVE) {
    noFill();
    text("Robo-51 control:\n"+
         "Use arrows to drive\n"+
         "press A, or B, or C, or D to stop\n"+
         msg, 2, 2, width-4, height-4);
  }

}

//
void libraryEvent(Object library, int event, Object data) {
  if (library == bt) {
    switch (event) {
    case Bluetooth.EVENT_DISCOVER_DEVICE:
      msg = "Found device at: " + ((Device) data).address + "...";
      break;
    case Bluetooth.EVENT_DISCOVER_DEVICE_COMPLETED:
      msg = "Found " + length((Device[]) data) + " devices, looking for serial port...";
      break;
    case Bluetooth.EVENT_DISCOVER_SERVICE:
      msg = "Found serial port on " + ((Service[]) data)[0].device.address + "...";
      break;
    case Bluetooth.EVENT_DISCOVER_SERVICE_COMPLETED:
      services = (Service[]) data;
      msg = "Search complete. Pick one.";
      break;
    case Bluetooth.EVENT_CLIENT_CONNECTED:
      cl = (Client) data;
      msg = "wtf. client connectd.";
      break;
    }
  }
}

//

//
void keyPressed() {
  if (state == STATE_START) {
    services = null;
    bt.find();
    state = STATE_FIND;
    msg = "Looking for devices...";
  }
  else if (state == STATE_FIND) {
    if (services != null) {
      if ((key >= '0') && (key <= '9')) {
        int i = key - '0';
        if (i < length(services)) {
          msg = "connecting...";
          cl = services[i].connect();
          state = STATE_DRIVE;
          msg = "ready";
        }
      }
    }
  }
  else if (state == STATE_DRIVE) {

    parse_robo51key(keyCode,key);

  }

}

void parse_robo51key(int akeyCode, int akey) {
  switch(akeyCode) {
    case UP:
      msg = "forward";
      robo51_send(fwd);
      break;
    case DOWN:
      msg = "backward";
      robo51_send(bwd);
      break;
    case LEFT:
      msg = "left";
      robo51_send(left);
      break;
    case RIGHT:
      msg = "right";
      robo51_send(right);
      break;
    case CENTER:
      msg = "stop";
      robo51_send(stop);
      break;
    default:
      msg = "stop";
      robo51_send(stop);
      break;

    } // switch(keyCode)
}

void robo51_send(byte[] buffer){
  cl.write(buffer);
  cl.flush();
}

Deploying

If you are absolute beginner with Mobile Processing I suggest you follow the tutorial “How to write apps with Mobile Processing on your N95” (if the link does not work please check: Mobile Application Development with Mobile Processing) . The tutorial will teach you how to make simple Mobile Processing applications and to deploy into your cell phone.

The control program

The program controls Robo-51 from Inex with the commands:

Key letter “d” foward, “a” backwards, “c” turn leftwards, “b” turn rightwards and “s” stop.  The commands are defined in the above sketch under “Robo-51 opcodes”. Arrow keys on N97 keyboard control the robot. The key ENTER on the N97 keyboard is used as FIRE button to stop the robot

When the program is launched, after it identifies the bluetooth devices, SPP device will appear with appropriate number 0, 1, 2 or whatever tag before it. One has to choose SPP with numeric option on N97 keyboard.

The firmware that accepts commands in above sketch was written by Pedro Vicente, a Summer vacation trainee in my company Aliatron. Pedro has already published his project here. The following video, recently published in youtube by Raquel (Pedro’s girlfriend), shows “Robo-51″ in action:

The program on the PC’s screen shown in the video is an application written by Pedro that allows web control of Robo-51.

I hope to next control the robot with a Psy60 program.  When it is done, I will publish it here. I have mentioned N97 as the program was tested with Nokia’s N97. Perhaps the program will work perfectly in other Nokia cell phones with Symbian OS (N97′s OS is Symbian).

——————————

Addenda on 06/07/2011:

I have tested the unaltered jar file made for Nokia N97, on my Blackberry Bold 9700 (v.6.6.0.124) by installing the jar file, after copying it into the cell phone’s memory. The robot responded well, and moved forward, backward, left and right, and stopped as expected with respective voice indicating the action. All the movements of the robot were made by playing with Blackberry’s joystick, i.e. track pad. The bluetooth connection of the Blackberry and the robot’s bluetooth serial module were duly detected. When the bluetooth connection on the Blackberry was not on, the cell phone asked for permission to switch it on, as was expected. Summing up: a fully satisfactory control of the robot is achieved with Blackberry Bold 9700. Implementations in other Bloackberry cell phones should give similar results.

——————————-

Addenda on 09/17/2010:

Adding sound to the robot control

In my previous project of Virtual Gamepad text-to-speech was added and so something similar would be interesting. So, effectively that’s what I did this time.

Text-to-speech

Though Nokia N97 supports text-to-speech, Mobile Processing has no library, as Psy60 has.

I didn’t want to record sounds and make them sound “robotic”, so I searched the Web, and found a freeware that does it. Download “TTSReader” and create .wav files for all the commands. All commands can be downloaded here (you will need 7z to uncompress):

Sound files

Copy these files into a sub-directory that you will name data in your MobileProcessing project folder (found normally under c:\my documents\.

Now you are ready to follow the above steps with following new Mobile Processing sketch:


// New sketch with sound support
// Based on original code Tic-Tac-Toe code by Francis Li, found at
// http://mobile.processing.org/learning/example.php?name=tictactoe
// and on roombaCtrl by Tod E. Kurt, tod@todbot.com
// http://roombahacking.com, and extra coding ideas from
// Pedro Miguel, ap0cn3t@gmail.com http://nxt-symbian.sourceforge.net
// code adapted for Robo-51 by Tayeb Habib, tayeb.habib@gmail.com
// http://redacacia.wordpress.com (check the site for more projects)
// compatibility tested for Nokia N97

// This needs my patched bluetooth library that allows short UUIDs
// found at http://roombahacking.com and msound library found at
// http://mjs.darkgreenmedia.com/site/

import processing.bluetooth.*;
import mjs.processing.mobile.msound.*;

MSound mySound;

// state machine sates
final int STATE_START    = 0;
final int STATE_FIND     = 1;
final int STATE_DRIVE    = 2;

// state machine state var
int state;

// bluetooth library
Bluetooth bt;
// discovered services
Service[] services;
// status message
String msg;
// connection to robo51
Client cl;
PFont font;

// ------------------------------------------------------------------
// robo51 opcodes
// ------------------------------------------------------------------

byte[] fwd = new byte[]{ (byte)0x64 };   // ascii key letter "d"
byte[] bwd = new byte[]{ (byte)0x61 };   // ascii key letter "a"
byte[] left = new byte[]{ (byte)0x63 };   // ascii key letter "c"
byte[] right = new byte[]{ (byte)0x62 };   // ascii key letter "b"
byte[] stop = new byte[]{ (byte)0x73  };   // ascii key letter "s"

///
void setup() {
  font = loadFont();
  textFont(font);
  bt = new Bluetooth(this, Bluetooth.UUID_SERIALPORT);
  state = STATE_START;
  mySound = MSoundManager.loadSound("start.wav");
  mySound.play();
}

void destroy() {
  background(255);
  fill(0);
  text("Exiting...", 2, 2, width - 4, height - 4);
  bt.stop();
}

//
void draw() {
  background(0xcc,0xcc,0xff);

  if (state == STATE_START) {
    fill(0);
    textAlign(LEFT);
    text("Welcome to Robo-51\n\nPress a key to search the robot", 2, 2, width - 4, height - 4);
  }
  else if (state == STATE_FIND) {
    fill(0);
    textAlign(LEFT);
    if (services == null) {
      text("Looking for Robo-51...\n\n" + msg, 2, 2, width-4, height-4);
    }
    else {
      String list = "Ports found:\n";
      for (int i = 0, len = length(services); i < len; i++)
        list += i + ". " + services[i].device.name + "\n";
      text(list, 2, 2, width-4, height-4);
    }
  }
  else if (state == STATE_DRIVE) {
    noFill();
    text("Robo-51 control:\n"+
         "Use arrows to drive\n"+
         "press ENTER to stop\n"+
         msg, 2, 2, width-4, height-4);
  }

}

//
void libraryEvent(Object library, int event, Object data) {
  if (library == bt) {
    switch (event) {
    case Bluetooth.EVENT_DISCOVER_DEVICE:
      msg = "Found device at: " + ((Device) data).address + "...";
      break;
    case Bluetooth.EVENT_DISCOVER_DEVICE_COMPLETED:
      msg = "Found " + length((Device[]) data) + " devices, looking for serial port...";
      break;
    case Bluetooth.EVENT_DISCOVER_SERVICE:
      msg = "Found serial port on " + ((Service[]) data)[0].device.address + "...";
      break;
    case Bluetooth.EVENT_DISCOVER_SERVICE_COMPLETED:
      services = (Service[]) data;
      msg = "Search complete. Pick one.";
      break;
    case Bluetooth.EVENT_CLIENT_CONNECTED:
      cl = (Client) data;
      msg = "wtf. client connectd.";

      break;
    }
  }
}

//

//
void keyPressed() {
  if (state == STATE_START) {
    services = null;
    bt.find();
    state = STATE_FIND;
    msg = "Looking for devices...";
  }
  else if (state == STATE_FIND) {
    if (services != null) {
      if ((key >= '0') && (key <= '9')) {
        int i = key - '0';
        if (i < length(services)) {
          msg = "connecting...";
          cl = services[i].connect();
          state = STATE_DRIVE;
          msg = "ready";
        }
      }
    }
  }
  else if (state == STATE_DRIVE) {

    parse_robo51key(keyCode,key);

  }

}

void parse_robo51key(int akeyCode, int akey) {
  switch(akeyCode) {
    case UP:
      mySound = MSoundManager.loadSound("forward.wav");
      mySound.play();
      msg = "forward";
      robo51_send(fwd);
      break;
    case DOWN:
      mySound = MSoundManager.loadSound("backward.wav");
      mySound.play();
      msg = "backward";
      robo51_send(bwd);
      break;
    case LEFT:
      mySound = MSoundManager.loadSound("left.wav");
      mySound.play();
      msg = "left";
      robo51_send(left);
      break;
    case RIGHT:
      mySound = MSoundManager.loadSound("right.wav");
      mySound.play();
      msg = "right";
      robo51_send(right);
      break;
    case FIRE:
      mySound = MSoundManager.loadSound("stop.wav");
      mySound.play();
      msg = "stop";
      robo51_send(stop);
      break;
    default:
      mySound = MSoundManager.loadSound("stop.wav");
      mySound.play();
      msg = "stop";
      robo51_send(stop);
      break;

    } // switch(keyCode)
}

void robo51_send(byte[] buffer){
  cl.write(buffer);
  cl.flush();
}

You will now need to Export and Deploy! That’s it!
After installing in your cell phone you will now have a very interactive control. Have fun!

Posted in Uncategorized | 3 Comments

Bluemote – A Virtual Gamepad for Bluetooth Control of a Robot

This application was born after a student trainee, Pedro Vicente, spent his Summer at my company Aliatron and did a technical project with a 8051-based robot “Robo-51″ from Inex . Pedro has already published here in this blog, his work that is based on remote control of a robot with bluetooth.

Objectives:

Use Processing sketch to create a virtual gamepad that controls a bluetooth-enabled robot, in this case a Robo-51 from Inex. The virtual gamepad must control the robot using serial communication capabilities of a bluetooth module (ZX-Bluetooth). Voice-enable the gamepad with TTS capabilities of Windows.

Equipment Setup:

A 8051 robot “Robo-51″ (could be any other micrcontroller) with ZX-Bluetooth module, running a firmware for bluetooth control (or any other serial control), and PC with Windows and Processing software.

Robo-51

8051-based robot "Robo-51"

Serial bluetooth module "ZX-Bluetooth"

 Bluemote – Virtual Gamepad:

The  sketch in Processing named bluemote has the following code:


import processing.serial.*;     //Import serial library
import guru.ttslib.*;           //Import tts text-to-voice library
// Based on serial example of Processing 1.2.1. To be used with
// 8051 "Robo-51" from INEX, bluetooth enabled wihZX-Bluetooth 
// Sketch by Tayeb tayeb.habib@gmail.com www.redacacia.wordpress.com
// This sketch uses ttslib for sound, library downloadable at
// www.local-guru.net/blog/pages/ttslib

PImage bg;      // Create object from PImage class
Serial myPort;  // Create object from Serial class
TTS tts;        // Create object from Tts class

void setup()
{
  size(318, 184);                             // Sketch of same size as gamepad image                      
 
  myPort = new Serial(this, "COM5", 9600);    // Set comm port
  bg = loadImage("bluemote.jpg");             // Load bluemote image
  tts = new TTS();                            // Create an instance of the TTS class
  tts.speak("Hi! I am Robot Fifty-One");      // Call the speak method
  tts.speak("I am at your orders! Boss!");    // Call the speak method
}
void draw() {
  background(bg);                 // Load bluemote gamepad image as background
 
  if ((mouseOverForw() == true) && mousePressed) {  // If mouse is pressed and over forward button,
    cursor(HAND);                 // Hand cursor
    myPort.write("d");            // Send letter d for forward movement of robot
    tts.speak("Forward");         // Call the speak method
  }
 
  else if ((mouseOverBack() == true) && mousePressed) {  // If mouse is pressed and over backward button,
    cursor(HAND);                 // Hand cursor
    myPort.write("a");            // Send letter c to turn the robot leftwards
    tts.speak("Backward");        // Call the speak method
  }
 
  else if ((mouseOverLeft() == true) && mousePressed){  // If mouse is pressed and over left button,
    cursor(HAND);                 // Hand cursor
    myPort.write("c");            // Send letter c to turn the robot rightwards
    tts.speak("Left");            // Call the speak method
   }
  
  else if ((mouseOverRight() == true) && mousePressed) {  // If mouse is pressed and over right button,
   cursor(HAND);                 // Hand cursor
   myPort.write("b");            // Send letter b to turn the robot rightwards
   tts.speak("Right");           // Call the speak method
   }
  
  else if ((mouseOverStop() == true) && mousePressed){  // If mouse is pressed and over stop button,
   cursor(HAND);                 // Hand cursor
   myPort.write("s");            // Send letter s to stop the robot
   tts.speak("Stopping");        // Call the speak method
   }

  else {
  cursor(HAND);                   // Hand cursor
  }  
}

  boolean mouseOverForw() { // Test if mouse is over control button
  return ((mouseX >= 240) && (mouseX <= 256) && (mouseY >= 63) && (mouseY <= 78));
}
  boolean mouseOverBack() { // Test if mouse is over control button
  return ((mouseX >= 240 ) && (mouseX <= 256) && (mouseY >= 106) && (mouseY <= 121)); 
}
  boolean mouseOverLeft() { // Test if mouse is over control button
  return ((mouseX >= 218) && (mouseX <= 228) && (mouseY >= 84) && (mouseY <= 98)); 
}
  boolean mouseOverRight() { // Test if mouse is over control button
  return ((mouseX >= 272) && (mouseX <= 287) && (mouseY >= 74) && (mouseY <= 96)); 
}      
  boolean mouseOverStop() { // Test if mouse is over stop button
  return ((mouseX >= 47) && (mouseX <= 108) && (mouseY >= 78) && (mouseY <= 132));     
}

Appropriate changes will be required according to the setup namely:

the serial port:  in our case it is COM5, in your case it could be another port

the commands: in our case they are d for forward, a for backwards, c for leftwards, b for rightwards andfor stopping.

The sketch calls a TTS library (link shown within the code) and uploads a background image. The gamepad image that has been used for this sketch is:

Bluemote

Just download it and add to your project folder ususally found within c:/my documents/processing

The 8051-robot firmware and bluetooth:

Pedro Vicente, mentioned above, has published here the whole project envolving the 8051-based robot “Robo-51″ and bluetooth. In fact the virtual gamepad can function through any serial connection to any micrcontroller. The commands and the serial port have to be adapted in the sketch.

View a video of Virtual Gamepad and Robo-51:

Conclusions:

Serial communciations library, and other libraries in Processing, offer enormous potential in adding interactivity to electronic projects. Bluemote, the virtual gamepad that has been explained here is an example of how easy it is to make electronic projects to talk and interact with the environment.

Posted in Uncategorized | 1 Comment