2013/09/25 ■ 秋葉原ラジオストアーが11月末で閉館!?と聞き、勝手ストリートビューを作ってみた Xでつぶやくこのエントリーをブックマークに追加このエントリーを含むはてなブックマーク

※RICOH THETA関連のHACKが増えてきたので、まとめた別ページを作りました

秋葉原の“昔ながらの”部品屋さんが集まる「秋葉原ラジオストアー」が64年の歴史に幕を閉じ、2013年11月30日で閉館すると発表されました。「秋葉原ラジオストアー」は、その名前までは認識していなくとも「JR秋葉原駅から中央通りに出ようとすると見かける、ガード下のごちゃっとした素人お断り風の路地」といえばわかりますでしょうか。あの一角はいくつかの建物?の集合体なのですが、そのうちのひとつが「秋葉原ラジオストアー」です。秋葉原はラジオ(電子部品)の街→電気製品の街→PCの街→萌えの街、というような変遷を経ていますが、この「電子部品の街」の頃から全くその景色が変わっていない、ザ・秋葉原という雰囲気を残す一角といえるでしょう。
その「秋葉原ラジオストアー」が閉館する!?と聞き、昔からの秋葉原ユーザとしてはいてもたってもいられずRICOH THETAを持って、あの雰囲気を記録するために「勝手ストリートビュー」を撮影してまいりました。衝動的に、勝手に撮ってしまいましたごめんなさい!

上記地図の青丸が撮影地点です。順に地図右側から、画像をクリックするとパノラマに飛びます
地図上のお店が赤く示されているところが「秋葉原ラジオストアー」です。通路をはさんで反対側は「ラジオセンター」という別の建物で、こちらは今回閉館のアナウンスはありません。このあたり、ラジオストアーが閉館したらどういう景色になるんでしょうか…。







今回の撮影はRICOH THETAを頭上にかかげ、自作スクリプトで5秒に一回リモートシャッターで自動的にシャッターを切り続けるようにセットしそのまま通路を歩いて撮影しました。通路の端から端まで1分くらいでしょうか。THETAの機動力の高さが活かせたかなと思います。

参考までに、THETAでリモートシャッターを切るスクリプト(Perl)を以下に示します。AndroidではSL4A+Perl for Androidの組み合わせで端末上で実行可能です。本スクリプトはシャッターを1回切るだけですが、PTP_OC_InitiateCaptureの部分を繰り返すことで複数回シャッターを繰り返させることが可能です。
THETAはWiFi経由ではPTP-IPで通信しているようで、制御はこちらのドキュメントなどを参考にしました。

※このスクリプトはその後バージョンアップしています。詳細はこちらのページをごらんください
#!/usr/bin/perl
# -------------------------------------------------------
#   RICOH THETA Remote shutter
# -------------------------------------------------------
use IO::Socket;
#use Encode;

# ----- TARGET THETA
my $Addr = "192.168.1.1";
my $Port = 15740;

# ----- My profile
my $Name = "THETA_Shutter";
my $GUID = "8a7ab04f-ebda-4f33-8649-8bf8c1cdc838";


my ($command_sock, $event_sock, $result, $session_id, $transaction_id);

# Init_Command
$command_sock = &PTPIP_Open_Connection;
&PTPIP_Init_Command_Request($command_sock);
($result, $session_id) = &PTPIP_Wait_Init_Command_Ack($command_sock);
if ($result == 0) { die "No Init_Command_Ack"; }

# Init_Event
$event_sock = &PTPIP_Open_Connection;
&PTPIP_Init_Event_Request($event_sock,$session_id);
($result) = &PTPIP_Wait_Event_Request_Ack($event_sock);
if ($result == 0) { die "No Init_Event_Ack"; }
$transaction_id = 0;

# PTP_OC_OpenSession
&PTPIP_Cmd_Request($command_sock, $transaction_id++, 0x1002, $session_id );
($result) = &PTPIP_Wait_Cmd_Response($command_sock);
if ($result == 0) { die "No Cmd_Response"; }

# PTP_OC_InitiateCapture
&PTPIP_Cmd_Request($command_sock, $transaction_id++, 0x100E, 0, 0 );
($result) = &PTPIP_Wait_Cmd_Response($command_sock);
if ($result == 0) { die "No Cmd_Response"; }


&PTPIP_Close_Connection($event_sock);
&PTPIP_Close_Connection($command_sock);
exit;





# -------------------------------------------------------
#   Init_Command
# -------------------------------------------------------

sub PTPIP_Init_Command_Request {
 my $sock = shift;

 my $payload = "";
 $payload .= pack("H8H4H4H4H12",split('-',$GUID));  # GUID
 $payload .= Encode_UTF16LE($Name."\x00");
 $payload .= pack("V",1);

 print $sock &PTPIP_pack_command( 1, $payload);
}

sub PTPIP_Wait_Init_Command_Ack {
 my $sock = shift;
 my ($result,$session_id,$target_guid,$target_name,$unknown1);
 my @error_response = (0,0);

 my ($cmd,$payload) = &PTPIP_Recv_Response($sock);
 if ($cmd != 2) { @error_response; exit; }

 $session_id  = unpack("V",$payload);
 $payload     = substr($payload,4);
 my (@guid)   = unpack("H8H4H4H4H12",$payload);
 $target_guid = join('-',@guid);
 $payload     = substr($payload,16);
 $target_name = Decode_UTF16LE(substr($payload,0,-4));
 $payload     = substr($payload,-4);
 $unknown1    = unpack("V",$payload);

 print "Target GUID :".$target_guid."\n";
 print "Target Name :".$target_name."\n";

 (1, $session_id);
}

# -------------------------------------------------------
#   Init_Event
# -------------------------------------------------------

sub PTPIP_Init_Event_Request {
 my $sock = shift;
 my $session_id = shift;

 my $payload = "";
 $payload .= pack("V",$session_id);

 print $sock &PTPIP_pack_command( 3, $payload);
}

sub PTPIP_Wait_Event_Request_Ack {
 my $sock = shift;
 my @error_response = (0);

 my ($cmd,$payload) = &PTPIP_Recv_Response($sock);
 if ($cmd != 4) { @error_response; exit; }

 1;
}

# -------------------------------------------------------
#   Cmd_Request
# -------------------------------------------------------

sub PTPIP_Cmd_Request {
 my $sock = shift;
 my $transaction_id = shift;
 my $cmd  = shift;
 my @args = @_;

 my $payload = "";
 $payload .= pack("V",1);
 $payload .= pack("v",$cmd);
 $payload .= pack("V",$transaction_id);
 $payload .= pack("V*",@args);

 print $sock &PTPIP_pack_command( 6, $payload);
}

sub PTPIP_Wait_Cmd_Response {
 my $sock = shift;
 my @error_response = (0);

 my ($cmd,$payload) = &PTPIP_Recv_Response($sock);
# if ($cmd != 4) { @error_response; exit; }

 1;
}

# -------------------------------------------------------
#   PTPIP utils
# -------------------------------------------------------

sub PTPIP_Open_Connection {
 my $sock = new IO::Socket::INET(PeerAddr=>$Addr,PeerPort=>$Port,Proto=>'tcp',TimeOut=>2);
 die "IO::Socket : $!" unless $sock;

 $sock;
}

sub PTPIP_Close_Connection {
 my $sock = shift;
 close($sock);
}

sub PTPIP_pack_command {
 my $cmd = shift;
 my $payload = shift;

 pack("VV",(length($payload)+8),$cmd).$payload;
}

sub PTPIP_Recv_Response {
 my $sock = shift;
 my ($buf,$len,$command_type,$packet_len);
 my @error_response = (0,'');

 # packet length
 $len = read($sock,$buf,4);
 if ($len != 4) { @error_response; exit; }
 $packet_len = unpack("V",$buf);
 if ($packet_len > 1024) { @error_response; exit; }
 if ($packet_len < 8   ) { @error_response; exit; }

 # command
 $len = read($sock,$buf,4);
 if ($len != 4) { @error_response; exit; }
 $command_type = unpack("V",$buf);

 # payload
 $len = read($sock,$buf,$packet_len-8);
 if ($len != ($packet_len-8)) { @error_response; exit; }

 ($command_type,$buf);
}

sub Encode_UTF16LE {
 my $str = shift;
# encode('UTF16LE', $str);
 pack("v*",unpack("c*",$str));
}

sub Decode_UTF16LE {
 my $str = shift;
# decode('UTF16LE', $str)
 pack("c*",unpack("v*",$str));
}
当初の目的だった「リモートシャッター」が動いたからもういいやー、とコマンドのレスポンスパース部を途中でほったらかしてありますがw、PTPIP_Wait_Cmd_Response の部分をもうちょっとちゃんと作って長いペイロードも受け取れるようになるといろいろとできる制御が広がるはず。そのあたりはまた後日、ということで。 この「勝手ストリートビュー」を作れる360度パノラマカメラ、RICOH THETAについては に詳しくレビューしてありますので、よろしければこちらもどうぞ。