RaspberryPi
IoT
led

汎用LED MATRIX DISPLAYを、ラズパイで使ってみる5

More than 1 year has passed since last update.

さて。
Raspberry Piに、登録していきましょうかね。

まず今回は、ファイル使うので。
SDカードへの負担を減らすため、RAMディスクを登録。

root@raspberrypi:/# mkdir /ramdisk
root@raspberrypi:/# chmod -R 777 /ramdisk
root@raspberrypi:/# cat /etc/fstab
proc            /proc           proc    defaults          0       0
PARTUUID=1bee5e28-01  /boot           vfat    defaults          0       2
PARTUUID=1bee5e28-02  /               ext4    defaults,noatime  0       1
# a swapfile is not a swap partition, no line here
#   use  dphys-swapfile swap[on|off]  for that
tmpfs           /ramdisk        tmpfs   defaults,size=16m 0 0

root@raspberrypi:/#

ま、マウント用ディレクトリ作って、fstabに登録、mount-aか再起動でRAMディスクが16MBできますよ、と。

で、出力はbmp、入力はppmなので、image-magickをセットアップ

root@raspberrypi:/# apt-get install imagemagick

LEDに表示する画像を作製するスクリプトと、LEDに画像を表示するスクリプトを、サービスとして作製。

root@raspberrypi:/# cd /etc/systemd/system
root@raspberrypi:/etc/systemd/system# cat makeledinfo.service
[Unit]
Description = makeledinfo

[Service]
ExecStart=/usr/bin/perl /data/ledinfo/makeledinfo.pl
Restart=always
Type=simple

[Install]
WantedBy=multi-user.target

root@raspberrypi:/etc/systemd/system# cat ledimageloader.service
[Unit]
Description = ledimageloader

[Service]
ExecStart=/usr/bin/python /data/ledinfo/ledimageloader.py -r 32 -c 2 -b 30 --led-slowdown-gpio 2 -p 5
Restart=always
Type=simple

[Install]
WantedBy=multi-user.target
root@raspberrypi:/etc/systemd/system#

systemctlで登録、と。
もう動かしてるので、ステータスで!。

root@raspberrypi:/etc/systemd/system# systemctl status makeledinfo.service
● makeledinfo.service - makeledinfo
   Loaded: loaded (/etc/systemd/system/makeledinfo.service; enabled; vendor preset: enabled)
   Active: active (running) since Sun 2017-11-26 19:57:04 JST; 1 weeks 5 days ago
 Main PID: 7990 (perl)
   CGroup: /system.slice/makeledinfo.service
           tq 7990 /usr/bin/perl /data/ledinfo/makeledinfo.pl
           mq30184 /usr/bin/python /data/ledinfo/hummeas.py

Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.
root@raspberrypi:/etc/systemd/system# systemctl status ledimageloader.service
● ledimageloader.service - ledimageloader
   Loaded: loaded (/etc/systemd/system/ledimageloader.service; enabled; vendor preset: enabled)
   Active: active (running) since Sat 2017-12-09 11:55:01 JST; 45min ago
 Main PID: 26104 (python)
   CGroup: /system.slice/ledimageloader.service
           mq26104 /usr/bin/python /data/ledinfo/ledimageloader.py -r 32 -c 2 -b 30 --led-slowdown-gpio 2 -p 5

12月 09 11:55:01 raspberrypi systemd[1]: Started ledimageloader.
root@raspberrypi:/etc/systemd/system#

数日動かしっぱなしにしてると、なんか盛大にハングしたので、たまにサービス再起動を仕込みました。

root@raspberrypi:/# cd /etc
root@raspberrypi:/etc# cat crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user  command
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#

55 * * * * root /usr/sbin/service ledimageloader restart
root@raspberrypi:/etc#

ま、これで、無事?動作。

動画だと、こんな感じです。
https://twitter.com/eucalydqx/status/934809174143221761

なかなか視認性も良く、取り扱いしやすいブツに仕上がり、まんぞくまんぞく。

最後に、実際に登録している、perlスクリプト、置いておきます。
/data/ledinfo とか、/ramdisk とかがキーワードかな。
あと、温度計計測用のスクリプトも、ここからキックしてますー。

makeledinfo.pl
$inputbitmapfontfilename = "/data/ledinfo/bfont.bmp";
$inputbitmapbackgroundfilename = "/data/ledinfo/back.bmp";
$humdatafilename2 = "/ramdisk/humoutput1.txt";
$humdatafilename1 = "/ramdisk/humoutput2.txt";
$outputfilename = "/ramdisk/ledoutput.bmp";

&inputbitmapfont;

while (){
 &meashum;
 &makeinfo;
 &imageconvert;
 sleep(2);
}
exit;

sub meashum {
 $systemcommand = "/usr/bin/python /data/ledinfo/hummeas.py";
 system ($systemcommand);
 $systemcommand = "/usr/bin/python /data/ledinfo/hummeas2.py";
 system ($systemcommand);
}

sub imageconvert {
 $systemcommand = "/usr/bin/convert /ramdisk/ledoutput.bmp /ramdisk/ledoutput.ppm";
 system ($systemcommand);
}

sub makeinfo{
 open (FILE,$humdatafilename1);
 (@humdataarray) = (<FILE>);
 close (FILE);

 chomp($humdataarray[0]);
 if ($humdataarray[0] < 0){
  $j = abs(int ($humdataarray[0]));
  $k = abs(int ($humdataarray[0] * 10));
  $k = $k - ($j * 10);
  $j = sprintf("%03d",$j);
  $k = sprintf("%01d",$k);
  $output_it = "-$j.$k";
 }
 else {
  $j = abs(int ($humdataarray[0]));
  $k = abs(int ($humdataarray[0] * 100));
  $k = $k - ($j * 100);
  $j = sprintf("%02d",$j);
  $k = sprintf("%02d",$k);
  $output_it = "$j.$k";
 }
 chomp($humdataarray[1]);
 $j = abs(int ($humdataarray[1] / 100));
 $k = abs(int ($humdataarray[1]));
 $k = $k - ($j * 100);
 $j = sprintf("%04d",$j);
 $k = sprintf("%02d",$k);
 $output_ip = "$j.$k";
 chomp($humdataarray[2]);
 $j = abs(int ($humdataarray[2]));
 $k = abs(int ($humdataarray[2] * 100));
 $k = $k - ($j * 100);
 $j = sprintf("%02d",$j);
 $k = sprintf("%02d",$k);
 $output_ih = "$j.$k";

 open (FILE,$humdatafilename2);
 (@humdataarray) = (<FILE>);
 close (FILE);

 chomp($humdataarray[0]);
 if ($humdataarray[0] < 0){
  $j = abs(int ($humdataarray[0]));
  $k = abs(int ($humdataarray[0] * 10));
  $k = $k - ($j * 10);
  $j = sprintf("%03d",$j);
  $k = sprintf("%01d",$k);
  $output_ot = "-$j.$k";
 }
 else {
  $j = abs(int ($humdataarray[0]));
  $k = abs(int ($humdataarray[0] * 100));
  $k = $k - ($j * 100);
  $j = sprintf("%02d",$j);
  $k = sprintf("%02d",$k);
  $output_ot = "$j.$k";
 }
 chomp($humdataarray[1]);
 $j = abs(int ($humdataarray[1] / 100));
 $k = abs(int ($humdataarray[1]));
 $k = $k - ($j * 100);
 $j = sprintf("%04d",$j);
 $k = sprintf("%02d",$k);
 $output_op = "$j.$k";
 chomp($humdataarray[2]);
 $j = abs(int ($humdataarray[2]));
 $k = abs(int ($humdataarray[2] * 100));
 $k = $k - ($j * 100);
 $j = sprintf("%02d",$j);
 $k = sprintf("%02d",$k);
 $output_oh = "$j.$k";


 #tokoyami
 $timenow = time;
 $timeseed = $timenow - 1510434000;
 $timeseed = int ($timeseed / 86400);
 $timeseed %= 4;

 if ($timeseed == 0){($toko_r,$toko_d,$toko_m) = (1,3,2);}
 if ($timeseed == 1){($toko_r,$toko_d,$toko_m) = (2,4,3);}
 if ($timeseed == 2){($toko_r,$toko_d,$toko_m) = (3,1,4);}
 if ($timeseed == 3){($toko_r,$toko_d,$toko_m) = (4,2,1);}

 #boueigun
 $timenow = time;
 $timeseed = $timenow - 1510434000;
 $timeseed = int ($timeseed / 3600);
 $timeseed %= 7;

 if ($timeseed == 0){($defe_i,$defe_j) = ("Yy","Yy");}
 if ($timeseed == 1){($defe_i,$defe_j) = ("Yy","Ww");}
 if ($timeseed == 2){($defe_i,$defe_j) = ("Ww","Ww");}
 if ($timeseed == 3){($defe_i,$defe_j) = ("Ww","Xx");}
 if ($timeseed == 4){($defe_i,$defe_j) = ("Xx","Xx");}
 if ($timeseed == 5){($defe_i,$defe_j) = ("Xx","Zz");}
 if ($timeseed == 6){($defe_i,$defe_j) = ("Zz","Yy");}

 (@date) = localtime (time);
 $time_format = sprintf("%02d:%02d",$date[2],$date[1]);

 $dataone = "  " .$output_it."c  ".$output_ot."c";
 $datatwo = "  " .$output_ih."p  ".$output_oh."p";
 $datathr = $output_ip."h".$output_op."h";
 $datafou = "R".$toko_r."D".$toko_d."M".$toko_m." ".$defe_i.$defe_j.$time_format;

 #print "$dataone\n$datatwo\n$datathr\n$datafou\n";
 &inputbasebitmap;
 $outputline = 0;$outputcol = 0;
 foreach $ch (split //, $dataone) { &renderfont($ch);$outputcol++;}
 $outputline = 1;$outputcol = 0;
 foreach $ch (split //, $datatwo) { &renderfont($ch);$outputcol++;}
 $outputline = 2;$outputcol = 0;
 foreach $ch (split //, $datathr) { &renderfont($ch);$outputcol++;}
 $outputline = 3;$outputcol = 0;
 foreach $ch (split //, $datafou) { &renderfont($ch);$outputcol++;}

 $bitmapoutput = "424d361800000000000036000000280000004000000020000000010018000000000000180000120b0000120b00000000000000000000";
 for $i (0..31){
  for $j (0..63){
   for $k (0..2){
    $bitmappointer = (( 31 - $i ) * 64 + $j) * 3 + $k;
    $bitmapoutput .= $bitmapoutputbase[$bitmappointer];
   }
  }
 }
 $bitmapbinary = pack("H*",$bitmapoutput);
 open (OUTPUT,">$outputfilename");
 binmode(OUTPUT);
 print OUTPUT $bitmapbinary;
 close (OUTPUT);
}

sub inputbitmapfont {
 open (IN,$inputbitmapfontfilename);
 binmode (IN);

 $buffersize = 1;
 $count = 0;
 $output = "";
 undef (@rawdata);
 $rawcount = 0;
 while (){
  $count++;
  read(IN,$readdata,$buffersize);
  if ($count < 55){next;}
  if ($count > 20000){last;}
  $readdata = unpack("H2",$readdata);
  $rawdata[$rawcount] = $readdata;
  $rawcount++;
 }
 close (IN);

#      コゥ・    E       コヨAア・ゥ鈬ノ
                                  ?B

 for ($i=1;$i>-1;$i--){
  for ($j=0;$j<16;$j++){
   $fontseed = "$i:$j";
   for ($k=7;$k>-1;$k--){
    for ($l=0;$l<4;$l++){
     $imagex = (( $j * 4 ) + $l) * 3;
     $imagey = ( $i * 8 ) + $k;
     $imagepointerbase = ( $imagey * 64 * 3 ) + $imagex;
     for ($m=0;$m<3;$m++){
      $imagepointer = $imagepointerbase + $m;
      $fontdata{$fontseed} .= $rawdata[$imagepointer];
     }
    }
   }
  }
 }
}

sub inputbasebitmap {
 open (IN,$inputbitmapbackgroundfilename);
 binmode (IN);

 $buffersize = 1;
 $count = 0;
 $output = "";
 undef (@bitmapoutputbase);
 $colcount = 0;
 $rowcount = 31;
 while (){
  $count++;
  read(IN,$readdata,$buffersize);
  if ($count < 55){next;}
  if ($count > 20000){last;}
  $readdata = unpack("H2",$readdata);
  $rawcount = $rowcount * 64 * 3;
  $rawcount += $colcount;
  $bitmapoutputbase[$rawcount] = $readdata;
  $colcount++;
  if ($colcount > 191){
   $rowcount--;
   if ($rowcount < 0){last;}
   $colcount = 0;
  }
 }
 close (IN);
}


sub renderfont {
 my $data = $_[0];

#0123456789.ch:p-
#RDMぶけラ
 $fontseed = "1:15";
 if ($data eq " "){$fontseed = "1:15";}
 if ($data eq "0"){$fontseed = "0:0";}
 if ($data eq "1"){$fontseed = "0:1";}
 if ($data eq "2"){$fontseed = "0:2";}
 if ($data eq "3"){$fontseed = "0:3";}
 if ($data eq "4"){$fontseed = "0:4";}
 if ($data eq "5"){$fontseed = "0:5";}
 if ($data eq "6"){$fontseed = "0:6";}
 if ($data eq "7"){$fontseed = "0:7";}
 if ($data eq "8"){$fontseed = "0:8";}
 if ($data eq "9"){$fontseed = "0:9";}
 if ($data eq "."){$fontseed = "0:10";}
 if ($data eq "c"){$fontseed = "0:11";}
 if ($data eq "h"){$fontseed = "0:12";}
 if ($data eq ":"){$fontseed = "0:13";}
 if ($data eq "p"){$fontseed = "0:14";}
 if ($data eq "-"){$fontseed = "0:15";}
 if ($data eq "R"){$fontseed = "1:0";}
 if ($data eq "D"){$fontseed = "1:1";}
 if ($data eq "M"){$fontseed = "1:2";}
 if ($data eq "W"){$fontseed = "1:3";}
 if ($data eq "w"){$fontseed = "1:4";}
 if ($data eq "X"){$fontseed = "1:5";}
 if ($data eq "x"){$fontseed = "1:6";}
 if ($data eq "Y"){$fontseed = "1:7";}
 if ($data eq "y"){$fontseed = "1:8";}
 if ($data eq "Z"){$fontseed = "1:9";}
 if ($data eq "z"){$fontseed = "1:10";}
 $fontcolcount = 0;
 $fontrowcount = 0;
 @fontdataarray = $fontdata{$fontseed} =~ /.{2}/g;
 foreach $ch (@fontdataarray) {
  $fontrow = ($outputline * 8) + $fontrowcount;
  $fontcol = ($outputcol * 4 * 3 ) + $fontcolcount;
  $injectpointer = ($fontrow * 3  * 64) + $fontcol;
  if ($ch ne "00"){
   $bitmapoutputbase[$injectpointer] = $ch;
  }
  $fontcolcount++;
  if ($fontcolcount > 11){
   $fontrowcount++;
   $fontcolcount = 0;
  }
 }
}