Connect your Mini Maestro to COM5 (or adjust COM5 in the code below)
Grab the free “iSensor” app from the store onto your iPhone/iPod/iPad and set it to port 5000 (or adjust port in code below)
Wiggle baby!
- Disconnect anytihng that blows up or chops fingers prior to the above, OK?
If anyone knows how to talk to the Maestro using DLLs (eg: USB instead of serial commands), PLEASE let me know here => https://forum.pololu.com/t/driving-the-maestro-via-usb-by-calling-driver-dlls-how/3978/1
#!/usr/bin/perl
our $VERSION='0.20111215';
=head1 NAME
iPhone_Servo_Mover.pl - Wiggle your Maestro servos in response to the orientation of your iPhone
=head1 SYNOPSIS
Grab the free iSensor app from the app store.
Set it broadcasting (port 5000 - you can change that below if you want), or unicasting to your PCs IP
perl iPhone_Servo_Mover.pl
Wiggle!
=head1 Installing
I'm using ActivePerl from ActiveState.
Put this:-
http://cpansearch.perl.org/src/BBIRTH/Win32-SerialPort-0.22/lib/Win32API/CommPort.pm
into C:\Perl64\site\lib\Win32API
And put this:-
http://cpansearch.perl.org/src/BBIRTH/Win32-SerialPort-0.22/lib/Win32/SerialPort.pm
into C:\Perl64\site\lib\Win
=head1 TESTING NETWORKING (does not work)
Do this (from a different window, while iPhone_Servo_Mover.pl is running)
perl iPhone_Servo_Mover.pl -t 'Some test data'
=head1 DESCRIPTION
Sends the orientation data to servos 1, 2, and 3
=head1 OPTIONS
=over
=item B<-t>
end a test UDP (currently not working maybe)
=back
=head1 README
Needs Win32::API and Win32::SerialPort installed
Assumes COM5 for the servo controller
=head1 PREREQUISITES
This script requires C<Win32::API 0.20>.
=pod OSNAMES
MSWin32
=pod SCRIPT CATEGORIES
Win32
=head1 AUTHOR
Written by Chris Drake.
=head1 COPYRIGHT
Copyright © 2011 Chris Drake.
This is Free Software; this software is licensed under the GPL version 2, as published by the Free Software Foundation.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
=cut
######################################################################
use strict;
use bytes;
use Socket;
use Win32::API;
use Win32::SerialPort;
my $port=5000; my $ip='0.0.0.0'; # 0.0.0.0 to listen on all interfaces/IPs
my($vec,$recording,@cmds,%state)=('',0);
exit &UDPTest('test' . $ARGV[1]) if($ARGV[0] eq '-t'); # See "TESTING" above
# Set up the servo controller
my $sport = Win32::SerialPort->new("COM5") || die $!;
$sport->baudrate(9600);
$sport->parity("none");
$sport->handshake("none");
$sport->databits(8);
$sport->stopbits(1);
$sport->read_char_time(0);
$sport->read_const_time(1);
# Open up a socket to listen for UDP requests on (able to send replies too if rqd)
my $iaddr = gethostbyname($ip); # Use 0.0.0.0 to listen on all interfaces/IPs
my $proto = getprotobyname('udp');
my $paddr = sockaddr_in($port, $iaddr); # We're going to listen on arbitray port
socket(SOCKET, PF_INET, SOCK_DGRAM, $proto) or die "socket: $!";
bind(SOCKET, $paddr) or die "bind: $!";
vec($vec, fileno(SOCKET), 1) = 1;
my($from, $request);
print "Listening on $ip:$port\n";
# Monitor the UDP socket requests indefinitely
while(1) {
my($r,$e);
select($r=$vec,undef,$e=$vec,999); # Wait for some data
if(vec($r,fileno(SOCKET),1)) { # A UDP packet has arrived
if(!($from = recv(SOCKET, $request, 8192, 0))) {
warn "recv() failed: $!";
} else {
my($udid,$timecode,@data)=split(/,/,$request);
my($xxaf,$xxport,$xxinetaddr) = unpack('S n a4 x8',$from);
# warn "got '$request'"; # Expects an IP.PORT to come in here
print "$xxaf " . join('.',unpack('C4',$xxinetaddr)) . ":$xxport=" . $request;
my $reply=($udid eq 'test') ? "Thanks for: $request" : '';
&Servo($data[0],$data[1],$data[2]);
# Send a reply
if(($reply ne '')&&(!(defined(send(SOCKET, $reply , 0, $from))))) { # Just send it - dunno if we need to wait on UDP sockets to see if we're allowed to send?
warn "Send failed: $!";
}
} # recv
} # if UDP
} # while
exit(0);
sub Servo {
my(@posy)=@_;
for(my $i=0; $i<=$#posy; $i++) {
if($state{$i} ne $posy[$i]) { # Phone has moved
my $pos=int(90+$posy[$i]/180*256); $pos=254 if($pos>254); $pos=0 if($pos<0);
my $pack = pack "CCC", 255,$i, $pos;
my ($user,$system,$cuser,$csystem) = times;
print "($user,$system,$cuser,$csystem) Sending:" . unpack("H*", $pack) . "\n";
$sport->write($pack);
$state{$i} = $posy[$i];
if($recording) {
push @cmds,[$user,\@posy];
}
} # change
} # $i
} # Joy
#######################################################################
=head2 UDPTest
Does not work - too lazy to figure out why not.
See if the server-side version of this code's UDP handling stuff is working OK.
=cut
#######################################################################
sub UDPTest {
my($request)=@_;
# Open up a socket to send UDPs out through (and receive replies from)
my $iaddr = gethostbyname('127.0.0.1'); # Use 0.0.0.0 to listen on all interfaces/IPs
my $proto = getprotobyname('udp');
my $paddr = sockaddr_in(0, $iaddr); # 0 means let kernel pick any port to listen on for replies
socket(SOCKET, PF_INET, SOCK_DGRAM, $proto) or die "socket: $!";
bind(SOCKET, $paddr) or die "bind: $!";
my $passivesvr=sockaddr_in($port,inet_aton('127.0.0.1')); # Where are we going to send our UDP to?
# Send a request
if(!(defined(send(SOCKET, $request , 0, $passivesvr)))) { die "Send failed: $!"; }
# Wait for a reply
my($rin,$rout,$reply,$svr)=('');
vec($rin, fileno(SOCKET), 1) = 1;
if (select($rout = $rin, undef, undef, 10.0)) { # times-out after 10.0 seconds
if(!($svr = recv(SOCKET, $reply, 8192, 0))) {
warn "recv() failed: $!";
} else {
warn "Server replies '$reply'";
}
} else {
warn "Oops - got no reply";
}
warn "Exiting";
exit(0);
} # UDPTest
#######################################################################
# The end
Enjoy!