The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

#!/usr/bin/perl
use v5.14;
use Getopt::Long qw( :config no_ignore_case );
my $IP = '192.168.1.1';
my $PROMPT = 'uav> ';
my $MULTILINE_PROMPT = "\t";
my @LIB_PATHS = ();
my @LIBS = ();
my $IFACE = undef;
GetOptions(
'host=s' => \$IP,
'i|iface=s' => \$IFACE,
'l|load=s' => \@LIBS,
'L|library=s' => \@LIB_PATHS,
);
sub run_cmd
{
my ($cmd, $repl) = @_;
my $return = 1;
if( $cmd =~ /\A(?: exit | quit | q ) \s*;\s*\z/x ) {
$return = 0;
}
else {
eval {
$repl->run_cmd( $cmd );
};
warn $@ if $@;
}
return $return;
}
sub load_libraries
{
my ($repl, $lib_paths, $libs, $cv) = @_;
$repl->add_lib_dir( $_ ) for @$lib_paths;
$repl->add_lib_dir( UAV::Pilot->default_module_dir );
print "Library paths:\n" . join( "\n", map { "\t$_" } @{ $repl->lib_dirs } ) . "\n";
foreach my $lib (@$libs) {
print "Loading library '$lib' . . . ";
$repl->load_lib( $lib, {
condvar => $cv,
});
print "OK\n";
}
print "\n";
return 1;
}
{
my @cmd = ();
sub add_cmd
{
my ($cmd) = @_;
push @cmd => $cmd;
return 1;
}
sub full_cmd
{
my $cmd = join( ' ', @cmd );
@cmd = ();
return $cmd;
}
}
{
my $continue = 1;
my $driver_args = {
host => $IP,
};
$driver_args->{iface} = $IFACE if defined $IFACE;
my $ardrone = UAV::Pilot::ARDrone::Driver->new( $driver_args );
$ardrone->connect;
my $dev = UAV::Pilot::ARDrone::Control::Event->new({
driver => $ardrone,
});
my $cv = $dev->init_event_loop;
my $repl = UAV::Pilot::Commands->new({
device => $dev,
condvar => $cv,
});
load_libraries( $repl, \@LIB_PATHS, \@LIBS, $cv );
my $readline; $readline = AnyEvent::ReadLine::Gnu->new(
prompt => $PROMPT,
on_line => sub {
my ($line) = @_;
add_cmd( $line );
if( $line =~ /; \s* \z/x ) {
my $cmd = full_cmd;
$readline->hide;
my $do_continue = run_cmd( $cmd, $repl );
$readline->show;
$cv->send( $do_continue ) unless $do_continue;
}
},
);
$cv->recv;
}
__END__
=head1 SYNOPSIS
uav \
--host 192.168.1.1 \
-L /path/to/libraries
-l ARDrone
=head1 DESCRIPTION
Launches a shell for controlling a UAV. Perl statements may be typed at the prompt, ending
with a semi-colon. With the Parrot AR.Drone, try:
uav> takeoff;
uav> pitch -0.5;
uav> wave;
uav> land;
=head1 OPTIONS
=head2 --host
Host IP to connect to. Out of the box, the Parrot AR.Drone will be its own wireless
access point on IP 192.168.1.1 (which is the default here).
=head2 -L or --library
Path to library modules. May be specified multiple times. By default, this will be the
dist shared dir returned by L<File::ShareDir> for L<UAV::Pilot>.
=head2 -l or --load
Library to load. May be specified multiple times. It will need to be under one of the
directories specified by the C<--library> option (or the default library path).
=cut