RobotControl GUI Servo Driver in Perl/TK
(By Patrick M. Rael, pmrael@aol.com)






The application above is called RobotControl.  This version is written in Perl/Tk.  Note that the RobotControl referenced in the HowTo... is written in Java.  I decided to write this one in Perl/Tk to see what the complexity issues were.  I'm using Perl/Tk on Redhat Linux 6, which is Linux 2.2.   This RobotControl Perl/Tk application can be pulled from this RobotControl.tar tar file.  I run it like this:
% RobotControl > /dev/ttyS0
As root I had to establish permission for non-root users to write to the port:
# chmod go+rw /dev/ttyS0
Also, I set the port settings to 9600, 8,N,1:
% stty 9600 cs8 -parenb -cstopb < /dev/ttyS0
If you run RobotControl and don't redirect output elsewhere, you're terminal driver may appear garbled, so type the following to restore it (and then next time redirect or pipe output elsewhere  :-)  ):
% ^Jreset^J              (Control-J, r, e, s, e, t, Control-J; 7 chars)


#!/usr/bin/perl -w

# RobotControl is a program for controlling Robot Maxamilian's servos.
# Copyright (C) 1999  Patrick M. Rael
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

#
# Use the Tk package
#
use Tk;


#
# Create the Main window, with a Menu of a few basic options, and a frame
#
my $mw = new MainWindow(-width  => '400',
                        -height => '400');
my $f = $mw->Frame(-relief      => 'raised',
                   -background  => 'tan3',
                   -borderwidth => 2);
$f->pack(-side   => 'top',
         -anchor => 'n',
         -expand => 1,
         -fill   => 'x');
my $fileMenu = $f->Menubutton(-text       => "File",
                              -tearoff    => 0,
                              -background => 'tan3',
                              -menuitems  => [
                                      ['command' => "Quit",
                                       -command  => sub { exit } ]
                                   ])->pack( -side => 'left');

#
# Load several pictures of RMax
#
my $canvas = $mw->Canvas(-height     => 100,
                         -width      => 410,
                         -background => 'firebrick4');
place_image($canvas, "Mini-SSC-II.gif",                45,50);
place_image($canvas, "InsideRobotHead.gif",           130,50);
place_image($canvas, "RMax2.gif",                     210,50);
place_image($canvas, "Schematic.gif",                 300,50);
place_image($canvas, "ChromeLook1-Thumbnail.gif",     375,50);
$canvas->pack();

my $f2 = $mw->Frame(-relief      => 'raised',
                    -borderwidth => 1)->pack();


#
# Create the Scale bars
#
$rightEye    = createScalebar($f2, "Right Eye",      0,  0,254,  0,0);
$leftEye     = createScalebar($f2, "Left Eye",       1,  0,254,  0,1);
$upDown      = createScalebar($f2, "Eyes Up/Dn",     2,  0,254,  1,0);
$spinHead    = createScalebar($f2, "Spin Head",      3,  0,254,  1,1);
$rightEyeLid = createScalebar($f2, "Right Eye-Lid",  4,  254,0,  2,0);
$leftEyeLid  = createScalebar($f2, "Left Eye-Lid",   5,  0,254,  2,1);

$bothEyesLR  = createScalebar($f2, "Both Eyes L/R", -1,  0,254,  3,0);
$bothEyeLids = createScalebar($f2, "Both Eye-Lids", -1,  0,254,  3,1);

$bothEyesLR->configure(-command =>  [\&vscale_cb, $rightEye, $leftEye]); 
$bothEyeLids->configure(-command => [\&vscale_cb,$rightEyeLid,$leftEyeLid]); 



#
# Enter the main graphics event loop
#
MainLoop;
###########################################################################

#
# Subroutine scale_cb() - Callback for a Scale bar change.
#
#     $sid [ServoID] is an integer I define from 0-7+ which is actually
#           a port number of the Mini-SSC-II.
#     $value is the value 0-254 of the Scale bar.  It seems to be passed in
#           Magically by Perl/Tk because I don't specify it.  What luck!
#
sub scale_cb {
    my ($sid, $value) = @_;

    #
    # Create a Packet of bytes: #255, Servo, Position
    #
    my $ch_sop = chr(255);     # char, start-of-packet, sop
    my $ch_sid = chr($sid);    # char, Servo-ID, sid
    my $ch_val = chr($value);  # char, Servo Position 0-254, val
    my $packet = "$ch_sop$ch_sid$ch_val";
    print "$packet";
}


#
# Subroutine vscale_cb() - Callback for driving two other servos.
#
sub vscale_cb {
    my ($slave1,$slave2,$value) = @_;

    $slave1->set($value);
    $slave2->set($value);
}


#
# Subroutine createScalebar() - Creates a Scale bar.
#
sub createScalebar {
    my ($container, $label,$servoID,$from,$to,$row,$col) = @_;

    my $sb = $container->Scale(-from         => $from,
                               -to           => $to,
                               -label        => "$label",
                               -length       => '200',
                               -showvalue    => '1',
                               -tickinterval => '50',
                               -orient       => 'horizontal',
                               -background   => 'tan1',
                               -trough       => 'tan4',
                               -command => [ \&scale_cb, $servoID] );
    $sb->grid(-row    => "$row",
              -column => "$col");

    return $sb;

}


#
# Subroutine place_image() - Loads "Photo's"
#
sub place_image {
    my ($container,$file,$x,$y) = @_;

    my $photo = $container->Photo(-file => $file);
    my $image = $container->createImage($x,$y, -image => $photo);
}