Pages: [1]   Go Down
Author Topic: Communication b/w Java Monkey Engine and Arduino  (Read 1095 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi everyone

I'm trying to create a program that has an Arduino and JME sending data back and forth. The Arduino is supposed to send data to the computer, which interprets it and sends back a  value for a servo on the Arduino. It’s basically simulating a servo rotating that matches the servo rotation in real life. The servo’s rotation is based on force-sensitive resistors. The data transfer is like so:

Value of FSR is sent to Java program from Arduino ---> Java program calculates value for servo ---> value for servo is sent to arduino ---> value is written to servo.

The values are being written to the virtual servo correctly, which I think rules out a problem in the Java program or in the initial data transfer of the FSR data. So there is probably a problem with the data being sent back to the Arduino.

I think this is the Arduino code that is causing the problem:

Code:
  if (abs(servoval) >= 360)servoval = 0;
   Serial.println(servoval);
   servoval = ((float)Serial.read())/100;
   myservo.write(servoval);

When this code is implemented, only the change in the servo value is written to the servo. This leads me to the conclusion that there is a disconnection between the cycles per second of the Arduino and the computer running the Java code.

I’m honestly not sure, and any input is welcomed.
Thanks.
« Last Edit: March 03, 2011, 11:04:29 am by Monorail » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Where is the code that writes to the serial port? Is it writing binary values or strings?

Code:
   if (abs(servoval) >= 360)servoval = 0;
   Serial.println(servoval);
   servoval = ((float)Serial.read())/100;
   myservo.write(servoval);
Where is the call to Serial.available() to determine that there is anything to read?

Serial.read() returns a byte, containing a value in the range 0 to 255. You are casting that to a float. Why?

You are then performing integer division. Why?

Quote
When this code is implemented, only the change in the servo value is written to the servo.
Then, why are you treating it as an absolute value?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Where is the code that writes to the serial port? Is it writing binary values or strings?

Code:
   if (abs(servoval) >= 360)servoval = 0;
   Serial.println(servoval);
   servoval = ((float)Serial.read())/100;
   myservo.write(servoval);
Where is the call to Serial.available() to determine that there is anything to read?

Serial.read() returns a byte, containing a value in the range 0 to 255. You are casting that to a float. Why?

You are then performing integer division. Why?

Quote
When this code is implemented, only the change in the servo value is written to the servo.
Then, why are you treating it as an absolute value?

Hey. Thanks for responding.

Are you talking about the Java code that writes to the serial port? It is writing strings. I didn't know that Serial.available() was a command. I'm very new to Arduino programming, and sending data over serial in general. I'll try that next time I get a chance.

A single call to Serial.read() can only return one byte? So Serial.available() must be used as the condition for a while loop with Serial.read() to put the string back together?

Code:
if (abs(servoval) >= 360)servoval = 0;
This line is probably superfluous. I think it may just be a remnant from some testing that I was doing. In any case, there are two FSRs, one that adds to the servo's value, and one that detracts from it. This presents the possibility of the servo going farther than -360 or 360 degrees, which will cause the servo to stop working unless it is reset to 0.

Thanks again for your help.
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
A single call to Serial.read() can only return one byte? So Serial.available() must be used as the condition for a while loop with Serial.read() to put the string back together?
Yes and yes.

Quote
This line is probably superfluous.
No, it isn't. But, are your servos capable of turning to 360 degrees? To negative angles? I don't think your limit checks are valid.

The code I was questioning, though, is not the first line of that block. It is the last two lines. Casting the byte read from the serial port to a float is completely unnecessary. Why are you dividing by 100?

In any case, if the monkey is sending relative values, you need to add the relative value to some previous value to get an absolute value. Servo.write() takes an absolute value. Servo.write(5) does NOT cause the servo to rotate 5 more degrees. It causes it to rotate TO 5 degrees.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
This line is probably superfluous.
No, it isn't. But, are your servos capable of turning to 360 degrees? To negative angles? I don't think your limit checks are valid.
No, but the servo that I wrote in the Java program is. I forgot to mention that it's superfluous because the angle is determined completely by the Java program, so changing it in the Arduino doesn't make sense. Also, my physical servo is 180 degrees.

The code I was questioning, though, is not the first line of that block. It is the last two lines. Casting the byte read from the serial port to a float is completely unnecessary. Why are you dividing by 100?
You're right. I need to fix that. I thought that a single Serial.read() returned the entire string that was sent from the Java program. A single byte being returned makes much more sense when I think about it.

In any case, if the monkey is sending relative values, you need to add the relative value to some previous value to get an absolute value. Servo.write() takes an absolute value. Servo.write(5) does NOT cause the servo to rotate 5 more degrees. It causes it to rotate TO 5 degrees.
I'm not sending relative values, the Java program sends the value of the virtual servo's angle.

Why are you dividing by 100?
The writestream in Java can only send integers, so I multiply it by 100 and cast it to an int to save the last couple of decimal points, then divide it by 100 on the Arduino side to return it to a float.
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
No, but the servo that I wrote in the Java program is. I forgot to mention that it's superfluous because the angle is determined completely by the Java program, so changing it in the Arduino doesn't make sense. Also, my physical servo is 180 degrees.
Shouldn't the model (in Java) match the real world?

Quote
I'm not sending relative values, the Java program sends the value of the virtual servo's angle.
In your original post, you said you were.

Quote
The writestream in Java can only send integers, so I multiply it by 100 and cast it to an int to save the last couple of decimal points, then divide it by 100 on the Arduino side to return it to a float.
Why? The Servo.write() function takes integer input.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
No, but the servo that I wrote in the Java program is. I forgot to mention that it's superfluous because the angle is determined completely by the Java program, so changing it in the Arduino doesn't make sense. Also, my physical servo is 180 degrees.
Shouldn't the model (in Java) match the real world?

Right. So that's why I originally said that the line in the Arduino code isn't needed.
Quote
I'm not sending relative values, the Java program sends the value of the virtual servo's angle.
In your original post, you said you were.
My bad. I meant to say that the value of the servo is sent after being manipulated by the FSR.

Quote
The writestream in Java can only send integers, so I multiply it by 100 and cast it to an int to save the last couple of decimal points, then divide it by 100 on the Arduino side to return it to a float.
Why? The Servo.write() function takes integer input.
But it also takes float input, which is more precise.

This is the code that I'm using now.
Code:
  Serial.println(servoval);
   input = ""; //declared in higher scope
   while(Serial.available()){
   input += (char)Serial.read();
   }
    char carray[input.length() + 1]; //determine size of the array
    input.toCharArray(carray, sizeof(carray)); //put input an array
    servoval = atoi(carray)/100; //convert the array into an Integer
   myservo.write(servoval);
It seems to be having the same problem though. I also don't think that redeclaring carray each time is very efficient, but I'm not sure how to do it otherwise.
Once again, thanks. I really appreciate this.
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Right. So that's why I originally said that the line in the Arduino code isn't needed.
We seem to have a failure to communicate here. If the physical servo can move from 0 to 180, and the virtual servo can move from 0 to 360, the model DOES NOT match the physical world.

Quote
My bad. I meant to say that the value of the servo is sent after being manipulated by the FSR.
Now, this might be interesting to watch. I don't believe I have ever seen a force sensing resistor manipulate a servo. Does it get up and crank the servo around?

Quote
But it also takes float input, which is more precise.
From Servo.h:
Code:
  void write(int value);             // if value is < 200 its treated as an angle, otherwise as pulse width in microseconds
  void writeMicroseconds(int value); // Write pulse width in microseconds
Which of those methods "takes float input, which is more precise."?

Quote
It seems to be having the same problem though. I also don't think that redeclaring carray each time is very efficient, but I'm not sure how to do it otherwise.
The problem isn't with redeclaring carray each time.

The problem is that serial data transmission takes time.
Code:
while(Serial.available()){
   input += (char)Serial.read();
   }
Whatever serial data has arrived since the last time any data was read is read and stored in a String.

Whatever is in that String object is extracted, converted to an int and divided by 100 and used to position the servo.

Suppose the sender sent "15000". You will get the data in increments "1", "50", "0", "0", maybe.

Prove to yourself that that is what is happening. After the while loop, put a Serial.println(input); statement. What gets printed will not be what you expect.

Your sender needs to send some kind of end-of-packet marker, and the receiver needs to keep reading data until that end of packet marker arrives. Then, and only then, should it interpret and the value.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Right. So that's why I originally said that the line in the Arduino code isn't needed.
We seem to have a failure to communicate here. If the physical servo can move from 0 to 180, and the virtual servo can move from 0 to 360, the model DOES NOT match the physical world.
I have Java code that ensures that the virtual servo can only move between 0 and 180.

Quote
My bad. I meant to say that the value of the servo is sent after being manipulated by the FSR.
Now, this might be interesting to watch. I don't believe I have ever seen a force sensing resistor manipulate a servo. Does it get up and crank the servo around?
Not exactly sure what you mean. It moves the servo based on how hard the FSR is pressed.

Quote
But it also takes float input, which is more precise.
From Servo.h:
Code:
 void write(int value);             // if value is < 200 its treated as an angle, otherwise as pulse width in microseconds
  void writeMicroseconds(int value); // Write pulse width in microseconds
Which of those methods "takes float input, which is more precise."?
Guess I just had a misconception. If I'm only capable of writing integer values, then I could probably just send one byte containing the value of the servo's angle.

Quote
It seems to be having the same problem though. I also don't think that redeclaring carray each time is very efficient, but I'm not sure how to do it otherwise.
The problem isn't with redeclaring carray each time.

The problem is that serial data transmission takes time.
Code:
while(Serial.available()){
   input += (char)Serial.read();
   }
Whatever serial data has arrived since the last time any data was read is read and stored in a String.

Whatever is in that String object is extracted, converted to an int and divided by 100 and used to position the servo.

Suppose the sender sent "15000". You will get the data in increments "1", "50", "0", "0", maybe.

Prove to yourself that that is what is happening. After the while loop, put a Serial.println(input); statement. What gets printed will not be what you expect.

Your sender needs to send some kind of end-of-packet marker, and the receiver needs to keep reading data until that end of packet marker arrives. Then, and only then, should it interpret and the value.
That would be consistent with what is happening. Can you recommend a good way to denote the end of a packet? Maybe a standard character that is sent?

Thanks.
« Last Edit: March 04, 2011, 01:31:16 pm by Monorail » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I have Java code that ensures that the virtual servo can only move between 0 and 180.
Well,this explains why you need to constrain the value on the Arduino to -360 to +360. Or not.

Quote
It moves the servo based on how hard the FSR is pressed.
In that sentence, "It" is a pronoun with no referent. I have no idea what "it" is.

Quote
Guess I just had a misconception. If I'm only capable of writing integer values, then I could probably just send one byte containing the value of the servo's angle.
If the application is capable of sending binary data to the serial port, yes, you could.

Quote
That would be consistent with what is happening. Can you recommend a good way to denote the end of a packet? Maybe a standard character that is sent?
Any character that is not part of the normal stream of data - !, ;, or > arre typical end-of-packet markers, along with carriage return and line feed.
Logged

Pages: [1]   Go Up
Jump to: