|
Page 1 of 1
|
[ 10 posts ] |
|
We're building a body-controlled robot - need some help!
Author |
Message |
sqiddster
Rookie
Joined: Mon Jun 11, 2012 9:28 pm Posts: 37
|
 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 |
|
 |
fretless_kb
Rookie
Joined: Wed Feb 09, 2011 1:08 am Posts: 27
|
 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 |
|
 |
magicode
Moderator
Joined: Tue Sep 14, 2010 9:19 pm Posts: 496
|
 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 |
|
 |
sqiddster
Rookie
Joined: Mon Jun 11, 2012 9:28 pm Posts: 37
|
 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 |
|
 |
fretless_kb
Rookie
Joined: Wed Feb 09, 2011 1:08 am Posts: 27
|
 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 |
|
 |
fretless_kb
Rookie
Joined: Wed Feb 09, 2011 1:08 am Posts: 27
|
 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 |
|
 |
sqiddster
Rookie
Joined: Mon Jun 11, 2012 9:28 pm Posts: 37
|
 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  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 |
|
 |
fretless_kb
Rookie
Joined: Wed Feb 09, 2011 1:08 am Posts: 27
|
 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 |
|
 |
sqiddster
Rookie
Joined: Mon Jun 11, 2012 9:28 pm Posts: 37
|
 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 |
|
 |
fretless_kb
Rookie
Joined: Wed Feb 09, 2011 1:08 am Posts: 27
|
 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 |
|
|
|
Page 1 of 1
|
[ 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
|
|