91.548 Robots
Assignment
Paper
Assignment No. 2
Due Date: Feb. 6, 2003
Course: 91.548 Robots 2003 Spring
Student: Jianping Zhou
Instructor: Prof. Fred Matin
1. 1. Experiment with the Handy Cricket and the Cricket Logo software. Play with motor and sensor commands. Display sensor data back on the the Cricket Logo screen.
For this experiment, I tried all commands relating to features of motor and sensor, such as a, b, ab, on, off, onfor duration, thisway, thatway, rd, setpower level, brake, switcha, switchb, sensora, sensorb.
When using statement send sensora or send procedure in which output sensora is its reture, then the sensor a’s data are displayed on the monitor field of Cricket Logo screen.
2. 2. Experiment with the Cricket's IR communications primitives send, newir?, and ir. Get one Cricket to trigger another Cricket to do something.
The Handy Cricket Programming Reference sample codes for infrared communication were used to exercise this experiment.
The first procedure, called sender, will run on one Cricket, and generate numbers which are sent to a second Cricket. Here, the sender procedure randomly sends a 0, 1, or 2:
to sender send random % 3 beep wait 30 senderend
The expression random % 3 produces a 0, 1, or 2, using the remainder-after-division operator. This value is sent using the send primitive. Then the procedure beeps and waits 3 seconds before sending a new number.
The second Cricket, a receiver procedure, doit, will receive these numbers and either turn on motor A, motor B, or both motors depending on the value it gets:
to doit waituntil [newir?] if ir = 0 [a, onfor 10] if ir = 1 [b, onfor 10] if ir = 2 [ab, onfor 10] doitend
This experiment doesn’t name the pair of crickets. This communication is in a non-addressed broadcast fashion.
3. 3. Create a multi-Cricket application whereby the Crickets pass a software token from one to another (“multi” >= 2). When a Cricket has the token, it should display some behavior to make this evident (e.g., beeping or turning on a motor output). Then this Cricket should be able to pass the token to another Cricket. Are there any problems in accomplishing this? Are the problems of a fundamental nature, or just implementation details?
Following codes are downloaded to three crickets respectively and used to implement above feature:
global
[token name pick]
to next ;choose next receiver randomly
setpick random % 3
if not pick = name [stop]
next
end
to
play
waituntil
[newir?]
if ir = 10 [settoken 0] ;sender knows receiver got token
if
ir = name
[settoken 1 ;receiver indeed got token
send 10 ;receiver notification
if name = 0 [note 119 20] ;receiver sound uniquely
if name = 1 [note 89 20]
if name = 2 [note 59 20]
wait 5
next ;randomly choose next cricket
send pick] ;pass token to next
play ;enter into listening
end
This command is used to name three crickets respectively
setname
<0,1,2>
Then run play procedure to make the three crickets alive. An additional cricket who runs following sender will serve as starter to initiate the game beginning from a random cricket. Once the game begins, the starter should be turn off. During the game, three tones music will be played, each tone will sound from different cricket.
to sender
send random % 3 beep wait 60 senderend
Inside cricket it does know whether it hold the token by checking its token variable
4. 4. Devise an experiment to determine if Cricket Logo arrays use 0 or 1 as an index for the first array element. (The Cricket Logo documentation does not specify.)
You may wish to refer to the Cricket memory map at http://handyboard.com/cricket/tech/. See also the Cricket Logo commands “examine byte” (eb) and “deposit byte” (db).
According to the Cricket memory map, the user array data are store in the beginning part of 4K external Eeprom. So in our experiment we first define an array, set two values of 262(low-byte =6; high-byte = 1) and 515 (low-byte =3; high-byte = 2) to the elements indexed 0 and 1, then examine the byte values at address 0, 1, 2, 3 (note: the values are stored and represented in 16 bits) resetdp ;ensure the pointer is at the beginning of eeprom
then download the command to define the array array [my-array 2] run these two commands to input array element valuesaset my-array 0 262 aset my-array 1 515 check the first four addresses’s byte valuessend eb 0send eb 1send eb 2send eb 3
Through running these commands in the command center of Cricket Logo respectively, we read the values on the monitor field and fill them in the table.
Address |
Read byte value |
Byte order |
Element value |
Corresponding index |
|
0 |
1 |
high-byte |
262 |
0 |
|
1 |
6 |
low-byte |
||
|
2 |
2 |
high-byte |
515 |
1 |
|
3 |
3 |
low-byte |
||
|
4 |
|
|
|
|
|
… |
|
|
|
|
Comparing with the original input, the first element is indexed as 0.
5. 5. Put a program on the Cricket that continually transmits sensor values (e.g., loop [send sensora]). Write a program that runs on a conventional desktop/laptop computer or a PDA that reads these values off the serial port* and displays them in some visual fashion (e.g., the music visualizations made by your desktop MP3 player).
* Note: Open the serial port with settings 9600-N-8-1.
I wrote a MFC application, called 91_548graphic, to capture the sensor data, and draw the curve on screen. Part of the codes and documentations are cited here. (complete source download)
/*****************************************************************
com
port class implementations, specifically for COM1, 9600-N-8-1
this
port is associated with a read thread. The thread function takes care of
reading com port buffer,an then writing to the application data list
******************************************************************/
CCommMonitor::CCommMonitor()
{
m_hComm = NULL;
m_pReadThread = NULL;
}
void
CCommMonitor::CommSettings()
{
DCB dcb;
COMMTIMEOUTS
CommTimeouts;
m_hComm = CreateFile((LPCTSTR)"COM1",
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
DWORD error =
GetLastError();
if(m_hComm == INVALID_HANDLE_VALUE)
{
// Handle the
error.
ReportLastError();
exit(1); // find C++
equivalent 20000908 JRL
}
// We will build on the current
configuration, and skip setting the size
// of the input and output buffers with
SetupComm.
//
set port for reading data
if(!SetCommMask(m_hComm, EV_RXCHAR | EV_CTS | EV_DSR))
{
ReportLastError();
exit(1);
}
//
initialize comm timeouts for port
CommTimeouts.ReadIntervalTimeout = MAXWORD;
CommTimeouts.ReadTotalTimeoutMultiplier = 0;
CommTimeouts.ReadTotalTimeoutConstant = 0;
CommTimeouts.WriteTotalTimeoutMultiplier = 0;
CommTimeouts.WriteTotalTimeoutConstant = 0;
if(!SetCommTimeouts(m_hComm, &CommTimeouts))
{
ReportLastError();
exit(1);
}
FillMemory(&dcb, sizeof(dcb), 0); //clean dcb before setting
// get the current state of the port to
keep unset parameters as default
if(!GetCommState(m_hComm, &dcb) )
{
ReportLastError();
exit(1);
}
// set the parameters specified
by the user for reading data from port
dcb.DCBlength =
sizeof( DCB ) ;
dcb.fParity = TRUE ;
dcb.BaudRate =
CBR_9600;
dcb.Parity =
NOPARITY;
dcb.StopBits =
ONESTOPBIT;
if(!SetCommState(m_hComm, &dcb)) // finally set up the dcb as
required
{
ReportLastError();
exit(1);
}
m_pReadThread = AfxBeginThread (ReadBytesFromPort, m_hComm,
THREAD_PRIORITY_NORMAL,
0, CREATE_SUSPENDED);
}
UINT
ReadBytesFromPort(LPVOID hComm)
{
CFileException e;
BYTE chRead;
cByte
* pByte;
DWORD dwCommEvent,dwRead;
if(WaitCommEvent((HANDLE)hComm,
&dwCommEvent, NULL) )
{
do
{
//
*pPortCollect = FALSE;
if(ReadFile((HANDLE)hComm,
//must have been created with GENERIC_READ access.
&chRead,
//buffer that receives the data read from comm handle
1,
&dwRead,
NULL
))
{
pByte
= new cByte(chRead);
pPortData
-> AddTail(pByte);
}
else
{
MessageBox (NULL, TEXT
("Severe error in byte reception."),
NULL, MB_ICONERROR);
}
} while(dwRead);
}
return TRUE;
}
/**************************************************************
implementation
for graphically displaying application data list. A timer is set for dynamical
display
****************************************************************/
void
CMy91_548graphicView::OnPaint()
{
CPaintDC dc(this); // device context for
painting
int x_coord =50, y_coord = 50;
dc.MoveTo(x_coord,y_coord); //start point
dc.LineTo(x_coord,y_coord);
int nByteCount = pPortData->GetCount();
POSITION pos;
cByte *pByte ;
for ( int nIndex = 0 ; nIndex <
nByteCount ; nIndex++ )
{
pos
= pPortData->FindIndex ( nIndex ) ;
if
( NULL != pos )
{
pByte = ( cByte * ) pPortData->GetNext (
pos ) ;
if
( NULL != pByte )
{
y_coord
+= 2;
dc.LineTo((x_coord
+ 2*(int) (pByte->m_bByteValue)), y_coord);
}
}
}
// Do not call CView::OnPaint() for
painting messages
}
void
CMy91_548graphicView::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code
here and/or call default
if ( nIDEvent == 1 ) // periodic sanity check
{
Invalidate(TRUE);
}
CView::OnTimer(nIDEvent);
}
/***************************************************************
These
commands trig data capture(immediately graphical display )and stop
***************************************************************/
void
CMy91_548graphicView::OnCapture()
{
// TODO: Add your command handler code
here
if(m_comm1.m_pReadThread)
m_comm1.m_pReadThread->ResumeThread();
Invalidate(TRUE);
CMy91_548graphicDoc * pDoc =
GetDocument();
pDoc->SetModifiedFlag(TRUE);
if
(!SetTimer (1, 50, NULL ))
{
AfxMessageBox("Failed to allocate timer, no timers available");
}
}
void
CMy91_548graphicView::OnStop()
{
SuspendThread(m_comm1.m_pReadThread);
KillTimer(1);
}
The touch sensor data are really captured, and shown graphically in the screen capture.

If you get done with all of the above, then:
6. 6. Read the information at http://handyboard.com/cricket/tech/ regarding the Cricket's byte code language and communications protocol. Write an application that interacts with the Cricket and causes it to turn on its motor port. The sequence of steps is as follows:
1. 1. Open the serial port for 9600-N-8-1 communications.
2. 2. Go through the cricket-check sequence and retrieve the decimal 135 acknowledgment value. Make sure to trap and discard the hardware and software echoes.
3. 3. Use the set-pointer command to point to an arbitrary address in memory.
4. 4. Load in the code for a, on.
5. 5. Set the pointer back to the initial location of the code.
6. 6. Send the run command.
The writing function to serial port is also implemented in above 91_548graphic MFC application. So the byte code string can be sent out through computer’s COM1 port. Since I haven’t not yet successfully finished processing the handshaking and echo between host and cricket-IR interface, the cricket didn’t respond at all. I will continue working on that.