📄 x8561.htm
字号:
<HTML
><HEAD
><TITLE
>Any coffee left?</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.64
"><LINK
REL="HOME"
TITLE="Programming Jabber"
HREF="book1.htm"><LINK
REL="UP"
TITLE="Extending Messages, Groupchat, Components, and Event Models"
HREF="c7982.htm"><LINK
REL="PREVIOUS"
TITLE="Keyword assistant"
HREF="x8004.htm"><LINK
REL="NEXT"
TITLE="RSS punter"
HREF="x9016.htm"></HEAD
><BODY
CLASS="SECT1"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming Jabber</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x8004.htm"
>Prev</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Chapter 8. Extending Messages, Groupchat, Components, and Event Models</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x9016.htm"
>Next</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="JABTDG-CH-8-SECT-2"
>Any coffee left?</A
></H1
><P
>LEGO Mindstorms. What a great reason to dig out that box of LEGO that
you haven't touched since your childhood. What? You're still in your
childhood? Even better! When I found out that LEGO was bringing out a
programmable brick - the RCX, I went straight to Hamley's on Regent Street
and handed over some well-earned cash for a large box containing the
RCX—a yellow lump of plastic with buttons, an LCD, and connectors for
sensors and motors—an infrared (IR) port plus an IR tower to connect to
the serial port of your PC, and a battery compartment.
<A
NAME="AEN8564"
HREF="#FTN.AEN8564"
>[1]</A
>
The box also contained a couple of motors, touch and light sensors,
and various LEGO Technic parts.
The RCX is pictured in <A
HREF="x8561.htm#JABTDG-CH-8-FIG-3"
>Figure 8-1</A
>.</P
><DIV
CLASS="FIGURE"
><A
NAME="JABTDG-CH-8-FIG-3"
></A
><P
><B
>Figure 8-1. The LEGO Mindstorms RCX, or "programmable brick"</B
></P
><P
><IMG
SRC="CH-8-FIG-3.jpg"></P
></DIV
><P
>There are plenty of ways of interacting with the RCX, also known as the
"programmable brick". The Mindstorms Robotics Invention System (RIS)
set comes with Windows software with which you
can build programs by moving blocks of logic around graphically on the
screen and chaining them together ("turn sensor 1 on" ... "while this
condition is true" ... "set motor 2 backwards" ... "turn motor 3 off" and
so on). In addition, various efforts on the parts of talented individuals have
come up with many different ways to program the RCX. O'Reilly's "The
Unofficial Guide to LEGO Mindstorms Robots" tells you all you need to
know, and gives you the big picture. What's important to know for this
recipe is the following:</P
><P
></P
><DIV
CLASS="VARIABLELIST"
><DL
><DT
>Cross compiling or realtime control</DT
><DD
><P
>There are two approaches to programming an RCX. One approach is to write a
program on your PC, and download it to the RCX once complete, thence start
and stop the program using the buttons on the RCX itself. The download is
done over the IR connection.</P
><P
>The other approach is to control the RCX directly from a program that you
write <I
CLASS="EMPHASIS"
>and execute</I
> on your PC, sending control signals
and receiving sensor values over the IR connection.</P
><P
>Both approaches have their merits. How appropriate each one is boils down
to one thing: connections.
On the one hand, building autonomous machines that find
their way around the kitchen to scare the cat and bring you a sandwich
calls for the first approach, where, once you've downloaded the program to
the RCX, you can dispense with any further connection with your PC because
the entire logic is situated in your creation. On the other hand, if you
want to build a physical extension to a larger system that, for example,
has a connection to the Internet, the second approach is likely to be more
fruitful, because you can essentially use the program that runs on your
PC and talks to the RCX over the IR link as a conduit, a proxy, to other
programs and systems that can be reached over the network.</P
><P
>We're going to use the second approach.</P
></DD
><DT
>The nature of the LEGO RIS software</DT
><DD
><P
>The RIS software that comes as standard centers around an ActiveX control.
While there are plenty of ways to talk to the RCX without using this control
(the book mentioned earlier describes many of these ways), the features
offered by the control—<TT
CLASS="LITERAL"
>Spirit.ocx</TT
>— are fine
for many a project. And with Perl's <TT
CLASS="LITERAL"
>Win32::OLE</TT
> module,
we can interact with this ActiveX control without having to resort to
Visual Basic. </P
></DD
></DL
></DIV
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="JABTDG-CH-8-SECT-2.1"
>What we're going to do</A
></H2
><P
>Everyone knows that one of the virtues of a programmer is
<I
CLASS="EMPHASIS"
>laziness</I
>. We're going to extend this virtue
(perhaps a little too far) and enhance it with a hacker's innate
ability to combine two favorite pastimes—programming and
playing with LEGO—to build contrived but fun devices.</P
><P
>We've a filter coffee machine that sits in my wife Sabine's study. My
office is in the basement. Rather than traipse all the way upstairs to
find out there's no coffee left in the pot, I decided to put my RCX to
good use and get it to tell me, via Jabber, whether the pot had enough
for another cup or not. That way, I didn't have to leave my keyboard
to find out.</P
><P
>The idea is that we connect a light sensor to the RCX, and use that
to "see" the coffee. The coffee pot is made of glass, and so allows light to
pass through it. If there's coffee in the pot, no light passes through.
The coffee effectively "gets in the way of" the light.
There we have a simple binary switch. No (or a small amount of) light
measured: there's coffee in the pot. Some (or a larger amount
of) light: there's no coffee in the pot. We want to be able to push
the coffee state to all interested parties in a way that their
off the shelf Jabber clients can easily understand and display. </P
><P
><A
HREF="x8561.htm#JABTDG-CH-8-FIG-4"
>Figure 8-2</A
> shows our LEGO Mindstorms device
in action. The brick mounted on the gantry which extends to the glass
coffee pot is our light sensor; a wire runs from it back to the
connector on the RCX. Behind the RCX is the IR tower which is
connected to Sabine's PC.</P
><DIV
CLASS="FIGURE"
><A
NAME="JABTDG-CH-8-FIG-4"
></A
><P
><B
>Figure 8-2. Our device "looking at" the coffee pot</B
></P
><P
><IMG
SRC="CH-8-FIG-4.jpg"></P
></DIV
><P
>Remembering that
<TT
CLASS="LITERAL"
><presence/></TT
> elements are a simple way
of broadcasting information about availability, <I
CLASS="EMPHASIS"
>and</I
>
contain a <TT
CLASS="LITERAL"
><status/></TT
> tag to describe the
detail or context of that availability in free-form text,
<A
NAME="AEN8603"
HREF="#FTN.AEN8603"
>[2]</A
>
we have a perfect mechanism that's
ready to be used. What's more, most, if not all, of the off the shelf
Jabber client implementations will display the content of the
<TT
CLASS="LITERAL"
><status/></TT
> tag next to the JID to which
it applies, in the client user's roster.
<A
HREF="x8561.htm#JABTDG-CH-8-FIG-4"
>Figure 8-2</A
> shows how the
<TT
CLASS="LITERAL"
><status/></TT
> tag content is
displayed—as a hovering "tooltip"—in WinJab.</P
><P
>Here's what we need to do:</P
><P
></P
><DIV
CLASS="VARIABLELIST"
><DL
><DT
>Set up the RCX</DT
><DD
><P
>We need to set the RCX up, with the light sensor, near enough to the
coffee machine to take reliable and consistent light readings. Luckily
the serial cable that comes with the Mindstorms set and connects to the
IR tower is long enough to stretch from Sabine's computer over to within
the infrared line-of-sight to the RCX. </P
></DD
><DT
>Make the correct calibrations</DT
><DD
><P
>There are bound to be differences in ambient light, sensitivity of the
light sensor, and how strong you make your coffee. So we need a way of
calibrating the setup, so that we can find the appropriate "pivot
point" light reading value that lies between the two states of
<I
CLASS="EMPHASIS"
>coffee</I
> and <I
CLASS="EMPHASIS"
>no-coffee</I
>. </P
></DD
><DT
>Set up a connection to Jabber</DT
><DD
><P
>We need a connection to a Jabber server, and a client account there.
We can set one up using the <B
CLASS="COMMAND"
>reguser</B
> script from
<A
HREF="x6787.htm"
>the section called <I
>User Registration Script</I
> in Chapter 6</A
>. We also need the script to honor
presence subscriptions and unsubscriptions from users who want to
be informed of the coffee state. </P
></DD
><DT
>Set up a sensor poll/presence push loop</DT
><DD
><P
>Once the RCX has been set up, the sensor calibrations taken, and the
connection has been made, we need to constantly
monitor the light sensor on the RCX at regular intervals.
At each interval we determine the coffee state by comparing the value
received from the sensor with the pivot point determined in the calibration
step, and send any change in that state as a new availability
<TT
CLASS="LITERAL"
><presence/></TT
> element containing an appropriate
description in the <TT
CLASS="LITERAL"
><status/></TT
> tag.</P
></DD
></DL
></DIV
></DIV
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="JABTDG-CH-8-SECT-2.2"
>The script</A
></H2
><P
>We're going to use Perl, and the <TT
CLASS="LITERAL"
>Net::Jabber</TT
> libraries,
to build the script. Perl allows us a comfortable way to interact with an
ActiveX control, through the <TT
CLASS="LITERAL"
>Win32::OLE</TT
> module. It's
Let's dive straight in.</P
><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="JABTDG-CH-8-SECT-2.2.1"
>Setup</A
></H3
><P
>We first declare the packages we're going to use. As well as
<TT
CLASS="LITERAL"
>Net::Jabber</TT
> and <TT
CLASS="LITERAL"
>Win32::OLE</TT
>, we're
going to use <TT
CLASS="LITERAL"
>Getopt::Std</TT
> which affords us a comfortable
way of accepting and parsing command line switches. We also want to use
the <TT
CLASS="LITERAL"
>strict</TT
> pragma, which should keep us from making
silly coding mistakes by not allowing undeclared variables and the like.</P
><P
>We specify the "Client" string on our usage declaration for the
<TT
CLASS="LITERAL"
>Net::Jabber</TT
> package to specify what should be
loaded. The package is a large and comprehensive set of modules,
and only some of those are relevant for what we wish to do in our
script—build and work with a Jabber <I
CLASS="EMPHASIS"
>client</I
>
connection. Other module sets are pulled in by specifying
"Component" or "Server".</P
><P
><PRE
CLASS="SCREEN"
>use Net::Jabber qw(Client);
use Win32::OLE;
use Getopt::Std;
use strict; </PRE
></P
><P
>We're going to allow the command line switches <TT
CLASS="OPTION"
>-l</TT
> and
<TT
CLASS="OPTION"
>-s</TT
>. This is what the switches do:</P
><P
></P
><DIV
CLASS="VARIABLELIST"
><DL
><DT
>No switches specified (or just the <TT
CLASS="OPTION"
>-s</TT
> switch): calibration mode</DT
><DD
><P
>When we run the script for the first time, we need
to perform the calibration, and read values from the sensor to determine
a mid point value, above which signifies the presence of light, and
therefore the absence of coffee, and below which signifies the absence
of light, and therefore the presence of coffee.</P
><P
>If we specify no switch, the script will start up automatically in
calibration mode.</P
><P
><A
HREF="x8561.htm#JABTDG-CH-8-FIG-1"
>Figure 8-3</A
> shows the script in calibration
mode. The values displayed, one each second, represent the values
read from the light sensor. When the sensor was picking up lots of
light, the values were 60. When I moved the sensor in front of some
dark coffee, the values went down to around 45. Based upon this
small test, I would set the pivot point value to 50. </P
></DD
><DT
><TT
CLASS="OPTION"
>-l</TT
>: specify pivot value</DT
><DD
><P
>Once we've determined a pivot point value, we run the script "for real"
and tell it this pivot value with the <TT
CLASS="OPTION"
>-l</TT
> ("light pivot"):</P
><P
><PRE
CLASS="SCREEN"
>C:\temp> <userinput>perl coffee.pl -l 50</userinput> </PRE
></P
></DD
><DT
><TT
CLASS="OPTION"
>-s</TT
>: specify sensor</DT
><DD
><P
>The RCX, shown in <A
HREF="x8561.htm#JABTDG-CH-8-FIG-3"
>Figure 8-1</A
>, has three connectors
to which you can attach sensors. They're the three grey 2x2 pieces, with
the legends "1", "2" and "3", near the top end of the brick. Any sensor
can be attached to any of the three connectors. The script assumes you've
attached the light sensor to the one marked "1", which internally is "0"
(don't you just love computer science?). If you attach it to either of the
other two, you can specify the connector using the <TT
CLASS="OPTION"
>-s</TT
>
("sensor") with a value of 1 (for the middle connector) or 2 (for the
rightmost connector), like this:</P
><P
><PRE
CLASS="SCREEN"
>C:\temp> <userinput>perl coffee.pl -l 50 -s 2</userinput> </PRE
></P
><P
>You can specify the <TT
CLASS="OPTION"
>-s</TT
> switch when running in calibration
and in normal modes.</P
></DD
></DL
></DIV
><DIV
CLASS="FIGURE"
><A
NAME="JABTDG-CH-8-FIG-1"
></A
><P
><B
>Figure 8-3. Running the coffee script in calibration mode</B
></P
><P
><IMG
SRC="CH-8-FIG-1.jpg"></P
></DIV
><P
>Here's where the switches are defined with the Getopt::Std function:</P
><P
><PRE
CLASS="SCREEN"
>my %opts;
getopt('ls', \%opts); </PRE
></P
><P
>Next come a raft of constants, describing the script's Jabber
relationship (the server it will connect to, and the user, password
and resource it will connect with), the representation of the two
states of "coffee" and "no coffee" (which will be used to determine
the content of the <TT
CLASS="LITERAL"
><status/></TT
> tag sent
along inside any <TT
CLASS="LITERAL"
><presence/></TT
> element
emitted), the identification of the connector to which the light
sensor is attached, and the polling granularity of the sensor poll /
presence push loop described earlier (measured in seconds).</P
><P
><PRE
CLASS="SCREEN"
>use constant SERVER => "merlix.dyndns.org";
use constant PORT => 5222;
use constant USERNAME => "coffee";
use constant PASSWORD => "pass";
use constant RESOURCE => "perlscript";
use constant NOCOFFEE => 0;
use constant COFFEE => 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -