Better late than never

Hexapod Robots

Re: Better late than never

Postby RayRenteria » Tue Mar 17, 2015 1:58 pm

Matt,

Absolutely, I will absolutely give a shout out to iC and work his inspiration into my presentation! I just threw together a destination page at http://www.dar-1.com and mentioned the inspiration under the section labeled "His Heritage."

There's an overall philosophy I employ which invokes magic as a major ingredient to glue all the technical pieces together and create a collective illusion. It starts by anthropomorphizing DAR-1 by calling him a "he." Explaining that his name comes from a name I had reserved for my son, who was never born because my wife and I called it a day after four daughters, I gave Dante Andreas Rentera to DAR-1. That sets the stage. When they look at him and he engages, they're hooked. The occasional anomaly which might be considered undesirable by engineers, is quickly rationalized as behaviors by the participant, including "quivering legs" (servo oscillation), subtle lurching threats (DAR-1 reacts in a jerky way to losing the face and seeing the face within a few milliseconds due to video noise), and the one that gets me is how he prefers to track women over men (probably a bias in the facial training set).

Collectively, I leverage these things with and combine them with talk track to create a suspension of disbelief in which the people are willing participants. I learned that from you and from the iC videos. I noticed in an interview in the Monster Mash video where you explained such an anomaly to the interviewer "we had a lady yesterday that he tracked and for some reason he would go up and down her body and I don't know why, but there we go. I didn't program that, so..." (at 1:00). Note, you also called iC a "he." :) We know there are some patterns that occasionally confuse the OpenCV face detection algorithm and they probably are what drew iC's attention. Your explanation helped perpetuate the sentiment that iC has his own personality, and it's more fun.

Magic as a discipline is a key ingredient for a successful social interaction with a robot. We have the burden as social robot builders to do what we can to create and maintain a suspension of disbelief and not jerk the participant out of it. DAR-1 has some issues where he'll lose the participant because his field of view is limited and if somebody moves to quickly he'll lose them. People will wave or call his name to get his attention and he won't respond. I intend to address all these things once I don't have an imminent commitment to present.

In the meantime, thank you again for all your support.

--Ray
RayRenteria
 
Posts: 31
Joined: Thu May 22, 2008 2:38 am
Location: Austin, TX, USA

Re: Better late than never

Postby Matt Denton » Tue Mar 17, 2015 2:11 pm

Hi Ray,,

Interesting stuff! I love where the DAR name comes from, very nice :)

It's a nice DAR page you have set up there also. And thanks for the heritage mention, could you add a link within the "IC Hexapod" the or something? The iC site does not work too well anymore, due to the vast number of images and sloppy server code :o , however, the link to the project page in this forum would be good:

viewtopic.php?f=14&t=9

cheers

Matt.
Matt Denton
AKA: Winchy_Matt

micromagic systems ltd
Matt Denton
Site Admin
 
Posts: 1622
Joined: Tue May 20, 2008 9:15 pm
Location: Winchester UK

Re: Better late than never

Postby RayRenteria » Tue Mar 17, 2015 2:19 pm

Done!

Though my dar-1.com page is a little sloppy -- I couldn't get rid of the navigation stuff at the top, but no time to debug. I'm late to SXSW! :)

--Ray
RayRenteria
 
Posts: 31
Joined: Thu May 22, 2008 2:38 am
Location: Austin, TX, USA

Re: Better late than never

Postby PauliusLiekis » Mon Mar 30, 2015 11:08 pm

Nice!

What kind of framerate are you getting on RPi during face-detection?
PauliusLiekis
 
Posts: 17
Joined: Tue Jan 13, 2015 4:30 pm

Re: Better late than never

Postby RayRenteria » Wed Apr 01, 2015 11:14 pm

I'm running at better than 22FPS. I found that eliminating the UI made a huge improvement. Also, using the RPi raspicam makes a huge difference, too. Both of these are easier than adjusting the math. :)

--Ray
RayRenteria
 
Posts: 31
Joined: Thu May 22, 2008 2:38 am
Location: Austin, TX, USA

Re: Better late than never

Postby plingboot » Tue Jun 27, 2017 8:39 pm

Just picking up this thread again. It's been a while since I last had a good look through the forum and so I'd somehow missed this nugget.

I still have my original (first off the production line) MSR-H01 and I also have a micro bug kit which has been sitting unopened in my desk drawer for years.

This project has galvanised me into finally building it with a view to adding an rPi3 and camera for face detection.

An RPi 3 and camera dropped through the post box today and I've asked Ray to lend a hand with the code he managed to get working. I'll start a new thread for this project with pics, details and links so any other mms hexapod owners can have a go at it.

With the newer RPi 3 having on board Bluetooth and wifi this promises to be a nice physically compact build.
Sheriff of Nothing
plingboot
 
Posts: 281
Joined: Sun Jun 01, 2008 5:30 pm
Location: the gutter, fashionable south west london

Re: Better late than never

Postby Matt Denton » Tue Jun 27, 2017 8:53 pm

Are you going to put it on the bug?
Matt Denton
AKA: Winchy_Matt

micromagic systems ltd
Matt Denton
Site Admin
 
Posts: 1622
Joined: Tue May 20, 2008 9:15 pm
Location: Winchester UK

Re: Better late than never

Postby plingboot » Tue Jun 27, 2017 9:02 pm

I'll put it on the big hexa first to get it working and depending on the size of the physical build I'll put one on the bug.

Matt, when I get going are you happy to field questions about direct connections between the RPi and p.brain SMB and p.Brain-µ24 boards if required - I have both.
Sheriff of Nothing
plingboot
 
Posts: 281
Joined: Sun Jun 01, 2008 5:30 pm
Location: the gutter, fashionable south west london

Re: Better late than never

Postby Matt Denton » Tue Jun 27, 2017 9:10 pm

Sure assuming I remember!!! :)

I looked at doing this at the time of the ubug release but couldn't find a small/powerful board to use. Pre Pi!
Matt Denton
AKA: Winchy_Matt

micromagic systems ltd
Matt Denton
Site Admin
 
Posts: 1622
Joined: Tue May 20, 2008 9:15 pm
Location: Winchester UK

Re: Better late than never

Postby RayRenteria » Tue Jun 27, 2017 9:24 pm

David,

What language will you be working in? I created following abstraction layer in C that helped me communicate with the p.Brain u24 and HexEngine. I remember struggling a little bit with IO because of my bluetooth configuration but I worked out most of the kinks through this layer. Hopefully you can use it.

My setup was a little weird because I was communicating with the HexEngine via bluetooth from the RPi, which sounds like you might be doing the same. The code assumes a port speed of 115200 on /dev/rfcomm0.

Once you get a Hello World working where you can control your uBug (I assume it has a similar protocol to the u24 on the MSR, I'm not familiar with it), I can help you get the RPi's camera to interface with the OpenCV image buffer. Once you've done that, then you're set. It's all easy peasy from there. :)

Here's the code I used to talk to the p.Brain u24 and HexEngine:

hexengine.c
Code: Select all
#include <unistd.h>  /* UNIX standard function definitions */
#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>   /* File control definitions */
#include <termios.h> /* POSIX terminal control definitions */

#include "hexengine.h"

static int      gTheHexEngine = -1;
char _printable_char(char c)
{
   switch(c)
   {
   case 0x1b:
      return '.';
   }
   return c;
}

int _safe_write(char *pData, int nBytes)
{
   int nRetryCount= 0;
   int nWritten = -1;
   while (((nWritten=write(gTheHexEngine,pData,nBytes)) < 0) && (nRetryCount++ < MAX_RETRIES))
      usleep(RETRY_SLEEP_DURATION);
   return nWritten;
}

int _safe_read()
{
   char cBuffer[1] = { 0x00 };
   int nRetryCount= 0;
   int nRead = -1;
   CAVEMAN_DEBUG2("%d >R",nRetryCount);
   while (((nRead=read( gTheHexEngine, cBuffer, 1 ))<0) && (nRetryCount++ < MAX_RETRIES))
      usleep(RETRY_SLEEP_DURATION);
   CAVEMAN_DEBUG2("%d",nRead);
   CAVEMAN_DEBUG("R> ");
   CAVEMAN_FLUSH();
   return cBuffer[0];
}


int HE_set_pip_mode_simple()
{
   CAVEMAN_DEBUG_CR("PIP_MODE:simple");
   if ( !HE_send_command("{", 1 ) )
      perror( "set_pip_mode_simple: could not send set_pip_mode_simple command" );
   return HE_read_response();
}

int HE_set_pip_mode_escaped()
{
   CAVEMAN_DEBUG_CR("PIP_MODE:escaped");
   if ( !HE_send_command("}", 1 ) )
      perror( "set_pip_mode_escaped: could not send set_pip_mode_escaped command" );
   return HE_read_response();
}

int HE_reset_legs_to_neutral_position()
{
   if ( !HE_send_command("r",1))
      perror( "reset_legs_to_neutral_position : " );
   return HE_read_response();
}

int HE_set_body_position_frames(int x_rotation, int y_rotation, int z_rotation, int x_translation, int y_translation, int z_translation, int frame_count)
{
   char cBuffer[9];
   cBuffer[0] = 'V';
   cBuffer[1] = x_rotation;
   cBuffer[2] = y_rotation;
   cBuffer[3] = z_rotation;
   cBuffer[4] = x_translation;
   cBuffer[5] = y_translation;
   cBuffer[6] = z_translation;
   cBuffer[7] = (frame_count >> 8) & 255;               // MSB of frame_count
   cBuffer[8] = (frame_count & 255);                     // LSB of frame_count
   if ( !HE_send_command(cBuffer,7))
      perror( "set_body_position : " );
   return HE_read_response();
}

int HE_set_body_position(int x_rotation, int y_rotation, int z_rotation, int x_translation, int y_translation, int z_translation)
{
   char cBuffer[7];
   cBuffer[0] = 'B';
   cBuffer[1] = x_rotation;
   cBuffer[2] = y_rotation;
   cBuffer[3] = z_rotation;
   cBuffer[4] = x_translation;
   cBuffer[5] = y_translation;
   cBuffer[6] = z_translation;
   if ( !HE_send_command(cBuffer,7))
      perror( "set_body_position : " );
   return HE_read_response();
}

int HE_set_body_rotation_offset(int x, int y, int z)
{
   char cBuffer[4];
   cBuffer[0] = 'J';
   cBuffer[1] = x;
   cBuffer[2] = y;
   cBuffer[3] = z;
   if ( !HE_send_command(cBuffer,4))
      perror( "set_body_rotation_offset : " );
   return HE_read_response();
}

int HE_set_head_position(int nPan, int nTilt)
{
   CAVEMAN_DEBUG_CR("CMD> HE_set_head_position()");
   char cBuffer[3];
   cBuffer[0] = 'H';
   cBuffer[1] = nTilt;
   cBuffer[2] = nPan;
   if ( !HE_send_command(cBuffer,3))
      perror( "set_head_position : " );
   CAVEMAN_DEBUG_CR("<CMD HE_set_head_position()");
   return HE_read_response();
}

int HE_wake()
{
   CAVEMAN_DEBUG_CR("CMD> HE_wake()");
   if ( !HE_send_command( "+", 1 ) )
      perror( "wake: could not send wake command" );
   CAVEMAN_DEBUG_CR("<CMD HE_wake()");
   return HE_read_response();
}

int HE_sleep()
{
   CAVEMAN_DEBUG_CR("CMD> nexengine_sleep()");
   if ( !HE_send_command( "-", 1 ) )
      perror( "sleep: could not send sleep command" );
   CAVEMAN_DEBUG_CR("<CMD nexengine_sleep()");
   return HE_read_response();
}

int HE_turn_left()
{
   CAVEMAN_DEBUG_CR("CMD> HE_turn_left()");
   if ( !HE_send_command( "a", 1 ) )
      perror( "turn_left: could not send wake command" );
   CAVEMAN_DEBUG_CR("<CMD HE_turn_left()");
   return HE_read_response();
}

int HE_turn_right()
{
   CAVEMAN_DEBUG_CR("CMD> HE_turn_right()");
   if ( !HE_send_command( "d", 1 ) )
      perror( "turn_right: could not send wake command" );
   CAVEMAN_DEBUG_CR("<CMD HE_turn_right()");
   return HE_read_response();
}

int HE_stop()
{
   CAVEMAN_DEBUG_CR("CMD> HE_stop()");
   if ( !HE_send_command( " ", 1 ) )
      perror( "stop: could not send wake command" );
   CAVEMAN_DEBUG_CR("<CMD HE_stop()");
   return HE_read_response();
}


int HE_twitch()
{
   CAVEMAN_DEBUG_CR("CMD> HE_twitch()");
   HE_turn_left();
   HE_stop();
   CAVEMAN_DEBUG_CR("<CMD HE_twitch()");
   return 1;
}

void HE_disconnect()
{
   close(gTheHexEngine);
}

int HE_send_command(char *pCommand, int nLen)
{
   int   checksum = 0;
   int   i        = 0;
   char  buffer[MAX_BUFFER_LEN];
   
   // Packet Format
   // The packet interface commands are sent in packets of data, each packet must conform to the following protocol:
   //
   //    [Header Byte],[Packet Count],[n Bytes of Data.....],[Check Sum]
   //
   // Header Byte = 0x7e
   // Packet Count = Data bytes excluding Header Byte, Packet Count & Check Sum
   // Check Sum = 0xff – (8 bit sum of all data bytes)
   //
   CAVEMAN_DEBUG_CR("> HE_send_command()");
   
   // Header Byte = 0x7e
   buffer[0] = CMD_PIP_HEADER;

   // Packet Count = Data bytes excluding Header Byte, Packet Count & Check Sum
   buffer[1] = nLen;
   memcpy((char*)&buffer[2],pCommand,nLen);
   
   // Check Sum = 0xff – (8 bit sum of all data bytes)
   for(i=0;i<nLen;i++)
      checksum += (int)pCommand[i];
   buffer[2 + nLen] = 0xff - checksum;
   
   CAVEMAN_DEBUG_CR("< HE_send_command()");
   return _safe_write(buffer,nLen+3);
}

int HE_read_response()
{
   CAVEMAN_DEBUG_CR("> HE_read_response()");
   char c = '\0';
   char cLastACK = '\0';
   
   // Make sure writes are complete.
   tcdrain(gTheHexEngine);

   // Read the response

   // Upon reception of a PIP packet, a return PIP packet is sent with one byte of data
   // corresponding to an ACK (Acknowledge) or NACK (Not Acknowledged).
   //
   // ACK = 'k' (PIP = 0x7e,0x01,0x6b,0x94)
   // NACK = '?'  (PIP = 0x7e,0x01,0x3f,0xc0)
   // BUSY = 'b' (PIP = 0x7e,0x01,0x62,0x9d)
   //   
   // ACK's and NACK's are only sent for properly formatted PIP packets, if a packet is sent with
   // a bad checksum or incorrect protocol, no reply is sent. If a PIP packet is sent with correct
   // formatting, but the data command is unrecognised, a NACK is sent in reply. The BUSY reply is for
   // commands 'V', 'N', 'v' & 'n'. This response indicates that the packet was received, but the
   // relative command is still busy.
   
   // Order of operations is very important here.  If we got our ACK back, let's finish.  We're in blocking
   // mode so if we try to read past our ACK packet and there's nothing there, then we'll just block.
   while ((cLastACK == '\0') && (c = _safe_read()))
   {
      CAVEMAN_DEBUG3("%02x (%c)\n\r",c,_printable_char(c));
      fflush(stdout);
     
      if (c == CMD_PIP_HEADER)
      {
         CAVEMAN_DEBUG_CR("CMD_PIP_HEADER detected");
         
         // If we find a CMD_PIP_HEADER , the next byte should be the number of characters to read.
         // For now, we're just looking for single-byte ACK packets.
         if ((int)_safe_read() == 1)
         {
            CAVEMAN_DEBUG_CR("1-byte packet detected");
            // If the packet size is 1, then check to see if the next byte is an ACK packet.
            switch(c = _safe_read())
            {
            case CMD_PIP_ACK:
            case CMD_PIP_NACK:
            case CMD_PIP_BUSY:
               CAVEMAN_DEBUG_CR("CMD_PIP_*ACK data detected");

               // Consume the checksum byte.
               _safe_read();
               CAVEMAN_DEBUG_CR("Consumed the checksum byte");
               
               // We got what we wanted, now let's get the hell out of here before we block.
               cLastACK = c;
               break;
            default:
               CAVEMAN_DEBUG2("%2x ",c);
               break;
            }
         }
      }
   }
   CAVEMAN_DEBUG_CR("< HE_read_response()");
   return cLastACK;
}

int HE_connect(void)
{
   gTheHexEngine       = -1;
   CAVEMAN_DEBUG_CR("> connect_to_hexengine()");
   
   gTheHexEngine = open("/dev/rfcomm0", O_RDWR | O_NOCTTY | O_NONBLOCK );
   if (gTheHexEngine == -1)
   {
      perror("open ");
      CAVEMAN_DEBUG_CR("< connect_to_hexengine()");
      return -1;
   }
   
   // isatty() will evaluate whether the port we're trying to connect to is actually a serial port.
   if (!isatty(gTheHexEngine))
   {
      CAVEMAN_DEBUG_CR("The port used to talk to the hex engine isn't a serial port.");
      close(gTheHexEngine);
      return -1;
   }
   
   struct termios config;
   tcgetattr(gTheHexEngine, &config);
   cfsetispeed(&config, B115200);
   cfsetospeed(&config, B115200);
   tcsetattr(gTheHexEngine, TCSANOW, &config);
   
   CAVEMAN_DEBUG_CR("< connect_to_hexengine()");
   return (gTheHexEngine);
}


hexengine.h
Code: Select all
// **********************************************************************
// DEFINITIONS
// **********************************************************************
#define CMD_PIP_HEADER             0x7e
#define CMD_PIP_ESCAPE             0x7d
#define CMD_PIP_XOR                0x20
#define CMD_PIP_ACK               0x6b
#define CMD_PIP_NACK               0x3f
#define CMD_PIP_BUSY               0x62

#define MAX_RETRIES              700      // 10 milliseconds between each try.
#define RETRY_SLEEP_DURATION     10000

#define MAX_BUFFER_LEN           128
#define MAX_TILT_POSITION        127
#define MIN_TILT_POSITION        -127
#define MAX_PAN_POSITION         127
#define MIN_PAN_POSITION         -127

// #define ENABLE_DEBUG             1

#ifdef ENABLE_DEBUG
#define CAVEMAN_DEBUG_CR(x)      printf("%s\n\r",x);
#define CAVEMAN_DEBUG(x)         printf(x);
#define CAVEMAN_DEBUG2(x,y)      printf(x,y);
#define CAVEMAN_DEBUG3(x,y,z)    printf(x,y,z);
#define CAVEMAN_DEBUG4(a,b,c,d)  printf(a,b,c,d);
#define CAVEMAN_FLUSH()          fflush(stdout);
#else
#define CAVEMAN_DEBUG_CR(x)     
#define CAVEMAN_DEBUG(x)         
#define CAVEMAN_DEBUG2(x,y)     
#define CAVEMAN_DEBUG3(x,y,z)   
#define CAVEMAN_DEBUG4(a,b,c,d) 
#define CAVEMAN_FLUSH()
#endif

extern int   HE_connect();
extern void  HE_disconnect();
extern int   HE_send_command(char *pCommand, int nLen);
extern int   HE_read_response();;

extern int   HE_sleep();
extern int   HE_wake();

extern int   HE_turn_left();
extern int   HE_turn_right();
extern int   HE_stop();
extern int   HE_twitch();
extern int   HE_set_control_mode();
extern int   HE_set_pip_mode_simple();
extern int   HE_set_pip_mode_escaped();
extern int   HE_reset_legs_to_neutral_position();
extern int   HE_set_body_position_frames(int x_rotation, int y_rotation, int z_rotation, int x_translation, int y_translation, int z_translation, int frame_count);
extern int   HE_set_body_position(int x_rotation, int y_rotation, int z_rotation, int x_translation, int y_translation, int z_translation);
extern int   HE_set_body_rotation_offset(int x, int y, int z);
extern int   HE_set_head_position(int nPan, int nTilt);
RayRenteria
 
Posts: 31
Joined: Thu May 22, 2008 2:38 am
Location: Austin, TX, USA

PreviousNext

Return to Hexapods

Who is online

Users browsing this forum: No registered users and 1 guest

cron