Thank you ahead of time for anyone willing to help, I'm not asking for you to write me a full code or let me rip off all the hard work you did, I have spent the last 8 weeks building a full sized 6 DOF robotic arm and support structure and learning to program with arduino as I went. I have some programming experiance but this is my first real arduino project. I will post the transmitting and recieving codes. My problem is figuring out how to successfully seperate and use the incomming data for the arduino mega on the robot itself. I am using Xbee S1 for the wireless communications. I have 2 arduino Uno's using the transmit code. The only difference is the second uno transmits the letters d,e, and f instead of a,b, and c. I am using a flex sensor for the gripper and a parallax L3G4200D for the wrist. Only 2 of the angles are used, 1 as the pitch and the other as the rotation of the wrist all attached to 1 uno. On the second is the same configuration except it's a flex sensor at the elbow and the gyro on the shoulder using again only 2 of the angles. Watching the outputs on the serial monitor or using a extra Xbee hooked to my laptop with the putty terminal I see all the outputs as I want them but I can't seem to get the receiving arduino board to use them correctly. Any help would be grateful getting this sorted out, without having to purchase even more equipment preffered (I am a disable vet recycling old projects and selling stuff on ebay just to get this built so my budget is tight)
Transmitting code
//project code for capstone project transmitter side
#include <Wire.h>
#define CTRL_REG1 0x20
#define CTRL_REG2 0x21
#define CTRL_REG3 0x22
#define CTRL_REG4 0x23
int Addr = 105; // I2C address of gyro
int x, y; //removed the z direction
int potpin = 0; // analog pin used to connect the flex sensor
int val; // variable to read the value from the analog pin
void setup(){
Wire.begin();
Serial.begin(9600);
writeI2C(CTRL_REG1, 0x1F); // Turn on all axes, disable power down
writeI2C(CTRL_REG3, 0x08); // Enable control ready signal
writeI2C(CTRL_REG4, 0x80); // Set scale (500 deg/sec)
delay(100); // Wait to synchronize
}
void loop(){
Serial.print("a"); //to seperate claw from elbow data
Serial.println(val);
val = analogRead(potpin); // reads the value of the potentiometer (value between 0 and 1023)
getGyroValues(); // Get new values
// In following Dividing by 114 reduces noise
Serial.print("b"); Serial.println(x / 114); // x is up and down
delay(10); //added delay to match input read time on robot side
Serial.print("c"); Serial.println(y / 114); // y wrist rotation added ln to the print function to end the line
//Serial.print(" Raw Z:"); Serial.println(z / 114); // commented out not being used
delay(500); // Short delay between reads
}
void getGyroValues () {
byte MSB, LSB;
MSB = readI2C(0x29);
LSB = readI2C(0x28);
x = ((MSB << 8) | LSB);
MSB = readI2C(0x2B);
LSB = readI2C(0x2A);
y = ((MSB << 8) | LSB);
//not being used
//MSB = readI2C(0x2D);
//LSB = readI2C(0x2C);
//z = ((MSB << 8) | LSB);
}
int readI2C (byte regAddr) {
Wire.beginTransmission(Addr);
Wire.write(regAddr); // Register address to read
Wire.endTransmission(); // Terminate request
Wire.requestFrom(Addr, 1); // Read a byte
while(!Wire.available()) { }; // Wait for receipt
return(Wire.read()); // Get result
}
void writeI2C (byte regAddr, byte val) {
Wire.beginTransmission(Addr);
Wire.write(regAddr);
Wire.write(val);
Wire.endTransmission();
}
the reciever still under constant construction...
//project for robotic arm portion of final capstone
#include <Servo.h>
char inchar;
Servo gripperServo; //creates servo object
Servo wristServoR;
Servo wristServoP;
Servo elbowServo;
Servo shoulderServoR;
Servo shoulderServoP;
int pos = 0; // variable to store the servo position
int val; //read value input
int gripperPos; //reads value from gripper flex sensor
int wristRPos; //reads value from wrist rotation
int wristPPos; //reads value from wrist pitch
int elbowPos; //reads elbow flex sensor
int shoulderRPos; //reads shoulder rotation
int shoulderPPos; //reads shoulder pitch
void setup()
{
Serial.begin(9600); //start serial transmition
gripperServo.attach(8); //gripper to pin 8
wristServoR.attach(9); //rotating wrist to pin 9
wristServoP.attach(10); //flexing wrist to pin 10
elbowServo.attach(11); //elbow to pin 11
shoulderServoR.attach(12); //rotating shoulder to pin 12
shoulderServoP.attach(13); //flexing shoulder to pin 13
}
void loop()
{
if ( Serial.available() > 0) //if a signal comes through Xbee
{
inchar = Serial.read();
if ( inchar == '#') //the start of our command string
{
delay(10); //time to read and get next bit
inchar = Serial.read(); //recieve the next bit
if (inchar == 'a') //detects the letter to know which servo to send command to
{
delay(10);
inchar = Serial.read();
if (inchar <### ) //replace ### with actual read out numbers
{
gripperPos = gripperPos + 1; //update the position of the gripper higher
}
else if (inchar >### )
{
gripperPos = gripperPos - 1; //update the position of the gripper lower
}
delay(10); //time to read and get next bit
inchar = Serial.read(); //recieve the next bit
if (inchar == 'b') //detects the letter to know which servo to send command to
{
delay(10);
inchar = Serial.read();
if (inchar <### ) //replace ### with actual read out numbers
{
wristRPos = wristRPos + 1; //update the position of the wrist rotation higher
}
else if (inchar >### )
{
wristRPos = wristRPos - 1; //update the position of the wrist rotation lower
}
delay(10);
inchar = Serial.read(); //recieve the next bit
if (inchar == 'c') //detects the letter to know which servo to send command to
{
delay(10);
inchar = Serial.read();
if (inchar <### ) //replace ### with actual read out numbers
{
wristPPos = wristPPos + 1; //update the position of the wrist pitch higher
}
else if (inchar >### )
{
wristPPos = wristPPos - 1; //update the position of the wrist pitch lower
}
delay(10);
inchar = Serial.read(); //recieve the next bit
if (inchar == 'd') //detects the letter to know which servo to send command to
{
delay(10);
inchar = Serial.read();
if (inchar <### ) //replace ### with actual read out numbers
{
elbowPos = elbowPos + 1; //update the position of the elbow higher
}
else if (inchar >### )
{
elbowPos = elbowPos - 1; //update the position of the elbow lower
}
delay(10);
inchar = Serial.read(); //recieve the next bit
if (inchar == 'e') //detects the letter to know which servo to send command to
{
delay(10);
inchar = Serial.read();
if (inchar <### ) //replace ### with actual read out numbers
{
shoulderRPos = shoulderRPos + 1; //update the position of the shoulder rotation higher
}
else if (inchar >### )
{
shoulderRPos = shoulderRPos - 1; //update the position of the shoulder rotation lower
}
delay(10);
inchar = Serial.read(); //recieve the next bit
if (inchar == 'f') //detects the letter to know which servo to send command to
{
delay(10);
inchar = Serial.read();
if (inchar <### ) //replace ### with actual read out numbers
{
shoulderPPos = shoulderPPos + 1; //update the position of the shoulder pitch higher
}
else if (inchar >### )
{
shoulderPPos = shoulderPPos - 1; //update the position of the shoulder pitch lower
}
delay(10);
}
}
}
}
On the HyperTerminal on my laptop that I have an Xbee directly linked to for debugging I get numbers like:
a136
b0
c0
d145
e0
f0
when both gyros are stationary, the flex resistor sensors still supply numbers. However the serial monitor for the Mega operating the robot arm I get nothing, or I will receive the "a" with the value one time and then nothing else again. I thought that it might be getting caught in a infinite loop. At the bottom of the receiving code I had added the "servoname".write(servoPos) for each servo but it had no reaction so I removed it and this is where I have my head banging against a wall. My intent was to have it read in the numbers and then simply add or subtract from it's current position in relation to the amount of time the gyro was moving since these are rate gyros and not the far more expensive directional gyros. I want the code to wait for a specific letter (a-f) to come through the Xbee and then grab the next set of numbers to adjust the servos then simply move on to the next letter.
Serial.print("a"); //to seperate claw from elbow data
Serial.println(val);
val = analogRead(potpin); // reads the value of the potentiometer (value between 0 and 1023)
Send an 'a'. Send a value. Get a value to send. Doesn't that order seem illogical?
delay(10); //added delay to match input read time on robot side
No. You should investigate hand-shaking. The sender should only send data when the receiver indicates that it is ready.
Edit: The values that you are sending do not represent incremental values. If the sensor hasn't changed, there is no reason to send the same data again.
as far as the first portion about the sending a letter, then sending a value, then getting the value... That part seems odd I know, but it does work, it does get the values and then send them right away. I'm not having a problem with that portion of the code.
I added the delay to slow down the transmitting a little because I thought I might be sending data too fast for the receiver to run through the loop and then get the next letter. This is my first time trying to send more then one signal so I wasn't sure just how quick it could process 6 signals on the receiving end.
Edit: The values that you are sending do not represent incremental values. If the sensor hasn't changed, there is no reason to send the same data again
So are you saying that it would make a difference when the gyros are not moving I shouldn't send the "0" position?
as far as the first portion about the sending a letter, then sending a value, then getting the value... That part seems odd I know, but it does work, it does get the values and then send them right away. I'm not having a problem with that portion of the code.
It sends an old value. Then, it gets a new value.
If you know that the code is illogical, why don't you spend 2 seconds to fix it?
So are you saying that it would make a difference when the gyros are not moving I shouldn't send the "0" position?
What I know is that sending data, and processing it on the receiving end, takes time. If nothing has changed, then sending the same old data, and processing it again, seems pointless. Nothing will change on the receiving end.
Sending data only when there is something new to report will make the receiver more responsive.
It's not clear what your problem is, really.
My problem is figuring out how to successfully seperate and use the incomming data for the arduino mega on the robot itself.
if ( inchar == '#') //the start of our command string
{
void loop()
{
if ( Serial.available() > 0) //if a signal comes through Xbee
{
inchar = Serial.read();
if ( inchar == '#') //the start of our command string
{
delay(10); //time to read and get next bit
inchar = Serial.read(); //recieve the next bit
if (inchar == 'a') //detects the letter to know which servo to send command to
{
delay(10);
inchar = Serial.read();
if (inchar <### ) //replace ### with actual read out numbers
{
gripperPos = gripperPos + 1; //update the position of the gripper higher
}
else if (inchar >### )
{
gripperPos = gripperPos - 1; //update the position of the gripper lower
}
delay(10); //time to read and get next bit
inchar = Serial.read(); //recieve the next bit
if (inchar == 'b') //detects the letter to know which servo to send command to
{
delay(10);
inchar = Serial.read();
if (inchar <### ) //replace ### with actual read out numbers
{
wristRPos = wristRPos + 1; //update the position of the wrist rotation higher
}
else if (inchar >### )
{
wristRPos = wristRPos - 1; //update the position of the wrist rotation lower
}
delay(10);
inchar = Serial.read(); //recieve the next bit
if (inchar == 'c') //detects the letter to know which servo to send command to
{
delay(10);
inchar = Serial.read();
if (inchar <### ) //replace ### with actual read out numbers
{
wristPPos = wristPPos + 1; //update the position of the wrist pitch higher
}
else if (inchar >### )
{
wristPPos = wristPPos - 1; //update the position of the wrist pitch lower
}
delay(10);
inchar = Serial.read(); //recieve the next bit
if (inchar == 'd') //detects the letter to know which servo to send command to
{
delay(10);
inchar = Serial.read();
if (inchar <### ) //replace ### with actual read out numbers
{
elbowPos = elbowPos + 1; //update the position of the elbow higher
}
else if (inchar >### )
{
elbowPos = elbowPos - 1; //update the position of the elbow lower
}
delay(10);
inchar = Serial.read(); //recieve the next bit
if (inchar == 'e') //detects the letter to know which servo to send command to
{
delay(10);
inchar = Serial.read();
if (inchar <### ) //replace ### with actual read out numbers
{
shoulderRPos = shoulderRPos + 1; //update the position of the shoulder rotation higher
}
else if (inchar >### )
{
shoulderRPos = shoulderRPos - 1; //update the position of the shoulder rotation lower
}
delay(10);
inchar = Serial.read(); //recieve the next bit
if (inchar == 'f') //detects the letter to know which servo to send command to
{
delay(10);
inchar = Serial.read();
if (inchar <### ) //replace ### with actual read out numbers
{
shoulderPPos = shoulderPPos + 1; //update the position of the shoulder pitch higher
}
else if (inchar >### )
{
shoulderPPos = shoulderPPos - 1; //update the position of the shoulder pitch lower
}
delay(10);
}
}
}
}
I'm not certain, but I think its quicker than a series of if statements.
example:
void loop()
{
if ( Serial.available() > 0) //if a signal comes through Xbee
{
inchar = Serial.read();
if ( inchar == '#') //the start of our command string
{
delay(10); //time to read and get next bit
inchar = Serial.read();
switch(inchar){
case 'a':
delay(10);
inchar = Serial.read();
if (inchar <### ) //replace ### with actual read out numbers
{
gripperPos = gripperPos + 1; //update the position of the gripper higher
}
else if (inchar >### )
{
gripperPos = gripperPos - 1; //update the position of the gripper lower
}
delay(10);
break;
case 'b':
//etc
Thank you for those that responded. I have never used cases but I will look into that. As far as the wasted coding and not fixing an old issue, I have fixed it, thank you for pointing it out. As far as the ### in the inchar I meant that for the number received from the transmitting arduinos, it is a 3 digit number such as from the flex sensor and the gyros.
To paulS, I understand that it can be frustrating reading posts like mine so I am sorry, I am just humbly asking for advice and do not mean to hurt anyone's eyes with my poor code writing.
I'm having difficulty following your setup, but perhaps the slave arduino controlling the servos could have receiving code like below. Then you could focus on the sending code making the calculations and sending the servo commands in this type format.
//zoomkat 11-22-12 simple delimited ',' string parse
//from serial port input (via serial monitor)
//and print result out serial port
//multi servos added
String readString;
#include <Servo.h>
Servo myservoa, myservob, myservoc, myservod; // create servo object to control a servo
void setup() {
Serial.begin(9600);
//myservoa.writeMicroseconds(1500); //set initial servo position if desired
myservoa.attach(6); //the pin for the servoa control
myservob.attach(7); //the pin for the servob control
myservoc.attach(8); //the pin for the servoc control
myservod.attach(9); //the pin for the servod control
Serial.println("multi-servo-delimit-test-dual-input-11-22-12"); // so I can keep track of what is loaded
}
void loop() {
//expect single strings like 700a, or 1500c, or 2000d,
//or like 30c, or 90a, or 180d,
//or combined like 30c,180b,70a,120d,
if (Serial.available()) {
char c = Serial.read(); //gets one byte from serial buffer
if (c == ',') {
if (readString.length() >1) {
Serial.println(readString); //prints string to serial port out
int n = readString.toInt(); //convert readString into a number
// auto select appropriate value, copied from someone elses code.
if(n >= 500)
{
Serial.print("writing Microseconds: ");
Serial.println(n);
if(readString.indexOf('a') >0) myservoa.writeMicroseconds(n);
if(readString.indexOf('b') >0) myservob.writeMicroseconds(n);
if(readString.indexOf('c') >0) myservoc.writeMicroseconds(n);
if(readString.indexOf('d') >0) myservod.writeMicroseconds(n);
}
else
{
Serial.print("writing Angle: ");
Serial.println(n);
if(readString.indexOf('a') >0) myservoa.write(n);
if(readString.indexOf('b') >0) myservob.write(n);
if(readString.indexOf('c') >0) myservoc.write(n);
if(readString.indexOf('d') >0) myservod.write(n);
}
readString=""; //clears variable for new input
}
}
else {
readString += c; //makes the string readString
}
}
}
smeezekitty:
Perhaps you want to run atoi() on the incoming data.
but only after the 3 values (will it always be 3 values ? ) have been concatenated together in a null terminated array or have been dealt with individually by using atoi(), multiplying by the appropriate factor of 10 and added to the result.
If the number will not always be 3 digits then neither scheme will work and something to indicate the end of digit will need to be sent and recognised, which would be a good idea anyway.
Thank you for all the advise, I did go with the case operations and it's working very well. Now I just need to clean it up and adjust the speeds and delays a little. Mostly tweaking and getting a way to stop the incease and decrease values for the servos when they hit there limit. Other then that I'm good to go, here is the fixed code as well incase someone else runs into this kind of issue and thinks my code could be usefull or atleast send you in a more generally correct direction.
[code]
//project code for capstone project transmitter side
#include <Wire.h>
#define CTRL_REG1 0x20
#define CTRL_REG2 0x21
#define CTRL_REG3 0x22
#define CTRL_REG4 0x23
int Addr = 105; // I2C address of gyro
int x, y; //removed the z direction
int potpin = 0; // analog pin used to connect the flex sensor
int val; // variable to read the value from the analog pin
int pos;
void setup(){
Wire.begin();
Serial.begin(9600);
writeI2C(CTRL_REG1, 0x1F); // Turn on all axes, disable power down
writeI2C(CTRL_REG3, 0x08); // Enable control ready signal
writeI2C(CTRL_REG4, 0x80); // Set scale (500 deg/sec)
delay(100); // Wait to synchronize
}
void loop()
{
val = analogRead(potpin); // reads the value of the potentiometer (value between 0 and 1023)
pos = map(val, 60, 150, 0, 179);
//Serial.println(pos);
if(pos <= 60 )
{
Serial.println('1');
delay(50);
}
if(pos >= 100)
Serial.println('2');
delay(50);
{
}
delay(50);
getGyroValues(); // Get new values
// In following Dividing by 114 reduces noise
if(x / 114 <= -5)
{
Serial.println('3');
delay(50);
}
if(x / 114 >= 5)
{
Serial.println('4');
delay(50);
}
if(y / 114 <= -5)
{
Serial.println('5');
delay(50);
}
if (y / 114 >= 5)
{
Serial.println('6');
delay(50);
}
delay(250);
}
void getGyroValues () {
byte MSB, LSB;
MSB = readI2C(0x29);
LSB = readI2C(0x28);
x = ((MSB << 8) | LSB);
MSB = readI2C(0x2B);
LSB = readI2C(0x2A);
y = ((MSB << 8) | LSB);
//not being used
//MSB = readI2C(0x2D);
//LSB = readI2C(0x2C);
//z = ((MSB << 8) | LSB);
}
int readI2C (byte regAddr)
{
Wire.beginTransmission(Addr);
Wire.write(regAddr); // Register address to read
Wire.endTransmission(); // Terminate request
Wire.requestFrom(Addr, 1); // Read a byte
while(!Wire.available()) {
}; // Wait for receipt
return(Wire.read()); // Get result
}
void writeI2C (byte regAddr, byte val)
{
Wire.beginTransmission(Addr);
Wire.write(regAddr);
Wire.write(val);
Wire.endTransmission();
}
then on the receving end I went with this
//newest test for recieving robotics arm
#include <Servo.h>
Servo gripperServo, wristRServo, wristPServo; //create the servo object by name
int gripperPos;
int wristPPos;
int wristRPos;
void setup()
{
Serial.begin(9600); //start serial transmition
gripperServo.attach(3); //attach gripper to pin 3
wristRServo.attach(5); //attach wrist rotation to pin 5
wristPServo.attach(9); //attach wrist pitch to pin 7
}
void loop()
{
if ( Serial.available()) //if a signal comes through the XBEE
{
char ch = Serial.read();
switch(ch)
{
case '1':
gripperClose();
break;
case'2':
gripperOpen();
break;
case '3':
wristRClose();
break;
case '4':
wristROpen();
break;
case '5':
wristPClose();
break;
case '6':
wristPOpen();
break;
default:
//Serial.print(ch);
//Serial.println("was recieved but not expected");
break;
}
}
}
void gripperClose()
{
gripperPos = gripperPos + 20;
gripperServo.write(gripperPos);
}
void gripperOpen()
{
gripperPos = gripperPos - 20;
gripperServo.write(gripperPos);
}
void wristRClose()
{
wristRPos = wristRPos + 20;
wristRServo.write(wristRPos);
}
void wristROpen()
{
wristRPos = wristRPos - 20;
wristRServo.write(wristRPos);
}
void wristPClose()
{
wristPPos = wristPPos + 20;
wristPServo.write(wristPPos);
}
void wristPOpen()
{
wristPPos = wristPPos - 20;
wristPServo.write(wristPPos);
}
I recommend always following each for, if, else, while and so on conditional statement with a pair of { and }, even if you only have a single statement between them. It makes it more obvious what structure you intend, and reduces the risk of maintenance induced errors later.
Tools/autoformat is a very good way to sort out the indentation of your code to make the control structure clear. I recommend putting each { and } on a separate line before running tools/autoformat.
amazingly enough the number 114 which is the divider for the gyroscope I use.... I found it on a accelerometer project I had done before, and when I spent a dozen hours trying to tweak them just right I accidently opened up the old balancing code and tried it, works like a charm with the gyros I mentioned on the first post. I have corrected the alignment problems in the code as well, thank you all for your time and consideration. It was just a matter of getting over that one little hurdle and now my project is back on track and moving ahead nicely. I have 2 more weeks to tweak the code a bit more and reinforce a couple structure weaknesses I had with the shoulder joints on the physical model. Cheers to all of you that were nice and helpful and not condescending