Sample Windows perl code to wiggle servos using your iPhone

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!

Thanks for sharing that with us! That sounds like a pretty cool way to control servos. I did not know about the iSensor app.

–David