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
  sender
end

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]
  doit
end

 

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
  sender
end

 

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 values
aset my-array 0 262 
aset my-array 1 515
 
check the first four addresses’s byte values
send eb 0
send eb 1
send eb 2
send 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 byte code for the sequential actions are as :

  1. (run <%num> 135 0 )             
  2. (run <%num> 131 <%num> 3  <%num> 255)
  3. (run <%num> 133 <%num> 0  <%num> 8 <a> <on>)
  4. (run <%num> 131 <%num> 3  <%num> 255)
  5. (run <%num> 134)

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.