2015/10/28

Intel Edisonでタイムラプス撮影 その1

以前、ストップモーション ムービーを作って遊んだ時は、ノートPCを使ってテザー撮影したけれども、タイムラプスの撮影をする時は撮影画像をその場でチェックするわけじゃないから、Intel Edisonでも十分可能だろうということで試してみた。

pkTriggerCord

カメラはこういう時の遊び用に使っているPentax K20Dなので、リモートコントロールのソフトにはpkTriggerCord (ver. 0.82.04)を使用した。
ソースをダウンロードして、GUIはいらないので、
# make cli
# make install
で、あっさりと完了。
OTGケーブルを経由してK20Dを繋いだら、とりあえず1枚撮影してみる。
# pktriggercord-cli --green -o test.jpg
画面のないEdison上では画像を確認できないので、PCに転送して撮影できていることを確認。

簡単にタイムラプスのテストもしてみた。
# pktriggercord-cli --frames 10 --delay 10 --green -o test
上記のコマンドで10秒毎に10枚撮影してくれる。画像の転送時間を考慮して待ち時間を調整してくれるので、例えば転送に4秒かかったら6秒待機して、正確に10秒毎に撮影をしてくれる。

ImageMagick

ちょうどpkTriggerCordのサイトにタイムラプス撮影の解説もあったので、それに従ってクロップとリサイズもEdison上でやってしまうことにした。
ImageMagick (ver. 6.9.2-4)のソースをダウンロードして、
# ./configure
# make
いくつか警告が出たけれども、エラーはなく終了。
先程撮影した画像でテストしてみると、
# identify test.jpg
identify: no decode delegate for this image format 'test.jpg'
と言われてしまった。
# identify -list configure | grep DELEGATES
で確認してみると、確かにjpegがない。
jpegのライブラリがないのが原因らしいので、インストールする。opkgで探してみると、
# opkg list | grep jpeg
libjpeg8とlibjpeg-devというのが見つかったので、インストールしてみた。
# opkg install libjpeg8
# opkg install libjpeg-dev
そうしたら、再度
# ./configure
してから、
# make
する。そうすると、
# identify -list configure | grep DELEGATES
DELEGATES bzlib mpeg jpeg xml zlib
となって、identify コマンドもきちんとjpeg画像の情報を表示してくれるようになった。

FFmpeg

最後はFFmpeg。静止画から動画の変換はEdisonでしなくてもいいかなと思ったけれども、せっかくなので挑戦してみた。

ソースはgitからクローンする。
# git clone git://source.ffmpeg.org/ffmpeg.git ffmpeg
(git クライアントは# opkg install gitでインストールできる。)
# ./configure
を実行すると、prコマンドがなくてエラーになる。prコマンドはcoreutilsに含まれているので、
# opkg install coreutils
でインストール。
すると今度はyasm/nasmがないとエラーがでる。
yasm/nasm not found or too old. Use --disable-yasm for a crippled build.
メッセージの通り、--disable-yasmをつけてやり直し。
# ./configure --disable-yasm
# make
すると、makeの途中でエラーが出た。
libavcodec/x86/cabac.h:192:5 error: 'asm' operand has impossible constraints
gccのインライン アセンブラのエラーらしい。Edisonにインストールされているgccはver. 4.9.1。 NASM (ver. 2.11.08)をインストールしたら何か変るかと試してみたけれども、同様のエラーがでる。
該当のヘッダを使用しているソースを見てみると、H264のデコード関連らしい。今回の目的(静止画から動画への変換)には必要のない機能なので、その機能を除外してmakeしてみた。
# ./configure --disable-decoder=h264
そうすると、エラーになる箇所はスキップしてビルドできた。

ついでなので、色々と試してみたところ、--disable-asmまたは--disable-optimizationsを指定するとH264のデコード機能を生かしたままビルドできた。でも、実際に計測はしていないけれども、恐らく他のコーデックのエンコード/デコード性能も落ちると予想できるので、今回はH264のデコードを諦めることにした。

さらについでに、H264のエンコードをサポートしたい場合は、x264のライブラリをopkgでインスールして、--enable-libx264を指定すれば良いみたい。(このスレッドを参考にした。)
# opkg install libx264-133
# opkg install libx264-bin
# opkg install libx264-dev
# opkg install libx264-staticdev
最終的にconfigureのオプションは以下のようになった。
# ./configure --disable-decoder=h264 --enable-libx264 --enable-gpl
あとはmakeして完了。(ちなみに、ビルドに2時間くらいかかる。)
# ffmpeg -codecs | grep 264
.EV.LS h264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (encoders: libx264 libx264rgb)
H264のエンコードをサポートしたffmpegのできあがり。

2015/10/10

Intel Edison; clone

I wanted to clone/copy a reference Edison board to multiple Edison boards. Maybe, the proper way of doing this is to build from source code with a customised configuration. But I also wanted to find out an easy way of backup/restore. And I came up with the following steps.
  1. Preparation 1: Bootable SD card.
  2. Preparation 2: Make a reference Edison
  3. Enable resize-rootfs.service.
  4. Boot from SD card.
  5. Mount rootfs and check how much used.
  6. Create a disk image and mount it.
  7. Copy files from rootfs@emmc to the mounted disk image.
  8. Unmount the disk image and copy it to a PC.
  9. Rename the disk image file to edison-image-edison.ext4 and replace the same name file in unzipped firmware directory.
  10. Run flashall against a target Edison board.

Preparation 1

It needs bootable SD card to safely copy rootfs partition. See this post for detail.

Preparation 2

Install required software, enable/disable services, add user account, etc.

Enable resize-rootfs.service

When create a disk image file, it need not copy empty blocks. So a disk image file is smaller than rootfs partition's size. After a target's rootfs partition is overwritten with a disk image, it needs to extend to an actual size. It happens when flashing by flashall/ota method too, so that there is already a service that runs only once at the first boot. Enable this service before boot from SD card. But even if you forget this, you can just run resize2fs command to extend rootfs partition. It can be done on live file system.
# systemctl enable resize-rootfs
Then reboot from SD card.
# reboot from_sdcard

Mount rootfs partition in eMMC and check size

After boot from SD card, mount rootfs partition in emmc and check its size.
# mkdir /mnt/emmc
# mount /dev/mmcblk0p8 /mnt/emmc

Run df and see how much used. In my case, 500MB is enough.
# df -h | grep /mnt/emmc
Filesystm      Size   Used Available Use% Mounted on
/dev/mmcblk0p8 1.4G 471.0M    889.0M  35% /mnt/emmc

Create a disk image and mount

The following command creates 512MB (512KB * 1024) disk image file (edison-rootfs.ext4). If you need bigger space, modify count=1024.
# dd if=/dev/zero of=edison-rootfs.ext4 bs=512K count=1024
# mkfs.ext4 -F -L rootfs edison-rootfs.ext4
# mkdir /mnt/image
# mount -o loop edison-rootfs.ext4 /mnt/image

Copy from eMMC to disk image

It is optional, but you can delete journal files before coping.
# cd /mnt/emmc/var/log/journal
# rm -rf *

It is also optional. But if a copied Edison is used somewhere else, it would be better to delete your Wifi information.
# cd /mnt/emmc/etc/wpa_supplicant
# cp wpa_supplicant.conf.original wpa_supplicant.conf

Now, copy all files.
# cp -a /mnt/emmc/* /mnt/image/
It seems to be better to use rsync because cp copies hard linked files as individual file. But then it needs to install rsync from opkg.
# opkg install rsync
# rsync -rlH /mnt/emmc/ /mnt/image/

Unmount and copy

# umount /mnt/image
# umount /mnt/emmc

Copy edison-rootfs.ext4 to a PC.

Clone

To make a clone, rename edison-rootfs.ext4 to edison-image-edison.ext4 and replace the same name file in a unzipped firmware directory. Then run flashall script and connect a target Edison.

(Strictly speaking, it is not a complete clone. It only copies rootfs. You might want to copy home and u-boot-env0 partitions too. To make more perfect clone, it needs to copy factory partition too. (That partition contains serial number and Bluetooth MAC address.))

2015/10/08

Intel Edison; boot from SD card.

There is very detailed post in Intel's forum. Basically I just follow the instruction in that post.
https://communities.intel.com/thread/61048

Prepare SD card

In my case, out-of-box Edison (edison-weekly_build_56_2014-08-20_15-54-05) did not have mkfs.ext4 command. But in the latest firmware (weekly-159), the command exists. And so you do not need a Linux PC to format SD card with ext4.

Copy edison-image-edison.ext4 in a zipped firmware file to Edison using scp command.
$ scp edison-image-edison.ext4 root@192.168.2.15:edison-image-edison.ext4
Or copy the file to a SD card.

Insert SD card to Edison. If you copied the file to SD card, then copy the ext4 image file to somewhere else as SD card will be formatted.
# cp /media/sdcard/edison-image-edison.ext4 /home/root/

Find SD card's device name
# mount | grep sdcard
In my case, it is /dev/mmcblk1.

Format it with ext4.
# umount /media/sdcard
# mkfs.ext4 /dev/mmcblk1p1

Mount ext4 image file and SD card.
# mount -o loop /home/root/edison-image-edison.ext4 /mnt
# mount /dev/mmcblk1p1 /media/sdcard

Copy files.
# cp -a /mnt/* /media/sdcard/

Configure U-Boot variables

I wrote a shell script based on the forum post.

#!/bin/sh
fw_setenv mmc-bootargs 'setenv bootargs root=${myrootfs} rootdelay=3 rootfstype=ext4 ${bootargs_console} ${bootargs_debug} systemd.unit=${bootargs_target}.target hardware_id=${hardware_id} g_multi.iSerialNumber=${serial#} g_multi.dev_addr=${usb0addr}'

# SD card
sdcard=`mount | grep sdcard | awk '{print $1;}'`
if [ "$sdcard" == "" ] ; then
  echo Insert SD card and try again.
  exit
fi
fw_setenv myrootfs_sdcard $sdcard

# eMMC
emmc=`/usr/sbin/fw_printenv uuid_rootfs | sed 's/uuid_rootfs=\(.*\)/\1/'`
fw_setenv myrootfs_emmc PARTUUID=$emmc

# Can use those at boot> prompt too.
fw_setenv do_boot_emmc 'setenv myrootfs ${myrootfs_emmc}; run do_boot'
fw_setenv do_boot_sdcard 'setenv myrootfs ${myrootfs_sdcard}; run do_boot'

# reboot from_sdcard or from_emmc
fw_setenv do_handle_bootargs_mode 'run do_preprocess_bootargs_mode; if itest.s $bootargs_mode == "ota" ; then run do_ota; fi; if itest.s $bootargs_mode == "boot" ; then run do_boot; fi; if itest.s $bootargs_mode == "flash"; then run do_flash; fi; if itest.s $bootargs_mode == "from_sdcard"; then run do_boot_sdcard; fi; if itest.s $bootargs_mode == "from_emmc"; then run do_boot_emmc; fi; run do_fallback; exit;'

The script modifies do_handle_bootargs_mode variable too. With this modification, you can boot from SD card by "reboot from_sdcard", or from eMMC by "reboot from_emmc".


2015/10/07

Intel Edison; flashing out-of-box Edison

There are two (or more?) ways to flash Edison.

  1. Phone Flash Tool (GUI) or flashall.bat/flashall.sh (CUI)
  2. reboot ota command or run do_ota at Boot prompt.
But it cannot use "reboot ota" method on out-of-box Edison. In my case, oob Edison's version is
root@edison:~# cat /etc/version 
edison-weekly_build_56_2014-08-20_15-54-05

And if you run reboot ota, it fails. The reason is in ota_abort_reason U-boot environment variable.
root@edison:~# fw_printenv ota_abort_reason
ota_abort_reason=Partition rootfs too small for edison-image-edison.ext4 

Oob Edison's partition layout looks like this.
Number Start End Size File system Name Flags 
 1 1049kB 3146kB 2097kB       u-boot0 
 2 3146kB 4194kB 1049kB       u-boot-env0 
 3 4194kB 6291kB 2097kB       u-boot1 
 4 6291kB 7340kB 1049kB       u-boot-env1 
 5 7340kB 8389kB 1049kB ext2  factory 
 6 8389kB 33.6MB 25.2MB       panic 
 7 33.6MB 67.1MB 33.6MB fat16 boot 
 8 67.1MB 604MB   537MB ext4  rootfs 
 9  604MB 1409MB  805MB       update 
10 1409MB 3909MB 2500MB ext4  home 

To compare, this is a partition layout after flashing to the latest firmware (weekly-159).
Number Start End Size File system Name Flags 
 1 1049kB 3146kB 2097kB       u-boot0 
 2 3146kB 4194kB 1049kB       u-boot-env0 
 3 4194kB 6291kB 2097kB       u-boot1 
 4 6291kB 7340kB 1049kB       u-boot-env1 
 5 7340kB 8389kB 1049kB ext2  factory 
 6 8389kB 33.6MB 25.2MB       panic 
 7 33.6MB 67.1MB 33.6MB fat16 boot 
 8 67.1MB 1678MB 1611MB ext4  rootfs 
 9 1678MB 2483MB  805MB       update 
10 2483MB 3909MB 1426MB ext4  home 

reboot ota command cannot change a partition layout, because the command refers files in update partition and rootfs partition is followed by update partition. If extend rootfs partition size, it destroys update partition.

On the other hand, flashall command does the following steps.
  1. Flash u-boot0/1 and u-boot-env0/1 partitions.
  2. Reboot.
  3. Flash rootfs partition.
At the second reboot step, U-boot overwrites a partition table using updated partitions variable at the first step.
root@edison:~# fw_printenv partition
partitions=uuid_disk=${uuid_disk};name=u-boot0,start=1MiB,size=2MiB,uuid=${uuid_uboot0};name=u-boot-env0,size=1MiB,uuid=${uuid_uboot_env0};name=u-boot1,size=2MiB,uuid=${uuid_uboot1};name=u-boot-env1,size=1MiB,uuid=${uuid_uboot_env1};name=factory,size=1MiB,uuid=${uuid_factory};name=panic,size=24MiB,uuid=${uuid_panic};name=boot,size=32MiB,uuid=${uuid_boot};name=rootfs,size=1536MiB,uuid=${uuid_rootfs};name=update,size=768MiB,uuid=${uuid_update};name=home,size=-,uuid=${uuid_home}; 

Just for reference, oob Edison's partition variable:
partitions=uuid_disk=${uuid_disk};name=u-boot0,start=1MiB,size=2MiB,uuid=${uuid_uboot0};name=u-boot-env0,size=1MiB,uuid=${uuid_uboot_env0};name=u-boot1,size=2MiB,uuid=${uuid_uboot1};name=u-boot-env1,size=1MiB,uuid=${uuid_uboot_env1};name=factory,size=1MiB,uuid=${uuid_factory};name=panic,size=24MiB,uuid=${uuid_panic};name=boot,size=32MiB,uuid=${uuid_boot};name=rootfs,size=512MiB,uuid=${uuid_rootfs};name=update,size=768MiB,uuid=${uuid_update};name=home,size=-,uuid=${uuid_home};