here's a visual of what i'm playing with: iPhone Controlled Robotic Arm on Vimeo
the script i used for the video above works fairly well - except it's not smart and sometimes it will write to the wrong servos and i'd have to manually change the order in which i was writing to the servos in the code. that code can be found here: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1291012063
so i set off to find a better way of sending multiple variables via serial to the arduino. i found a bunch of posts by PaulS saying search for: "started && ended" in the forums... after some searching i found the "packet" technique he was referring to.
i began to implement.
what WAS a processing script capturing OSC messages from my iphone is now replaced by this ruby script:
# require libraries
%w[ rubygems osc-ruby serialport ].each { |lib| require lib }
# connect to arduino
@sp = SerialPort.new "/dev/tty.usbserial-A800etAZ", 9600, 8, 1, SerialPort::NONE
# initial arm position
@shoulder, @forearm, @elbow, @claw = 180, 50, 60, 35
# setup osc server so we can listen for messages from the multi-touch on my iphone
osc_server = OSC::Server.new 'razic.local', 4000
# these are the osc patterns and their callbacks
# it's callback is triggered when a osc message matching one of our addresses is received
osc_addrs = [
["/1/shoulder_forearm", Proc.new { |m| @shoulder, @forearm = *m.instance_variable_get(:@args); }],
["/1/elbow", Proc.new { |m| @elbow = m.instance_variable_get(:@args)[0]; }],
["/1/claw", Proc.new { |m| @claw = m.instance_variable_get(:@args)[0]; }]
]
osc_addrs.each { |a| osc_server.add_method a[0], &a[1] }
# run the osc server in a new thread
Thread.new { osc_server.run }
# start talking to the arduino
loop do
# serially send 4 packets (one for each servo)
@sp.write "<s#{@shoulder.to_i}><f#{@forearm.to_i}><e#{@elbow.to_i}><c#{@claw.to_i}>"
sleep 1
end
and here is the new arduino code that interprets the packets and writes to the appropriate motor:
#include <Servo.h>
Servo shoulder, forearm, elbow, claw;
int shoulder_pin = 3;
int forearm_pin = 5;
int elbow_pin = 6;
int claw_pin = 9;
int baud = 9600;
char buff[4];
byte i = 0;
boolean started = false;
boolean ended = false;
void setup(){
Serial.begin(baud);
shoulder.attach(shoulder_pin);
forearm.attach(forearm_pin);
elbow.attach(elbow_pin);
claw.attach(claw_pin);
}
void loop(){
while(Serial.available() > 0){
char aChar = Serial.read();
if(aChar == '<'){
started = true;
ended = false;
}
else if(aChar == '>'){
ended = true;
break; // break the while loop
}
else {
buff[i] = aChar;
i++;
buff[i] = '\0'; // this terminates the array
}
}
if(started && ended){
int intpos;
char pos[3] = { buff[1], buff[2], buff[3] };
intpos = atoi(pos);
Serial.print("Writing motor ");
Serial.print(buff[0]);
Serial.print(" to ");
Serial.println(intpos);
Serial.println();
if(buff[0] == 's') shoulder.write(intpos);
if(buff[0] == 'f') forearm.write(intpos);
if(buff[0] == 'e') elbow.write(intpos);
if(buff[0] == 'c') claw.write(intpos);
i = 0;
buff[i] = '\0'; // this terminates the array
started = false;
ended = false;
}
}
so heres the big problem: in the ruby script, i put a one second delay between every loop that it writes the servo positions to the arduino.
this works well. but much to slow to emulate my actual fingers movement on the iphone's multitouch. in the old code, (in the link above) i had no delay and it worked really smooth and reacted almost perfectly to realtime.
as soon as i change the delay to 0.1 second the arm flips out and starts moving when it shouldnt etc..
is this because of packet loss/interuption? keep in mind that i am constantly writing the servo position even if it's unchanged since the last time.