Instructions;
Plug in your XBox360 wireless remote controller (or some other joystick)
Connect your Mini Maestro to COM5 (or adjust COM5 in the code below)
Wiggling the joysticks will control servos 1, 2, and 3.
Press “Y” to start recording your wiggles.
Press “B” to stop recording
Press “A” to play it back
Press “X” to exit.
If anyone knows how to talk to the Maestro using DLLs (eg: USB instead of serial commands), PLEASE let me know!!!
#!/usr/bin/perl
use strict;
use Win32::API;
use Win32::SerialPort;
# use Time::HiRes; # Do not use this - it crashes the serialport code
my $VERSION = 0.1;
=head1 NAME
XBox_Pololu.pl - demo controlling servos via joystick
=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\Win3
=head1 SYNOPSIS
XBox_Pololu.pl [joynumber]
=head1 DESCRIPTION
This B<XBox_Pololu.pl> demo wiggles pololu servos
=head1 OPTIONS
=over
=item B<none>
this demo has no options
=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 The Chris Drake Team.
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
# Set up the servo controller
my $port = Win32::SerialPort->new("COM5") || die $!;
$port->baudrate(9600);
$port->parity("none");
$port->handshake("none");
$port->databits(8);
$port->stopbits(1);
$port->read_char_time(0);
$port->read_const_time(1);
# Define the structure we need to get all this info (might already be defined in Win32::API - I didn't look)
typedef Win32::API::Struct JOYINFOEX => (
'LONG', 'dwSize', # size of structure
'LONG', 'dwFlags', # flags to indicate what to return
'LONG', 'dwXpos', # x position
'LONG', 'dwYpos', # y position
'LONG', 'dwZpos', # z position
'LONG', 'dwRpos', # rudder/4th axis position
'LONG', 'dwUpos', # 5th axis position
'LONG', 'dwVpos', # 6th axis position
'LONG', 'dwButtons', # button states
'LONG', 'dwButtonNumber', # current button number pressed
'LONG', 'dwPOV', # point of view state
'LONG', 'dwReserved1', # reserved for communication between winmm driver
'LONG', 'dwReserved2', # reserved for future expansion
);
my $joyinfoex=Win32::API::Struct->new( 'JOYINFOEX' ); # Register the structure
# Windows wants us to fill in some parts of the structure before we use it:
$joyinfoex->{dwSize}=Win32::API::Struct::sizeof($joyinfoex);
$joyinfoex->{dwFlags}= 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80; # JOY_RETURNX JOY_RETURNY JOY_RETURNZ JOY_RETURNR JOY_RETURNU JOY_RETURNV JOY_RETURNPOV JOY_RETURNBUTTONS
# "import" the call we need to get the joystick data.
my $joyGetPosEx=Win32::API->new('WinMM', 'int joyGetPosEx(int a, JOYINFOEX *p)');
my $endloop=0;
my $recording;
my @cmds;
my @inputs=qw(dwXpos dwYpos dwRpos); my %state;
print "Use sticks to control servos\n";
print "Y = start recording\n";
print "B = stop recording\n";
print "A = Playback\n";
print "X = Exit\n\n";
while(!$endloop) {
my $ret=$joyGetPosEx->Call($ARGV[0] || 0,$joyinfoex);
die "Joystick problem - rc=$ret" if($ret);
&Joy($joyinfoex);
$endloop=($joyinfoex->{'dwButtons'}&4); # + $joyinfoex->{'dwButtonNumber'};
if($joyinfoex->{'dwButtons'}&8) { # Y button
print "Recording begun\n" unless($recording);
$recording=1;
@cmds=(); # Clear old one
}
if($joyinfoex->{'dwButtons'}&2) { # B button
print "Recording ended. Got " . $#cmds . " commands \n" if($recording);
$recording=0;
}
if($joyinfoex->{'dwButtons'}&1) { # A button
$recording=0;
print "Playing back recording...\n";
my $t=$cmds[0]; $t=$$t[0]; # Start moment.
foreach my $step (@cmds) {
my $delay=($$step[0]-$t);
print "D:$delay\t";
if($delay>0) { select(undef, undef, undef, $delay); }
&Joy($$step[1]);
$t=$$step[0];
}
}
} # loop;
$port->close;
print "Ending on button-press\n";
exit(0);
sub Joy {
my($joyinfoex)=@_;
for(my $i=0; $i<=$#inputs; $i++) {
if($state{$inputs[$i]} ne $joyinfoex->{$inputs[$i]}) { # joystick pos is changed
my $pos=int($joyinfoex->{$inputs[$i]} / 256); $pos=254 if($pos>254);
my $pack = pack "CCC", 255,$i, $pos;
my ($user,$system,$cuser,$csystem) = times;
print "($user,$system,$cuser,$csystem) Sending:" . unpack("H*", $pack) . "\n";
$port->write($pack);
$state{$inputs[$i]} = $joyinfoex->{$inputs[$i]};
if($recording) {
push @cmds,[$user,&ObjtoH($joyinfoex)];
}
} # change
} # $i
} # Joy
sub ObjtoH {
my($joyinfoex)=@_;
my %h;
foreach my $i (@inputs) {$h{$i}=$joyinfoex->{$i}}
return \%h;
}
# The end.
Have Fun!!!