View unanswered posts | View active topics It is currently Mon Dec 22, 2014 7:56 pm






Reply to topic  [ 10 posts ] 
We're building a body-controlled robot - need some help! 
Author Message
Rookie

Joined: Mon Jun 11, 2012 9:28 pm
Posts: 37
Post We're building a body-controlled robot - need some help!
Hey everyone!

I asked a few weeks ago about getting wireless communication between two VEX systems. I got some personal help from fretless_kb and he suggested I move the discussion to the forum so it can benefit everyone and allow some of the experts to offer some help.

The high school project I'm working on (with a partner) is a little hard to describe. Basically, think of a frame that attaches to your upper body and straps to your arms, so that it will move when your arms move. It has four degrees of freedom (and as such, 4 potentiometers) on each arm, along with a grip trigger.

These potentiometers should then send their to a robot which is basically designed as an upper body with its own two arms with 4 degrees of freedom (4 servos) and a claw.

So, if all works well, we will end up with a robot that mimics your movement from the waist up... something that will be very cool if it works!

Mechanically, it's all working very well - however, as there's no VEX system which allows signals to be transmitted wirelessly from one Cortex to another, it's looking like I'll have to buy some Xbee modules so that I can send the required potentiometer values from the suit to the robot. A wired system is pretty much out of the question as that's a lot of signal wires to send between cortices.

So, my questions are:
-What will I have to order?
-How can I go about coding the wireless communication?

Thanks for your help! I'll be sure to post pics/video when it's done!

Daniel


Fri May 17, 2013 11:09 am
Profile
Rookie

Joined: Wed Feb 09, 2011 1:08 am
Posts: 27
Post Re: We're building a body-controlled robot - need some help!
Hi There,

I still need to refresh where I left off in my latest project. But when I've finished that (Shouldn't take too long) I'll post it here. The project uses two joystick inputs from sparkfun and allows remote wireless control of a robot. This should provide a good example of the code needed to make a remote controlled body robot.

We'll describe how to test without XBee and then provide an example using XBee point to point.

Cheers Kb


Sat May 18, 2013 1:03 pm
Profile
Moderator
Moderator
User avatar

Joined: Tue Sep 14, 2010 9:19 pm
Posts: 496
Post Re: We're building a body-controlled robot - need some help!
You say that a wired connection is out of the question, but have you considered UART? It's just one wire (well actually it's four, but it's one set), and you can communicate back and forth between the cortexes.

This isn't really related to your question, but my team has done something similar a few years ago. Check it out if you'd like: http://www.youtube.com/watch?v=Y5tPkMS1_h8

_________________
sudo rm -rf /


Sat May 18, 2013 8:06 pm
Profile
Rookie

Joined: Mon Jun 11, 2012 9:28 pm
Posts: 37
Post Re: We're building a body-controlled robot - need some help!
@fretless_kb Thanks!

@magicode nope, I never heard of UART. isn't it what the robot uses to talk to the LCD screen? Our school doesn't have any of those cables, but perhaps we could order them in then solder on some long wires, or even just wire the wires straight to the cortex without the plug. That system would be very unintrusive and a lot cheaper than the Xbees.

Is there anywhere I could find an example of cortex-to-cortex communication code with the UART? Do you think it will be able to handle the 8 pot values?

Heh, nice dancing robot :) To be honest, I'm surprised the servos handled the weight of those arms... perhaps my third paty giant servos and geared down 393's are a bit of overkill ;D


Sat May 18, 2013 10:36 pm
Profile
Rookie

Joined: Wed Feb 09, 2011 1:08 am
Posts: 27
Post Re: We're building a body-controlled robot - need some help!
Actually I was suggesting the first step of the project would be conducted using hardwire. Then progress to XBee Assuming Squidster wanted to use wireless.

Squidster, The XBee Communication is via the Uart, you can substitute the XBee itself with wires, although I don't know how long they can be before the messages start to get garbled on the wires.

I was assuming you would want to use an Arduino as input (Users wearing harness connected to the arduino) but if you have a couple Cortex on hand or even a PIC and a Cortex on hand they could be used for a scaled down project. The Cortex only supports 8 Analog inputs. the PIC has 16 Analog / digital inputs so would make a good device for input. (if you have one)

why don't you let me know what you have on hand. I can put some instruction together on how to connect the uarts together using wires. For my testing I used a 4 wire IME cable from Vex, It actually has complimentary (I.e. good) wire orientation that allowed me to plug a 4 wire cable into the UART socket and directly to a XBee Shield the pins lined up nicely. If we connect 2 cortex Uarts we need to do a slight adjustment.

The Uart has 4 pins +5v, Transmit (Tx), Receive (Rx), and ground

You want the transmit of one computer port to connect to the receive of the other computer port. so a mouth pairs with an ear so to speak.

Why don't you let me know what type of pieces you have on hand to play with?

Cheers Kb


Sun May 19, 2013 9:03 am
Profile
Rookie

Joined: Wed Feb 09, 2011 1:08 am
Posts: 27
Post Re: We're building a body-controlled robot - need some help!
I will say It is a great day for yard work here so that is my priority today I will tr to post pictures and a working example of pic to cortex hardwire Uart communication tonight.

Cheers Kb


Sun May 19, 2013 10:59 am
Profile
Rookie

Joined: Mon Jun 11, 2012 9:28 pm
Posts: 37
Post Re: We're building a body-controlled robot - need some help!
@Fretless_kb

That's nice to hear that the Xbee can just be a substitution for wired once wired is working. That means I can started right away.

I have access to:
-Around 5 cortex
-A boatload of PIC's
-One Arduino Mega. This is my personal one though. I have not used it for anything yet, but I would only use it for this project if absolutely necessary.

You say a PIC will be useful, but I don't see any UART port on the PIC :P
Also the Cortex's 8 analog pins should be enough.

EDIT: I just remembered the TX and RX markings, feel free to disregard ;)


Sun May 19, 2013 12:18 pm
Profile
Rookie

Joined: Wed Feb 09, 2011 1:08 am
Posts: 27
Post Re: We're building a body-controlled robot - need some help!
This is where I've got to so far, Sorry I haven't had as much time as I thought this week.

I've simplified my example to a symmetric send and receive program, that is the program will send and receive the same data packet. basically a message ID(future use), time (to provide constantly changing data), and 2 potentiometer readings (if connected)

I haven't tested this yet, so caveat emptor, but I should be able to test this weekend and update any issues.

The other thing to note is this code is written to run on a PIC, I would do other things if this was targeting only a Cortex, but since there are limitations on the PIC platform and as I understand it you wanted originally more than 8 analog inputs, I started with PIC code.

I still intend to document further the State Machine working (Rx Task)

If you were to load this on 2 PIC / Cortexs and connect their serial ports correctly you should see on the debugger for each robot the time in the RX data packets, likewise if you hook up potentiometers you should see the value change on the remote unit.

Let me know if you need help wiring up the Serial Ports, and how you intend to deploy, on 2 PIC / a cortex / PIC or 2 Cortex.

Cheers Kb

Code:
#pragma config(ProgramType, NonCompetition)
#pragma config(UART_Usage, UART1, uartNotUsed, baudRate4800, IOPins, None, None)
#pragma config(Sensor, in1,    pot1,           sensorPotentiometer)
#pragma config(Sensor, in2,    pot2,           sensorPotentiometer)
#pragma config(Motor,  port1,           LeftWheel,     tmotorVex393, openLoop)
#pragma config(Motor,  port8,           RightWheel,    tmotorVex393, openLoop, reversed)
//*!!Code automatically generated by 'ROBOTC' configuration wizard               !!*//

/*************************************************************************************
*         PIC based code for binary serial transmission
*     Should Run on a Cortex as well
*     Primarily to use the PIC as a motor controller
*     for a more capable compute platform
*     Example is provided for the VEX Robot Enthusiast community
*     Much help was provided by James Pearman and CMU
*     This is provided with the hope that improvements will be shared via the Vex Forum
*     Copyright 11/19/2012 Kevin Barrett
*     All 4 timers are used
*         T1 is used for main program timer functions Reset prior to overflow
*     T2 is used in RX char timeout checks
*     T3 is used for packet to packet timeout
*        to stop all motors remotely controlled if no input received
*         T4 is managed by the run time clock (reset every second)
*
*     It is built to control 2 drive motors with Optical Shaft Encoders
*         Added Ultrasonic (SONAR) 1/12/13
**************************************************************************************/

#define  VEXDATAOFFSET          3       // Bytes of static header data in the messages
#define  VEX_DATA_BUFFER_SIZE  20       // size of internal message buffer (older PICs have 20 byte UART buffer)
                                                         // (both tx and rx buffers must be this size or smaller)
#define  RX_MESSAGE_LENGTH 12             // 8 motors 2 bytes A/D or 2 encoders (PIC)
#define  TX_MESSAGE_LENGTH 12             // 8 motors 2 bytes A/D or 2 encoders (PIC)
#define  SYNC_1 0x56
#define  SYNC_2 0xA5
#define TIME_STEP 40                            // minimum wait millisec between transmissions

// because there is no debug stream capability in a PIC program
// these variables are being placed in Global at the top of the listing
// to allow for easy viewing in the RobotC debugger
unsigned int packetRecievedProcessed=0; // how many packets Rx and processed
short localPotentiometer1Value=0,localPotentiometer2Value=0;
short remotePotentiometer1Value=0,remotePotentiometer2Value=0;

int hours=0,minutes=0,seconds=0; // global variables for the run time clock
unsigned int goodPackets=0,badPackets=0; // keep track of good and bad packet reciept

struct {
      unsigned char  header_56;// expect a Sync
      unsigned char  header_A5;// pattern of sorts
      unsigned char  messageLength;// also need to properly set the message length
      //3 bytes (my bookkeeping)
      unsigned char  messageID;
      unsigned char  hours; // hours since robot turned on
      unsigned char  minutes; // minutes since robot turned on
      unsigned char  seconds; // seconds since robot turned on
      unsigned char  potentiometer1High; // Potentiometer readings
      unsigned char  potentiometer1Low;  // one analog port requires
                                                           // 2 bytes of data as values range from 0 to 4095?
      unsigned char  potentiometer2High; // Potentiometer readings
      unsigned char  potentiometer2Low;  // one analog port requires
                                                           // 2 bytes of data as values range from 0 to 4095?
      unsigned char  checksum;
      //12 bytes (my bookkeeping to check message length)
     } outboundData;

union  { // this definition allows the memory to be accessed in two ways
   outboundData data; // as a struct and by the struce member names
   unsigned char    buffer[VEX_DATA_BUFFER_SIZE]; // as a char array which allows
                                                                           // easy serial transmission
  } txVexData;

   txVexData myLastGoodVexDataRx; // local copy for last good received data
   txVexData myVexDataTx; // local copy for transmitted data
   txVexData myVexDataRx; // local copy for received data


void VexTxDataInit() {  // must call at least once before using serial communication
      memset(myVexDataTx.buffer, 0,VEX_DATA_BUFFER_SIZE ); // clear the whole buffer
      // Initialize packet
      myVexDataTx.data.header_56    = SYNC_1; // Set Sync Pattern one
      myVexDataTx.data.header_A5    = SYNC_2; // Set Sync Pattern two
      myVexDataTx.data.messageLength=TX_MESSAGE_LENGTH; // sets the header byte to the proper message length
}

void VexRxDataInit() {  // must call at least once before using serial communication
      memset(myVexDataRx.buffer, 0,VEX_DATA_BUFFER_SIZE ); // clear the whole buffer
      memset(myLastGoodVexDataRx.buffer, 0,VEX_DATA_BUFFER_SIZE ); // clear the whole buffer     
}

void initSerialPort () { // must call at least once before using serial communication
  // There is only one port for general use on a PIC so set it's baud rate
  configureSerialPort(UART1, uartUserControl);
  setBaudRate(UART1, baudRate115200);
  return;
  }


void timeTag() { // provides HH:MM:SS based run time clock
   static short secondsTimeTic=0;
    secondsTimeTic = time1[T4];
    if (secondsTimeTic> 1000) {
       seconds++;
       ClearTimer(T4);// used to reset Timer 4 every 1000 ms to avoid overflow
      }
      if (seconds ==60) {
         seconds = 0;
         minutes++;
      }
      if (minutes == 60) {
         minutes =0;
         hours++;
      }
    return;
  }

void sendVexData() // transmit buffer
   {
  for (int i=0; i <= TX_MESSAGE_LENGTH-1; i++)
     {
    sendChar(UART1, myVexDataTx.buffer[i]);
    while(!bXmitComplete(UART1)) {abortTimeslice();}// test the boolean Xmit Complete flag
    }
   }

   
   void copyVexData() // make a copy of the last good data received
   {
  for (int i=0; i <= RX_MESSAGE_LENGTH-1; i++)
     {
    myLastGoodVexDataRx.buffer[i] = myVexDataRx.buffer[i];
    }
   }

////////////////////////////////////////////////

/*-----------------------------------------------------------------------------*/
/*                                                                             */
/*  Receive data timeout code                                                               */
/*                                                                             */
/*-----------------------------------------------------------------------------*/
static  int timeout     =0; // global variable for persisting timeout duration (0 = timeout not active)

void StartTimeout( )
{
    // Start timeout
      ClearTimer(T2);
    timeout = time1[T2];
}

void StopTimeout( )
{
    // Stop timeout
    timeout = 0;
}

int CheckTimeout( )
{
    // Is timeout running ?
    if( timeout > 0 )
        {
        if((time1[T2] - timeout) < 10)
            return(0);
        else
            return(1);
        }
    return(0);
}
/********************************************************************
Motor Timeout code
*********************************************************************/
static int motorTimeout=0; // global variable for persisting motor drive timeout duration (0 = timeout not active)

void StartMotorTimeout( )
{
    // Start timeout
      ClearTimer(T3);
      motorTimeout=1;
}


int CheckMotorTimeout( )
{
    // Is timeout running ?
    if( motorTimeout > 0 )
        {
        if(time1[T3]  > 80) // 80 millisec ~ 4 packets worth of messages
            return(1);
        else
            return(0);
        }
    return(0);
}


void VexDataChecksumTx(  ) // calculate checksum the same way as the XBEE
{
    int  i;
    int  cs = 0;

    for(i=VEXDATAOFFSET;i<(myVexDataTx.data.messageLength-1);i++)
      cs = cs + myVexDataTx.buffer[i];
    myVexDataTx.data.checksum = 0xFF - (cs & 0xFF);
    return;
}

void VexDataChecksumRx(  ) // calculate checksum the same way as the XBEE
{
    int  i;
    int  cs = 0;

    for(i=VEXDATAOFFSET;i<abs(myVexDataRx.data.messageLength)-1;i++)
      cs = cs + myVexDataRx.buffer[i];
    myVexDataRx.data.checksum = 0xFF - (cs & 0xFF);
    return;
}


task serialRxTask()
{
    static  int serialRxState=0;
    static  short serialDataReceived = 0;
    short c;

    while (true) {
       // check for a received character
       c = getChar(UART1);
       if( c == -1 )
         {
         // -1 implies no received char
         // Check for inter char timeout
         if( CheckTimeout() == 1 ){
           serialRxState = 0;
           StopTimeout();
           }
         abortTimeslice(); // ends thread execution
         continue;
         }
       // A new character has been received so process it.

       // Start inter char timeout used to detect Partial Packet Rx
       StartTimeout();
         // Rx Data state machine
       // Where are we in the message parsing process ?
       switch( serialRxState )
         {
         case  0:
             // look for first header byte
             if( (unsigned char)c == SYNC_1 ) {
              serialRxState++;
             }
             else {
               StopTimeout();
             }
             break;

         case  1:
             // look for second header byte
             if( (unsigned char)c == SYNC_2 ) {
               serialRxState++;
             }
             else
               {
               // Bad message
               StopTimeout();
               serialRxState = 0;
               badPackets++;
               }
             break;


         case  2:
             // next is message length
             myVexDataRx.data.messageLength=c;
             // check to ensure RX datagram is within the size we can accept
             // if it is too large it would cause a memory exception so reject it
             if (myVexDataRx.data.messageLength > VEX_DATA_BUFFER_SIZE) {
               // Bad message
               StopTimeout();
               serialRxState = 0;
               badPackets++;
                     } else { // within bounds so we can accept it although it still might not be good
             serialRxState++;
             serialDataReceived =serialRxState;
              }
             break;

         case  3:
             // receive the data packet
               
             myVexDataRx.buffer[serialDataReceived] = c;
             serialDataReceived++;
             // repeat this step until message length data bytes are received
             if( serialDataReceived >= myVexDataRx.data.messageLength-1){
               serialRxState++;
             }
             // check to avoid buffer overflow conditions
             if( serialDataReceived >= (VEX_DATA_BUFFER_SIZE-1) )
               {
               // Error
               StopTimeout();
               serialRxState = 0;
               badPackets++;
               }
             break;

         case  4:
             // Received checksum byte
             // stop timeout
             StopTimeout();
             // calculate received checksum
             VexDataChecksumRx(  );
             // comapare checksums

             if( (unsigned char)c == myVexDataRx.data.checksum)
               { // Good data
               goodPackets++;
               // Copy Good Data Received to last good data structure
                     // probably should add semaphore code to avoid read access while
                     // writing the copy but thats another day's task
                     copyVexData();
               }
             else
               {
                     badPackets++;
               }
             // done
             serialRxState = 0;
             break;

         default:
         } // end case
       } // end while
} // end task

/*
Main Program


*/
task main()
{

// do these steps once per run
initSerialPort ();
VexTxDataInit();  // initialize data structures
VexRxDataInit();

// Start up the receive serial data task
StartTask(serialRxTask);

while (true) { // begin main program loop
   // Update Sensor Values at the start of the loop
   localPotentiometer1Value  = SensorValue[pot1];
   localPotentiometer2Value  = SensorValue[pot2];
  timeTag(); // update runtime in Hours, Minutes, and Seconds


  if (time1[T1]> TIME_STEP) {
     ClearTimer(T1);
     // Send Data every time step
         // store readings in outboundData struct
       myVexDataTx.data.hours                       = hours; // these are 1 byte copies
       myVexDataTx.data.minutes                    = minutes;
       myVexDataTx.data.seconds                    = seconds;
       myVexDataTx.data.potentiometer1High  = (localPotentiometer1Value >> 8) & 0xFF; // data larger than a byte
       myVexDataTx.data.potentiometer1Low   = localPotentiometer1Value & 0xFF; // must be 'bit banged' into byte sized chunks
       myVexDataTx.data.potentiometer2High  = (localPotentiometer2Value >> 8) & 0xFF;
       myVexDataTx.data.potentiometer2Low   = localPotentiometer2Value & 0xFF;
       VexDataChecksumTx(  );
       sendVexData();
     } // end if Time step  */
     
  // Check if good packet received
     if ( goodPackets > packetRecievedProcessed) {
        packetRecievedProcessed = goodPackets;
        remotePotentiometer1Value = myLastGoodVexDataRx.data.potentiometer1High << 8;
        remotePotentiometer1Value = remotePotentiometer1Value + myLastGoodVexDataRx.data.potentiometer1Low;
        remotePotentiometer2Value = myLastGoodVexDataRx.data.potentiometer2High << 8;
        remotePotentiometer2Value = remotePotentiometer2Value + myLastGoodVexDataRx.data.potentiometer2Low;
     }
     
   }// end main program while loop

} // end task main


Fri May 24, 2013 8:07 am
Profile
Rookie

Joined: Mon Jun 11, 2012 9:28 pm
Posts: 37
Post Re: We're building a body-controlled robot - need some help!
OK, I just tried it out with 2 PIC's.

It's working! However, there's one problem. It seems that there is some interference between the two values. When the value of RemotePotentiometer1Value changes, the value of RemotePotentiometer2Value changes, even when there's no sensor plugged into Port 2 of the remote PIC. When sensors are plugged into both, the cross interference is very noticeable - I fear when I'm using 8 potentiometers is will be unusable. Is there any way to fix this?

(Keep in mind the fact that I don't have any potentiometers on hand at the moment, so I'm using line tracker sensors for my analog values).

Also, I noticed you allocated 2 bytes for each analog value. I'd be OK with just using 1 byte for each analog value, as they will be going straight to motor commands, which are only 1 byte anyway. I'd guess this would make the code simpler and a lot easier to propagate to 8 sensors.

Thanks for your help!


Sat Jun 01, 2013 11:17 am
Profile
Rookie

Joined: Wed Feb 09, 2011 1:08 am
Posts: 27
Post Re: We're building a body-controlled robot - need some help!
Keep in mind if the analog port being read has nothing plugged in the value will bounce around. When I tested the code this afternoon the 2 potentiometer values were transferred accurately. they do vary slightly but that is the nature of the potentiometer. (a little noisy) but in general with 2 potentiometers plugged in the remote potentiometer value tracked independently as desired.

As far as the value being transferred, that would be driven by your particular design. This example was crafted upon the premise that there would be 2 devices an actuator say an arm brace strapped to your arm which would for this example have a potentiometer for the elbow joint, the robot 'elbow' would also have a potentiometer as feed back for a PID loop to control the robot elbow. As the actuator potentiometer value changes the robot arm (under PID control) would track to the same position.


This is a simple linear example, the implementation gets a little more complicated if the sensors aren't the same on each device.

The code example I posted is just the piece to transfer the data from the actuator to the robot.

Cheers Kb


Sat Jun 01, 2013 6:48 pm
Profile
Display posts from previous:  Sort by  
Reply to topic   [ 10 posts ] 

Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  



Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software for PTF.