ソフトウェア」カテゴリーアーカイブ

ジャイロセンサーの測定プロセスを優先する

ジャイロセンサーを使った旋回制御動作の際、指定した回転角より多く回転する動きを見せることがあります。 ドリフトや振動などの影響もありますが、他のプロセスと協調動作を行う関係上、ある程度はしかたがないことと考えていました。 そんな折、このような情報(?)を目にしました。

Linux リアルタイムカーネルを使いたかった – TK’s HP

桜とハウスローバー

桜とハウスローバー

リアルタイム性は、ハードウェアにより近いシステム、例えばarduinoのようなものでなければ難しいと思っていましたが、リアルタイムカーネルで実現可能なことを知ったのです。

さらに調べていくと、下記サイトに重要な事が…

プログラムを実行する優先度を変更 – Linuxコマンド

プログラムを実行する時に優先度を指示できるコマンドがあったのです。 それはnice(!)

ジャイロセンサーを使う」の旋回用プログラムをniceコマンドで実行してみます。 nice値は最優先の-20です。

nice -n -20 sudo ./gyro_turn11 r 90

すごい!素晴らしい! 全くと言えるほどズレがなく、何度実行しても再現性抜群です。

今後の開発にも非常に有効な情報であったと思うと同時に、知らなかったことの怖さも実感したのでした。

 

Raspberry Piの初期設定 – Raspbian

Arch Linuxで開発を進めてきたハウスローバーですが、先日、いつもの様にシステムのアップデートを実施したところ、 パッケージマネージャのデータベースが破損したとのメッセージを出力し、pacmanが使用できなくなってしまいました。

修復を試みましたが、上手く行かず、再セットアップした方が早そうです。 それならと、最新のRaspbianに切り替えることにしました。

重い印象だったRaspbianですが、CUIではArch Linuxと大差なさそう。 それとも改善しているのでしょうか。

raspbian_img

Raspbianの初期設定

・パッケージ更新
sudo apt-get update
sudo apt-get upgrade

・ネットワーク設定
sudo nano /etc/network/interfaces
/etc/network/interfacesの内容
—————————————-
auto lo wlan0 eth0

iface lo inet loopback
address 127.0.0.1
netmask 255.0.0.0

iface eth0 inet static
address 192.168.0.XX
netmask 255.255.255.0
network 192.168.0.0

iface wlan0 inet static
address 192.168.0.XX
netmask 255.255.255.0
network 192.168.0.0
gateway 192.168.0.XX
wireless-essid XXXXX
wireless-key XXXXXXXXXX
#wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
—————————————-
(セキュリティ設定がWEPの場合、上記設定のみで繋がりますが下記ネットワークマネージャーで設定した方が安定しました)

・ワイヤレス用ネットワークマネージャー
sudo apt-get install wicd-curses
インストール後、wicd-cursesで設定画面へ

・DNS設定
sudo nano /etc/resolv.conf
nameserver 192.168.0.XX

・ネットワーク設定の適用
sudo /etc/init.d/networking reload

・Apacheインストール
sudo apt-get install apache2

・PHP5インストール
sudo apt-get install php5

・PHPキャッシュモジュールAPCインストール
sudo apt-get install php-apc

・mjpg_streamerのインストール
sudo apt-get install subversion
sudo apt-get install libjpeg-dev imagemagick
svn co https://svn.code.sf.net/p/mjpg-streamer/code/mjpg-streamer mjpg-streamer
cd mjpg-streamer
make
mjpg_streamerをバックグランドで起動
(インストールディレクトリで実行)
sudo ./mjpg_streamer -b -i “./input_uvc.so -f 20 -r 320×240 -d /dev/video0 -y” -o “./output_http.so -w ./www -p 8080”

・ServoBlaster
git clone git://github.com/richardghirst/PiBits.git
cd PiBits/ServoBlaster/user
make servod
sudo make install
起動オプション
–idle-timeout=2000 –p1pins=7,11

・WebIOPiのインストール
wget http://webiopi.googlecode.com/files/WebIOPi-0.6.0.tar.gz
tar xvzf WebIOPi-0.6.0.tar.gz
cd WebIOPi-0.6.0
sudo ./setup.sh
サービス起動 sudo /etc/init.d/webiopi start
サービス停止 sudo /etc/init.d/webiopi stop

・Wiring Piのインストール
git clone git://git.drogon.net/wiringPi
cd wiringPi
./build

・I2Cの使用
i2c-devのロード
sudo modprobe i2c-dev
自動起動の為/etc/modulesにi2c-devを追加
nano /etc/modules
i2c-toolsのインストール
sudo apt-get install i2c-tools
状態表示
i2cdetect 1

・CGIをroot権限で実行する為の設定
sudo の設定ファイル (/etc/sudoers) を編集する
www-data ALL=(root) NOPASSWD:ALL を追加

追加項目

・webminインストール
sudo apt-get install perl libnet-ssleay-perl openssl libauthen-pam-perl libpam-runtime libio-pty-perl apt-show-versions
wget http://prdownloads.sourceforge.net/webadmin/webmin_1.660_all.deb
sudo dpkg –install webmin_1.660_all.deb
sudo /usr/share/webmin/changepass.pl /etc/webmin root <rootのパスワード>
https://<raspberrypiのIPアドレス>:10000/

・sambaをインストール
sudo apt-get install samba samba-common-bin
sambaの設定
sudo nano /etc/samba/smb.conf
以下を追加
—————————————-
[share]
comment = share drive
read only = no
locking = no
path = /var/www
guest ok = yes
force user = <sambaユーザー名>
—————————————-
パスワードを設定
sudo smbpasswd -a <sambaユーザー名>
New SMB password:<sambaユーザーパスワード>
Retype new SMB password:<sambaユーザーパスワード>
smanbaを再起動
sudo service samba restart

コマンド等

・デバイス表示(主にUSBデバイスの確認)
lsusb

・GPIOの状態表示
gpio readall

・wiringPiのライブラリを指定してコンパイル
gcc xxxxxx.c -o xxxxxx -I/usr/local/include -L/usr/local/lib -lwiringPi

 

 参考にさせていただいたサイト

人と技術のマッシュアップ – Raspberry PiでGPIO制御

sstea備忘録 – Raspberry Pi の最適化を試みる

ものづくりエクスペリメント – メモリーを節約する

 

リアルタイムクロック RTC-8564NB で起動する

ESAの彗星探査機「フィラエ」が電力喪失、スリープモードに移行

探査機にとって電力は命です。 フィラエは太陽光パネルに光が当たれば、復活の可能性がありますが、電力源としてバッテリーしか持たないハウスローバーは、それを消費してしまえば、活動できなくなります。 少しでも長くバッテリーを持続させるための制御に利用する計画で、RTCを搭載しました。

RTC-8564NB

RTC-8564NBは、分、時、日、曜日を指定できるアラームと0~255秒(または分)を設定できるタイマーを内蔵しています。 その出力としてINT端子がLowレベルとなるため、Raspberry Piのリセット端子と接続することで、シャットダウン状態のシステムを起動することができます。

RTC_INT配線

RTCのINT端子部分の配線

 

P6の1番ピンへ接続

P6の1番ピンへ接続

I2C接続後、ハードウェアクロックデバイスとして登録します。

/etc/modules-load.d/rasberrypi.conf へ
rtc-pcf8563 を、追加
echo pcf8563 0x51 > /sys/class/i2c-adapter/i2c-1/new_device を、実行する。

これで、hwclockコマンドが使用できるようになります。

ところが、システムモジュールとして登録すると、I2Cコマンドで直接操作ができなくなります。 (pythonでは可能なようですが…)

今回は、アラーム設定を直接操作したいので、システムモジュールには登録しません。 (システムモジュールとして登録されていて、一時的に外す場合は modprobe -r rtc-pcf8563 を実行)

PHPで、RTCを設定するスクリプトを作成しました。

<?php
//RTC SET v1.1 2015.1.11 spacelab
//ハードウェアクロックとして設定されている場合は
//タイムゾーンはUTCが使用されています。
//本スクリプトはJSTとして動作しますので、事前に
//時刻設定を行って下さい。

date_default_timezone_set('Asia/Tokyo');
setlocale(LC_ALL,"ja_JP.UTF-8");

$i2cadd = 0x51; //デバイススレーブアドレス

$msk3 = 0x07;
$msk5 = 0x1f;
$msk7 = 0x3f;
$msk8 = 0x7f;
$bit2 = 0x02;

if($argv[1]){ //パラメータチェック
 $sw = $argv[1];
}else{
 $sw = "-d";
}

switch ($sw){
 case "-d":
 //RTC時刻の取得
 //レジスタの読み込み
 $r_sec = hexdec(exec("i2cget -y 1 $i2cadd 0x02"));
 $r_min = hexdec(exec("i2cget -y 1 $i2cadd 0x03"));
 $r_hou = hexdec(exec("i2cget -y 1 $i2cadd 0x04"));
 $r_day = hexdec(exec("i2cget -y 1 $i2cadd 0x05"));
 //$r_wek = exec("i2cget -y 1 0x51 0x06");
 $r_mon = hexdec(exec("i2cget -y 1 $i2cadd 0x07"));
 $r_yea = substr(exec("i2cget -y 1 $i2cadd 0x08"),2) + 2000;

 //不要ビットをマスク
 $r_sec = dechex($r_sec & $msk8);
 $r_min = dechex($r_min & $msk8);
 $r_hou = dechex($r_hou & $msk7);
 $r_day = dechex($r_day & $msk7);
 $r_mon = dechex($r_mon & $msk5);

 $timestamp = mktime($r_hou,$r_min,$r_sec,$r_mon,$r_day,$r_yea,0);
 echo strftime("%c\n",$timestamp);
 break;

 case "-s":
 //RTC時刻をシステムタイマーと同期
 $r_yea = date('y');
 $r_mon = date('m');
 $r_day = date('d');
 $r_wek = date('w');
 $r_hou = date('H');
 $r_min = date('i');
 $r_sec = date('s');

 exec("i2cset -y 1 $i2cadd 0x08 0x".$r_yea);
 exec("i2cset -y 1 $i2cadd 0x07 0x".$r_mon);
 exec("i2cset -y 1 $i2cadd 0x06 0x".$r_wek);
 exec("i2cset -y 1 $i2cadd 0x05 0x".$r_day);
 exec("i2cset -y 1 $i2cadd 0x04 0x".$r_hou);
 exec("i2cset -y 1 $i2cadd 0x03 0x".$r_min);
 exec("i2cset -y 1 $i2cadd 0x02 0x".$r_sec);

 $timestamp = mktime($r_hou,$r_min,$r_sec,$r_mon,$r_day,$r_yea,0);
 echo strftime("%c\n",$timestamp);
 break;

 case "-w":
 //RTCをシステム時刻に設定
 //レジスタの読み込み
 $r_sec = hexdec(exec("i2cget -y 1 $i2cadd 0x02"));
 $r_min = hexdec(exec("i2cget -y 1 $i2cadd 0x03"));
 $r_hou = hexdec(exec("i2cget -y 1 $i2cadd 0x04"));
 $r_day = hexdec(exec("i2cget -y 1 $i2cadd 0x05"));
 //$r_wek = exec("i2cget -y 1 0x51 0x06");
 $r_mon = hexdec(exec("i2cget -y 1 $i2cadd 0x07"));
 $r_yea = substr(exec("i2cget -y 1 $i2cadd 0x08"),2) + 2000;

 //不要ビットをマスク
 $r_sec = dechex($r_sec & $msk8);
 $r_min = dechex($r_min & $msk8);
 $r_hou = dechex($r_hou & $msk7);
 $r_day = dechex($r_day & $msk7);
 $r_mon = dechex($r_mon & $msk5);

 $timestr = "$r_yea/$r_mon/$r_day $r_hou:$r_min:$r_sec";
 exec("date --set='".$timestr."'");
 echo exec("date")."\n";
 break;

 case "-as":
 //アラーム時刻の設定
 if($argv[2]){
 if($argv[2] =="m"){$a_cas = "0x09";}
 if($argv[2] =="h"){$a_cas = "0x0a";}
 if($argv[2] =="d"){$a_cas = "0x0b";}
 if($argv[2] =="w"){$a_cas = "0x0c";}
 if($argv[3]){
 $a_val = hexdec($argv[3]);
 }else{
 $a_val = 128;
 }
 exec("i2cset -y 1 $i2cadd $a_cas $a_val");
 exec("i2cset -y 1 $i2cadd 0x01 0x02");

 }else{
 //アラームセット
 exec("i2cset -y 1 $i2cadd 0x01 0x02");
 echo "アラームセットしました\n";
 }
 case "-a":
 //アラーム時刻の表示
 $a_set = hexdec(exec("i2cget -y 1 $i2cadd 0x01"));
 $a_min = hexdec(exec("i2cget -y 1 $i2cadd 0x09"));
 $a_hou = hexdec(exec("i2cget -y 1 $i2cadd 0x0a"));
 $a_day = hexdec(exec("i2cget -y 1 $i2cadd 0x0b"));
 $a_wek = hexdec(exec("i2cget -y 1 $i2cadd 0x0c"));

 if ($a_min >=128){$a_min_on = "無効 ";}else{$a_min_on = "有効 ";}
 if ($a_hou >=128){$a_hou_on = "無効 ";}else{$a_hou_on = "有効 ";}
 if ($a_day >=128){$a_day_on = "無効 ";}else{$a_day_on = "有効 ";}
 if ($a_wek >=128){$a_wek_on = "無効 ";}else{$a_wek_on = "有効 ";}

 $a_min = dechex($a_min & $msk8);
 $a_hou = dechex($a_hou & $msk7);
 $a_day = dechex($a_day & $msk7);
 $a_wek = dechex($a_wek & $msk3);

 echo "アラーム設定";
 if (dechex($a_set & $bit2) == 2){echo " 有効\n";}else{echo " 無効\n";}
 echo "Minuite: $a_min_on $a_min\n";
 echo "Hour : $a_hou_on $a_hou\n";
 echo "Day : $a_day_on $a_day\n";
 echo "Week : $a_wek_on $a_wek\n";
 break;

 case "-ar":
 //アラームリセット
 exec("i2cset -y 1 $i2cadd 0x01 0x00");
 echo "アラームリセットしました\n";
 break;

 case "-ts":
 //タイマーの設定
 if($argv[2]){
 exec("i2cset -y 1 $i2cadd 0x0f $argv[2]");
 if($argv[3]){
 exec("i2cset -y 1 $i2cadd 0x0e 0x83");
 }else{
 exec("i2cset -y 1 $i2cadd 0x0e 0x82");
 }
 exec("i2cset -y 1 $i2cadd 0x01 0x01");
 }else{
 echo "パラメータが足りません\n";
 }

 case "-t":
 //タイマー情報の表示
 $t_cnt = hexdec(exec("i2cget -y 1 $i2cadd 0x0e"));
 $t_dat = hexdec(exec("i2cget -y 1 $i2cadd 0x0f"));

 echo "タイマー設定";
 if ($t_cnt >=128){echo " 有効\n";}else{echo " 無効\n";}
 if ($t_cnt & 1){$clock = "分";}else{$clock = "秒";}
 echo "Timer: $t_dat $clock\n";
 break;

 case "-tr":
 //タイマーリセット
 exec("i2cset -y 1 $i2cadd 0x01 0x00");
 exec("i2cset -y 1 $i2cadd 0x0e 0x00");
 echo "タイマーリセットしました\n";
 break;

 case "-h":
 case "-?":
print <<< EOS
使用法: rtcset.php [機能] [設定値]...
機能:
 -d 現在時刻を表示する
 -s RTCをシステムクロックと同期する
 -w RTCの時刻をシステムクロックへ設定する
 -a アラームの設定状況を表示する
 -as [m,h,d,w] [値]
 アラームを有効に設定する
   [m,h,d,w] 分,時,日,曜日の項目を指定する
 [値] を省略すると該当項目を無効にする
 曜日の値:日=0 月=1 火=2 水=3 木=4 金=5 土=6
 例: 10時30分に設定
 -as h 10
 -as m 30
 -ar アラームをリセットし、無効に設定する
 -t タイマーの設定状況を表示する
 -ts [値] [秒,分]
 タイマーを有効に設定する
 [値] 0-255(秒) 単位: [初期値=秒,1=分]
 -tr タイマーをリセットし、無効に設定する
 -h,-? 使い方を表示
 -v バージョン情報を表示

EOS;
 break;

 case "-v":
 echo "rtcset.php version 1.1\nCopyright (C) 2015 space laboratory\n";
 break;

}
?>

php rtcset.php -h で、ヘルプが表示されます。 アラームやタイマーの設定をして、シャットダウンを実行することで、指定の時刻に起動させる事ができるようになりました。

アラーム出力はRaspberry Piにリセットをかけるものですので、メインのソフトウェアで定期的にタイマーを更新するような処理を行うことで、システム異常停止の際に復帰させる、ウォッチドッグタイマーの様な使い方もできると思います。