Raspberry Pi Picoでアナログ時計(原子精度)

MicroPythonで楽々プログラミング。十分に高速処理してくれます。
舐めてかかったら、色々、初心に帰ることに(笑い)。
1)UTC(グリニッジ)からLOCAL時間に+9時間・・・・
  桁上りが複雑だったのに、Simpleに組む方法を試行錯誤。
2)針が通過したところの絵を戻すのに、スプライトなんてものは
  無いから、針の汚したところを裏絵で描き戻し。
3)12時の通過時にたくさんの処理が集中しないように、分散化。
4)Core1も使ったスレッド処理を試みるもSMP-OSの無い中では、
  制限がきつい。
5)GPS情報に曜日は載らないので、計算するのね。
  def week(yy, feb):
    days = (125+yy[0]+yy[0]//4+int(“*033614625035″[yy[1]])+yy[2])
    wday = (days-1)%7 if feb==29 and yy[1]<3 else days%7
    return wday

などなど・・・

https://github.com/NorioFujii/GitPython/


カテゴリー: RaspberryPi, お知らせ | 1件のコメント

RaspberryPi Pico で 高度Lチカ 音の光出力

銭湯の料金1回分で買えるRaspberryPi Pico、恐ろしい能力を秘めていました。
専用ICチップ無しにSPDIFで音楽を光送出するのにも使えるPIO機能の装備は、
他の廉価マイコンボードに真似ができません。
Example Programとして用意されている、Sine波出力プログラムを
https://github.com/raspberrypi/pico-playground/tree/master/audio/sine_wave

アレンジして、好みの楽曲のWAVファイルから、高度Lチカによって光再生する
Cソースコードを生成し、コンパイルして書き込む手順をここに公開します。

表面実装タイプのボード1枚のまま、何も増設せずに再生できるように、Flash
2MBの範囲(10秒程度繰返し)で書き込めるサンプルプログラムとします。
Example ProgramのSine波の代わりにWAVファイルから取り出したPCMデータの
先頭から10秒程度を与える形のソースコード生成をツールで支援してくれます。

ソースコード生成のためにPythonプログラムを用意しています。
母艦はWindowsでもMacでもOKですが、ここではPico親類のRaspberry Pi3Bや4B
での操作例をハードコピーしています。

用意すべきWAVファイルは、16BitモードでMonoにフォーマット変換したリアルPCM
のものです。Stereoでの実装は、まだ少しチューニングが必要なようです。

1)ツールによるソースコード生成
(cmd)python3 uf2convWav.py -o sine_wave_spdif.c  -C 入力WAVファイル名
次の uf2convWav.py を実行することで、ソースコード sine_wave_spdif.c
が生成されます。
https://mori1-hakua.tokyo/test/uf2convWav.txt (拡張子変更)

2)Pico開発環境のセットアップ
クイック・セットアップとして紹介されている手順で整備します。
https://www.raspberrypi.org/blog/how-to-blink-an-led-with-raspberry-pi-pico-in-c/
blink.uf2 を作って書き込んでみるのは、いい予行演習になりますね。

3)sine_wave のアレンジ
2)の「cd pico/pico-examples」の代わりに「cd pico/pico-playground」と
入力し、お定まりの手順を実行し、配下のaudio/sine_wave に移動します。
mkdir build
cd build
cmake ..
make
次に、CMakeLists.txtのadd_executable(sine_wave_spdif sine_wave.c)を、
add_executable(sine_wave_spdif sine_wave_spdif.c)に替えます。
また、同じディレクトリ内に、1)で生成したsine_wave_spdif.cを追加します。

4)コンパイルしターゲットファイル作成
再び、buildディレクトリで、
cd build
cmake ..
make
によって、配下のaudio/sine_waveディレクトリに出力されたuf2ファイルを
確認します。(Flash2MBを超えても、平気で書き込むので要注意です)

5)Picoボードへの書き込み
Blinkプログラムと同様の方法です。
PicoボードのBOOTSELボタンを押したまま、母艦からのUSBケーブルを接続し、
次のCopyコマンドを実行します(ケーブル抜差しを避けるにはRUN端子を使う)。
cp build/audio/sine_wave/sine_wave_spdif.uf2 /media/pi/RPI*

6)オーディオ装置への光入力
Picoボードに5Vを供給、光デジタル入力のあるオーディオ装置で、入力形式を
PCMと設定し、光ケーブルの一方をPicoボードのLEDに近づけます。
GPIO12をGNDに落とせば、用意した楽音とサイン波とを交互に切り替えることが
出来ます。
なお、オーディオ装置の初期ボリューム設定には、十分に留意してください。

カテゴリー: RaspberryPi | 2件のコメント

Raspberry Pi Picoで美咲フォントの常駐が出来た

Micro:bit V2に続いて出荷された、RasPIの4ドルのプロセッサボード、
Raspberry Pi Pico。なんと、Flash Memoryに美咲フォントを常駐化できた。
貴重なSRAM領域を殆ど消費しない(Flashからseekで利用)。
電子ペーパー書き込み機や、OLEDのディスプレイなど、日本語の表示が
電池搭載軽端末として実現できる。
産業的にも廉価ツールを普及できるかもしれない。

次にライブラリのソースコードを載せる。

font_read16.py

import os, sys, binascii
from micropython import const
TEXT_NORMAL = const(2)
COLBYTES = const(25)
yoko = 94
tate = 12
fontL = 84
img = [[0 for x in range(yoko)] for y in range(tate)]
# kanjiL = [[0 for x in range(yoko*2)] for y in range(2)]
kanjiL = ""
last_seek = -1
last_eye = 0
# BMPデータを取り込む
fbm = open("images/k8x12L_jisx0208_r.bmp", "rb")
# headerとpadding zero を取り除いたBitmapファイル

# 文字列の入力と変換
def dispUTF(strg, disp=None, rot=None):
    global img, kanjiL, last_seek, last_eye
    strg1 = bytes(strg,'utf-8')
    strg2 = ""
    if strg1[0]==0:  # 半角の時、全角に
        i = strg1[1]+0x20
        strg1 = chr(strg1[1]).encode()
        strg2 = "ff" + ('%02x' % (i^0xC0 if i&0x80 else i^0x40)) 
    elif 0xc2<=strg1[0]<=0xdf:
        strg2 = ('%02x' % (strg1[0]&0x1f)>>2) \
              + ('%02x' % (((strg1[0]&0x1f)<<6)|(strg1[1]&0x3f))%256)
    elif 0xe0<=strg1[0]<=0xef:
        strg2 = ('%02x' % ((strg1[0]&0x0f)<<4 | (strg1[1]&0x3f)>>2)) \
              + ('%02x' % ((strg1[1]<<6)&0xff | strg1[2]&0x3f))
    with open("images/JIS16_tbl.txt", "rb") as ftx:
        # UTF-16(BE) BOM付きで94字/行にcr改行されたFontファイル
        dmy = ftx.read(2)
        i = last_eye
        j = -1
        k = 0
        key = strg2  # '%02x%02x' % (strg1[0],strg1[1])
        x = kanjiL.find(key)
        if x >= 0 and x % 4 == 0:
            j = x // 4
        else:
            for i in range(fontL): # 一定長の読み込みを続ける
                kanjiL = str(binascii.hexlify(ftx.read(yoko*2+2)),'utf-8')
                x = kanjiL.find(key)
                if x < 0 or x & 1 > 0:
                    n = kanjiL[0:yoko*4].find("000d")
                    if n != -1:
                        k += 1
                        dmy = ftx.read(n//2 + 2) # 4バイト文字以降は捨てる
                    continue
                j = x // 4
                break
            if j==-1:
                print('Kanji Not found',key,'from',strg)
                return
            last_eye = i + k
    print(strg1.decode(), last_eye, j, k, key)
    new_seek = tate*(fontL-last_eye-1)*yoko
    if last_seek != new_seek:
        last_seek = new_seek
        fbm.seek(new_seek)
        for y in range(tate):
            img[11-y] = fbm.read(yoko)
    dots = ""
    fontw = 8
#    tate  = 12
    for q in range(tate) :
        c = img[q][j]
        for r in range(0, fontw) :
            dots += ("●●" if (c & (0x80 >> r))==0 else " ")
            if disp:
                pos = disp.x + r*TEXT_NORMAL
                bufc = disp.on if (c & (0x80 >> r))>0 else disp.on ^ 1
                disp.set_pixel(pos,disp.y+q*TEXT_NORMAL, bufc, rotate=rot)
                disp.set_pixel(pos+1,disp.y+q*TEXT_NORMAL, bufc, rotate=rot)  # TEXT_NORMAL times
                disp.set_pixel(pos,disp.y+1+q*TEXT_NORMAL, bufc, rotate=rot)
                disp.set_pixel(pos+1,disp.y+1+q*TEXT_NORMAL, bufc, rotate=rot)  # TEXT_NORMAL times
        dots += "\n"
    if disp :
        disp.x += fontw*TEXT_NORMAL
    else:
        print(dots)

def reptTXT(strg, disp=None, rot=None):
    strg1 = strg.encode() if len("日本語")==3 else bytes(strg, 'utf-8')
    skip=0
    for i in range(len(strg1)):
        if (skip>0):
            skip -= 1
            continue
        code=ord(strg1[i:i+1]) & 0xFF
        if (code<=0x1F):
            if (code==0) :
                break
        elif (code<=0x7F):
            dispUTF(chr(0x00)+chr(code), disp=disp, rot=rot)
        elif (code & 0xe0)==0xe0:
            dispUTF(strg1[i:i+3], disp=disp, rot=rot)
            skip = 2
        elif (code & 0xc0)==0xc0:
            dispUTF(strg1[i:i+2], disp=disp, rot=rot)
            skip = 1

カテゴリー: RaspberryPi, お知らせ | 2件のコメント

Micro:bit V2 で 電子ペーパー表示ができた!

micro:bit v1だと、メモリ不足で歯が立たない
>>> microbit.reset()
MemoryError:
MicroPython v1.9.2-34-gd64154c73 on 2017-09-01; micro:bit v1.0.1 with nRF51822
Type “help()” for more information.
>>>
>>> micropython.mem_info()
stack: 516 out of 1800
GC: total: 10048, used: 672, free: 9376
No. of 1-blocks: 18, 2-blocks: 9, max blk sz: 3, max free sz: 562
>>>

micro:bit v2では、8KBのソースが複数個ロードでき、余裕で動作する。
>>> microbit.reset()
MicroPython v1.13 on 2020-12-21; micro:bit v2.0.0-beta.3 with nRF52833
Type “help()” for more information.
>>>
>>> micropython.mem_info()
stack: 392 out of 7680
GC: total: 64512, used: 24832, free: 39680
No. of 1-blocks: 583, 2-blocks: 199, max blk sz: 189, max free sz: 1266
>>>

# MemoryDisplayライブラリ (MemoDisp.py)

# The MIT License (MIT)
#
# Copyright (c) 2018 ladyada for Adafruit Industries
# pylint: disable=line-too-long
"""
`adafruit_sharpmemorydisplay`
====================================================
  https://github.com/adafruit/circuitpython/releases

"""
from microbit import *
from micropython import const
# import sharp_memorydisp
_SHARPMEM_BIT_WRITECMD = const(0x80)  # in lsb
_SHARPMEM_BIT_VCOM = const(0x40)  # in lsb
_SHARPMEM_BIT_CLEAR = const(0x20)  # in lsb
spi_clk = pin13
spi_scs = pin12

CS_ACTIVE = const(1)
CS_INACTIVE = const(0)
# Colors
BLACK = const(0)
WHITE = const(255)
# Parameters to Change
COLS = const(144)
ROWS = const(168)
COLBYTES = const(COLS // 8)
TEXT_NORMAL = const(2)
ROTATION = list(range(4))

_icons = [getattr(Image, x) for x in dir(Image)
          if hasattr(getattr(Image, x), 'get_pixel')]

def reverse_bit(num):
    """Turn an LSB byte to an MSB byte, and vice versa. Used for SPI as
    it is LSB for the SHARP, but 99% of SPI implementations are MSB only!"""
    result = 0
    for _ in range(8):
        result <<= 1
        result += num & 1
        num >>= 1
    return result
class SharpMemoryDisplay():
    """A driver for sharp memory displays, you can use any size but the
    full display must be buffered in memory!"""

    def __init__(self, spiP, width, height, *,
                 baudrate=2000000, portrait=True, bottom=False):
        self._scs_pin = spi_scs
        # The SCS pin is active HIGH so we can't use bus_device. exciting!
        # scs_pin.switch_to_output(value=True)
        self._baudrate = baudrate
        self._portrait = portrait
        self._bottom = bottom
        self._spi = spiP
        self.width = width
        self.height = height
        # prealloc for when we write the display
        self._buf = bytearray(1)
        self.buffer = bytearray((width // 8) * height)
        # Set the vcom bit to a defined state
        self._vcom = True

    def fill(self, color, start=0, stop=0):
        """completely fill/clear the buffer with a color"""
        if color == 1:
            fill = WHITE
        else:
            fill = BLACK
        if stop == 0:
            bufl = len(self.buffer)
        else:
            bufl = stop*COLBYTES
        if not self._portrait:
            start = 0
            bufl = len(self.buffer)
        elif self._bottom :
            bufl = (self.height - start)*COLBYTES
            if stop>0:
                start = (self.height - stop)*COLBYTES
        for i in range(start, bufl):
            self.buffer[i] = fill

    def clear(self):
        """completely fill/clear the buffer """
        self._scs_pin.write_digital(CS_ACTIVE)
        self._buf[0] = _SHARPMEM_BIT_CLEAR
        self._spi.write(self._buf)
        self._buf[0] = 0
        self._spi.write(self._buf)  # we send one last 0 byte
        self._scs_pin.write_digital(CS_INACTIVE)

    def show(self, start=1, stop=0, rotate=0):
        portrait, bottom = ROTATION[rotate]
        # CS pin is inverted so we have to do this all by hand
        self._scs_pin.write_digital(CS_ACTIVE)
        # toggle the VCOM bit
        self._buf[0] = _SHARPMEM_BIT_WRITECMD
        if self._vcom:
            self._buf[0] |= _SHARPMEM_BIT_VCOM
        self._vcom = not self._vcom
        self._spi.write(self._buf)

        if (not portrait) or stop == 0:
            start = 1
            stop = self.height
            stopl = self.height + 1
        else:
            stopl = stop + 1
        if portrait and bottom :
            stopl = (self.height - start+1) + 1
            start = (self.height - stop) + 1
        line_len = COLBYTES
        slice_from = (start-1) * line_len
        for line in range(start, stopl):
            self._buf[0] = reverse_bit(line)
            self._spi.write(self._buf)
            self._spi.write(
                 memoryview(self.buffer[slice_from : slice_from + line_len]))
            slice_from += line_len
            self._buf[0] = 0
            self._spi.write(self._buf)
        self._spi.write(self._buf)  # we send one last 0 byte
        self._scs_pin.write_digital(CS_INACTIVE)

    def draw_line(self, x0, y0, x1, y1, color=1, rotate=0):
        dx = abs(x1 - x0)
        sx = 1 if x0 < x1 else -1
        dy = -abs(y1 - y0)
        sy = 1 if y0 < y1 else -1

        err = dx + dy
        while True:
            self.set_pixel(x0, y0, color, rotate=0)
            if x0 == x1 and y0 == y1:
                break
            e2 = 2 * err
            if e2 > dy:
                err += dy
                x0 += sx
            if e2 <= dx:
                err += dx
                y0 += sy

    def set_pixel(self, x, y, color=1, rotate=0):
        portrait, bottom = ROTATION[rotate]
        if portrait :
            if bottom :
                x = COLS - x
            shift = 7 - x % 8
            x //= 8
            offset = y
            if bottom :
                offset = ROWS - offset
            offset = offset * COLBYTES + x
        else:
            if not bottom :
                y = COLS - y
            shift = 7 - y % 8
            y //= 8
            offset = x
            if bottom :
                offset = ROWS - offset
            offset = offset * COLBYTES + y
        if offset >= len(self.buffer):
            return
        byte_b = self.buffer[offset]
        if color == 1:
            # Mask *out* a bit to set as black
            byte_b &= ~(0b1 << shift)
        if color == 0:
            # a bit to set as white
            byte_b |= (0b1 << shift)
        self.buffer[offset] = byte_b

    def draw_bin(self, filename):
        with open(filename, "rb") as f:
            f.readinto(self.buffer)

spi.init(baudrate=8000000, bits=8, mode=0)
# Create blank image for drawing.

# デモプログラム

# ここにコードを書いてね :-)
from microbit import *
from micropython import const
import time
import MemoDisp

COLS = const(144)
ROWS = const(168)
COLBYTES = const(COLS // 8)
# Colors
BLACK = const(0)
WHITE = const(255)

# Parameters to Change
WIDTH = 144
HEIGHT = 168
PORTRAIT = (HEIGHT > WIDTH)
BOTTOMUP = True
BORDER = 5
OFFSET_X = 4
OFFSET_Y = 4
TEXT_NORMAL = const(2)

MemoDisp.ROTATION[0] = (PORTRAIT, BOTTOMUP)
MemoDisp.ROTATION[1] = (not PORTRAIT, BOTTOMUP)
MemoDisp.ROTATION[2] = (PORTRAIT, not BOTTOMUP)
MemoDisp.ROTATION[3] = (not PORTRAIT, not BOTTOMUP)

def char_len(char, text_size=TEXT_NORMAL):
    if char in b"\"*+-0123<=>ABCDEFHKLOPQSUXZ[]^bcdefghjklnopqrsxz{":
        return 4 * text_size
    if char in b"!'.:i|":
        return 2 * text_size
    if char in b" (),;I`}":
        return 3 * text_size
    return 5 * text_size

def text_len(text, text_size=TEXT_NORMAL):
    return sum(char_len(c, text_size=text_size) + text_size for c in text)

def draw_image(icon, x, y, color=1, type="T", size=TEXT_NORMAL, rotate=0):
    cols = 5 * size
    rows = 5 * size
    for ox in range(cols):
        if x + ox < 0:
            continue
        if x + ox >= WIDTH:
            return False
        for oy in range(rows):
            if (not icon.get_pixel(ox // size,
                                   oy // size)) and type == "T":
                disp.set_pixel(ox + x + OFFSET_X,
                               oy + y + OFFSET_Y, color ^ 1, rotate=rotate)
                continue
            try:
                disp.set_pixel(ox + x + OFFSET_X,
                               oy + y + OFFSET_Y, color, rotate=rotate)
            except IndexError:
                pass
    return True

def write_text(text, x, y, color=1, text_size=TEXT_NORMAL, rotate=0):
    image = None
    for letter in text:
        image = None
        letter_width = char_len(letter, text_size=text_size)
        if x+letter_width >= WIDTH or ord(letter) == 13:
            y += text_size*5+2
            x = OFFSET_X
        if letter != " " and (x + letter_width) >= 1:
            if ord(letter) > 127:
                image = MemoDisp._icons[ord(letter) - 128]
            else:
                try:
                    image = Image(letter)
                except:
                    pass
        if image is not None:
            if not draw_image(image, x, y, color,
                              type="T", size=text_size, rotate=rotate):
                return
        if ord(letter) != 13:
            x += letter_width + text_size

    del image

# display = adafruit_sharpmemorydisplay.SharpMemoryDisplay(spi, scs, 96, 96)
disp = MemoDisp.SharpMemoryDisplay(spi, COLS, ROWS,
                          portrait=PORTRAIT, bottom=BOTTOMUP)

# Clear display.
disp.fill(1)
disp.show()
# Draw Some Text
text = "Hello World! Good morning."
write_text(text, 0, 5, rotate=0)
disp.draw_line(0, 5+OFFSET_Y + TEXT_NORMAL*5, text_len(text),
                  5+OFFSET_Y + TEXT_NORMAL*5, color=1)
disp.show(5, 35)
write_text(text, 0, 5, rotate=1)
disp.show(5, 35, rotate=1)
write_text(text, 0, 5, rotate=2)
disp.show(5, 35, rotate=2)
write_text(text, 0, 5, rotate=3)
disp.show(5, 35, rotate=3)
sleep(300)
disp.show(5, 35)
disp.fill(1, 5, 35)
sleep(500)
disp.show(5, 35)
write_text("Time = ", 0, 5)
start = time.ticks_ms()
while not button_a.is_pressed():
    past = time.ticks_diff(time.ticks_ms(), start)
    if past % 100 == 0:
        write_text(str(past // 100), TEXT_NORMAL*5*7, 5)
        disp.show(5, 35)
    if past > 800:
        start = time.ticks_ms()
# Display image
with open('Screen1.bin', "wb") as f:
    f.write(disp.buffer)
    
disp.fill(0)
disp.show()
sleep(1000)
disp.draw_bin('Screen1.bin')
disp.show()
# disp.clear()
カテゴリー: Micro:bit, お知らせ | コメントする

サイトのセキュリティ強化

e在京白堊会のサイトを念願の常時SSLに対応できるように、引っ越しと移植を
実施しました。Topページには、こっそり「47ML」へのリンクも貼っています。
ついでに、テーマのカストマイズで保守性を犠牲にしていた「子テーマ」設置と
MyFunctionとした私的関数の維持管理の知恵をメモしておきます。

1)子テーマの設置
  twentyten-child として次のstyle.css を設置(他のCSS値も置換できる)
/*
Theme Name: Twenty Ten Child
Theme URI: https://wordpress.org/themes/twentyten-child/
Description: The 2010 theme for WordPress is stylish, customizable, simple, and readable -- make it yours with a custom menu, header image, and background. Twenty Ten supports six widgetized areas (two in the sidebar, four in the footer) and featured images (thumbnails for gallery posts and custom header images for posts and pages). It includes stylesheets for print and the admin Visual Editor, special styles for posts in the "Asides" and "Gallery" categories, and has an optional one-column page template that removes the sidebar.
Author: the WordPress team
Author URI: https://wordpress.org/
Template: twentyten
Version: 1.0.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Tags: blog, two-columns, custom-header, custom-background, threaded-comments, sticky-post, translation-ready, microformats, rtl-language-support, editor-style, custom-menu, flexible-header, featured-images, footer-widgets, featured-image-header
Text Domain: twenty-ten-child
*/
2)MyFunctionのinclude方法   childのfunction.php には、次の記述を実施した。
add_action( 'wp_enqueue_scripts', 'theme_enqueue_styles' );
function theme_enqueue_styles() {
    wp_enqueue_style( 'parent-style', get_template_directory_uri() . '/style.css' );
    wp_enqueue_style( 'child-style', get_stylesheet_directory_uri() . '/style.css', array('parent-style'));
}
//ここから自由インクルード
function Include_my_php($params = array()) {
    extract(shortcode_atts(array(
        'file' => 'default'
    ), $params));
    ob_start();
    include(get_stylesheet_directory() ."/$file.php");
    return ob_get_clean();
}
add_shortcode('myphp', 'Include_my_php');
Include_my_php(array('file'=>'myFunction'));
//ここまで
これで、テーマ「twentyten」の更新があっても、全く影響が出ない。
カテゴリー: お知らせ | 3件のコメント

Raspberry Pi 4で スマスピ動作

(RaspbianOS 2020-02-05版では、Debian向けのAIYインストールを使って楽になったので、コメント4に投稿)

Raspberry Pi 4でAIY Voice Kit を動作させ、「ね~グーグル」の呼びかけができたので、
備忘録とする。RasPi3でも勿論動作する。
更に、14)のcheck_audio.pyを飛ばせば、AIY Voice Kit が無くても動作したので驚いた。Pulseaudioでマイク・スピーカーを切り替えることで自由に構築・運用ができる。
(下記原稿中、「–ダッシュ2個」の表現が全角文字置換されているので要注意)

【新規SDカードに書き込む場合】
1)MicroSDの初期化
  PCにてExplorerがすべて閉じた状態でディスク管理を開いて
  SDドライブのパーティションをすべてボリューム削除する
2)Win32DiskImager等でMicroSDに最新RaspbianOSを書き込む
  https://downloads.raspberrypi.org/raspbian_full_latest
  2019-09-26-raspbian-buster-full.img(Busterバージョン)
3)bootのconfig.txtに次の追記をする
  dtoverlay=googlevoicehat-soundcard
  また次をコメントアウトする
  #dtparam=audio=on
  なお、ミニLCDを使う場合は、次の追記も必要になることが多い。
  7Inch 1024×600だと、config.txtに次の追加を指示されている。
max_usb_current=1
hdmi_force_hotplug=1
config_hdmi_boost=7
hdmi_group=2
hdmi_mode=87
hdmi_cvt 1024 600 60 6 0 0 0
4)bootのトップにsshダミーファイルをおく

5)RasPiにMicroSDを入れ、電源をオンにして起動する
  (もしRasPi4だった場合は、まだgooglevoicehat-soundcardの
  ボードをドッキングさせずに電源を入れる)
6)RaspberryPiの設定誘導に対し、Password,Locale,Time zoneを適切に
  変更し、WiFiのPassKeyを設定する(スマホのGoogleツールで
  デバイス設定するとき、同一AP配下となる様に考慮)
  updateはここではskipする
7)PCからSSHツールにてraspberrypi.localに接続する
  SSHで時々の休止が気になるときは、次のコマンドで省エネを停止できる
  sudo iw dev wlan0 set power_save off
8)ダウンロードリストを拡張して、UPGRADEを実施する
  echo “deb https://dl.google.com/aiyprojects/deb stable main” | sudo tee /etc/apt/sources.list.d/aiyprojects.list
  wget -q -O – https://dl.google.com/linux/linux_signing_key.pub | sudo apt-key add –
  sudo apt-get update
  sudo apt-get -y upgrade
  sudo reboot する
  (RasPi4については、ここで画面出力を2Kに確定し、Shutdown
   してgooglevoicehat-soundcardのボードをドッキングさせる)

9)仮置きとしてAIY V2のインストールをする
  sudo apt install –fix-missing dkms
  sudo apt-get install -y aiy-voicebonnet-soundcard-dkms aiy-dkms
  処理中に–configureのエラーが発生するが、無視する:
   aiy-dkms
   aiy-voicebonnet-soundcard-dkms

10)AIYのadcとi2cの変更
  sudo cp /usr/src/aiy-1.1/aiy/iio/adc/aiy-adc.c /usr/src/aiy-1.1/aiy/iio/adc/aiy-adc.c.org
  sudo vi +138 /usr/src/aiy-1.1/aiy/iio/adc/aiy-adc.c
   該当1行の削除
  sudo cp /usr/src/aiy-1.1/aiy/mfd/aiy-io-i2c.c /usr/src/aiy-1.1/aiy/mfd/aiy-io-i2c.c.org
  sudo vi /usr/src/aiy-1.1/aiy/mfd/aiy-io-i2c.c
   2か所のi2c_lock_adapter(i2c->adapter);をi2c_lock_bus(i2c->adapter, I2C_LOCK_ROOT_ADAPTER);に変更
   2か所のi2c_unlock_adapter(i2c->adapter);をi2c_unlock_bus(i2c->adapter, I2C_LOCK_ROOT_ADAPTER);に変更
  インストールする
   sudo dkms install aiy/1.1
  sudo dkms remove aiy-voicebonnet-soundcard/1.0 –all
  sudo reboot する
11)Audioのインストール
  sudo apt-get update
  sudo apt-get install -y pulseaudio pavucontrol
  タイムアウトだったら、上手く行くまでinstallを再試行する。
  処理中のaiy-voicebonnet-soundcardに関するエラーは無視する。
   sudo mkdir /etc/pulse/daemon.conf.d/
  echo “default-sample-rate = 48000” | sudo tee /etc/pulse/daemon.conf.d/aiy.conf
  sudo apt-get install -y aiy-python-wheels
  処理中にlinux_armv6lと–configureのエラーが発生するが、無視する:
   aiy-python-wheels
   aiy-voicebonnet-soundcard-dkms

  また、VLCのHDMIからの音声出力を選択したいならば、
  #dtparam=audio=on
  のコメントを外し、カード番号を入れ替え、さらに次の
  定義を、/etc/asound.conf に追加する。
  <AIY VoiceKITのサウンドカードの人は、次のように設定>
options snd_rpi_googlevoicehat_soundcard index=0
pcm.softvol {
    type softvol
   slave.pcm dmix
        control {
        name Master
        card 0
    }
}
pcm.micboost {
    type route
    slave.pcm dsnoop
    ttable {
        0.0 30.0
        1.1 30.0
    }
}
pcm.!default {
    type asym
    playback.pcm “plug:softvol”
    capture.pcm “plug:micboost”
}
ctl.!default {
    type hw
    card 0
}
  <カード番号の入れ替え>/etc/modprobe.d/alsa-base.conf
  options snd slots=snd_rpi_googlevoicehat_soundcard,snd_bcm2835
  options snd_rpi_googlevoicehat_soundcard index=0
  options snd_bcm2835 index=1

12)protobufのインストール
  cd Downloads
  pip3 download protobuf
  pip3 install ./protobuf-3.11.2-py2.py3-none-any.whl
   (3.11.2の部分は、最新Vnoを使う)
  sudo vi +7 /var/lib/dpkg/info/aiy-python-wheels.postinst
   7-8行をコメントアウトする
  sudo dpkg –configure –force-overwrite –force-overwrite-dir -a
  処理中に–configureのエラーが発生するが、無視する:
   aiy-voicebonnet-soundcard-dkms
  sudo reboot する

13)実行準備
  git clone https://github.com/google/aiyprojects-raspbian.git AIY-projects-python
  sudo mv AIY-projects-python /opt/aiy/projects-python
  ln -s /opt/aiy/projects-python AIY-projects-python
  ln -s /home/pi/AIY-projects-python AIY-voice-kit-python
  sudo pip3 install -e AIY-projects-python

  THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS FILE.
   このエラーが出たとしても無視する。

  sudo cp /opt/aiy/projects-python/src/aiy/assistant/auth_helpers.py \
                  /opt/aiy/projects-python/src/aiy/assistant/auth_helpers.py.org
  sudo vi +75 /opt/aiy/projects-python/src/aiy/assistant/auth_helpers.py
   この行末カッコ内の最後のパラメタ’,-1’を削除する
  pip3 install google-assistant-library==1.0.0
#  (Segmentation Fault防止のため、1.0.1を推奨するメッセージを
   無視して1.0.0をPre設置)
  pip3 install google-assistant-library
  pip3 install google-auth-oauthlib
  sudo pip3 install grpcio
  AIYプロジェクト内の日本語対応が不完全なところを修正する。
   vi +214 /home/pi/.local/lib/python3.7/site-packages/google/assistant/library/assistant.py
   の.encode(‘ASCII’) を.encode(‘utf-8’) にする。
  AIYボードの初期化のために、命令を追加する。
   vi +284 /home/pi/AIY-voice-kit-python/src/aiy/board.py
   に、GPIO.setwarnings(False) を行追加する。
14)次の確認を実施する
  amixer sset Master 50% で、音量を半分にしておく
  export PYTHONPATH=”/home/pi/AIY-voice-kit-python/src”
  /home/pi/AIY-voice-kit-python/checkpoints/check_audio.py

15)次のURLに基づき、アカウント登録をする
  https://tech.nikkeibp.co.jp/atcl/nxt/column/18/00255/042600011/?P=4
  assistant.json ファイルを /home/piに置く
16)サンプルコードの実行
  export PYTHONPATH=”/home/pi/AIY-voice-kit-python/src”
$PYTHONPATH/examples/voice/assistant_library_with_button_demo.py
   初回のスクリプト実行時にURLが表示され、ブラウザでアクセスする
  ことで認証文字列が返される。
  それをスクリプト実行中の質問に貼り付ける。
17)デバイスの登録
  サンプルコードの実行でしばらく放置し、スマホのHomeアプリの設定・詳細設定の
  「アシスタント」に出現した新たなデバイス(Voice Kit)の言語を
  日本語に設定し、属性参照を許可する。

以下は、SmartTV(PX-W3U4,PX-Q3U4使用)に変身させるときの追加作業
18)TVチューナーサポートシステムのインストール
  curl –silent https://mori1-hakua.tokyo/test/TVget.sh | sh

19)N2TTS,youtube-dl,mojimojiのインストール
  このURLに従う:https://support.kddi-research.jp/n2/service.html
  (wget -O n2-linux-foc.tgz https://support.kddi-research.jp/n2/download.php?type=5)
  sudo -H pip install youtube-dl
  pip3 install mojimoji
  pip3 install –upgrade google-api-python-client

【RasPi4に対応させ、multiTV.shから aiyTV.shを用意】
  MPEG2に対するプレーヤーとして、OMXからVLCメディアプレーヤに
  切り替えるため、
  source ~/.biling
  if [ “$BILING” = “yes” ]; then
   MPG2 =`vcgencmd codec_enabled MPG2`
   if [ “$MPG2” = “MPG2 disabled” ]; then
   BILING=sel
   fi
  fi
  とし、
  elif [ “$BILING” = “sel” ]; then
   (recdvb –dev ${DEV} –b25 –strip –http 8080 ${LCH}; exit) &
   (sleep 2) &
   cvlc -f –no-video-title-show http://localhost:8080/${CH}/
  fi
  と、プレーヤーを取り換える。
  VLCはマルチスレッドではブロックノイズが出やすいため、スレッドを
  シングルに切り替える。
  <sayJ関数の追加>
  vi $PYTHONPATH/aiy/voice/tts.py
<pre>
def sayJ(text, asynch=0, lang=’ja-JP’, volume=60, pitch=130, speed=100, device=’sysdefault:CARD=ALSA’):

    logging.info(text)
    with tempfile.NamedTemporaryFile(suffix='.wav', dir=RUN_DIR) as f:
       cmd = 'n2tts -p VOLUME=%s -o %s "%s" && aplay -q -D %s %s' % \
             (volume, f.name, text, device, f.name)
       if asynch==0: subprocess.check_call(cmd, shell=True)
       else: subprocess.Popen(cmd, shell=True)
</pre>

以上

カテゴリー: RaspberryPi, お知らせ | 5件のコメント

コマンドプロンプトからファイル数


Windowsのコマンドプロンプトから、 フォルダ(ディレクトリ)配下の全ファイル数、全フォルダ数を取得するコマンドのメモ

——————–

ファイル数

dir /A-D /S /B | find /c /v “”

——————–

フォルダ数

dir /AD /S /B | find /c /v “”

——————–

dir /A-D は、ディレクトリ以外

dir /AD は、ディレクトリのみ

dir /S /B は、サブフォルダも含めて、配下のファイル名/フォルダ名のみ

出力

find /c /v “” は、行数を出力

カテゴリー: お知らせ | コメントする

2019年もよろしく

カテゴリー: お知らせ | コメントする

AIY Voice KIT にAlexaとGoogleAssistantを同居

3月26日のOSアップグレードで、少しインタフェースが変わったため、確実な同居方法を
メモした。また、04-13版のレベルダウンへも対応追記。

1.AIYプロジェクトのVoice Kit SD imageをダウンロード
 aiyprojects-2018-04-13.img.xz
 https://dl.google.com/dl/aiyprojects/aiyprojects-latest.img.xz
2.MicroSDに書き込み、インストール
 aiyprojects-2018-04-13.img.xzを解凍し、書き込みする
 参照:https://aiyprojects.withgoogle.com/voice/#assembly-guide-5-2–boot-the-device
2.1 Audio音量関数の修正
 2018-04-13.imgにはレベルダウンがあり、AIY-project*/src/aiy/audio.py を修正する。
 113行 db_range = -60.0 – (-60.0 * (volume / 100.0)) を
     db_range = -6.6 – (-6.6 * (volume / 100.0)) に書き換え。
3.AIYでの日本語動作確認
 PulseAudioの初期値が未設定なので、/etc/pulse/default.pa を編集します。
 バックエンドドライバーをロードする行を探してアンコメント(#削除)し、
 以下のように device パラメータを追加してください。
 さらに autodetect モジュールをロードする行をコメントアウトしてください。
 load-module module-alsa-sink device=dmix
 load-module module-alsa-source device=dsnoop
 # load-module module-udev-detect
 # load-module module-detect
 再起動
 amixer sset Master 50%  (初期音量を変更したい)
 参照:https://kureuetan.com/web/raspberrypi/4998/#OS
 ~/bin/AIY-projects-shell.sh
 src/examples/voice/assistant_grpc_demo.py
 この後、GoogleAssistantアプリで、デバイスVoiceKitの言語選択を日本語に設定してください。
4.RasPi用Snowboyのインストール
 参照:https://github.com/wanleg/snowboyPi
4.1 事前準備
 sudo apt update && sudo apt -y upgrade && sudo apt-get -y auto-remove && sudo reboot
 OSのバージョンは、3月末で、次のようになります。
  Linux raspberrypi 4.14.30-v7+ #1102 SMP Mon Mar 26 16:45:49 BST 2018 armv7l GNU/Linux
 sudo apt -y install python-pyaudio python3-pyaudio sox python3-pip python-pip libatlas-base-dev
 sudo pip3 install pyaudio
 sudo cp ~/.asoundrc /root/
4.2 Snowboyの準備
 wget https://s3-us-west-2.amazonaws.com/snowboy/snowboy-releases/rpi-arm-raspbian-8.0-1.1.1.tar.bz2
tar xvf rpi-arm-raspbian-8.0-1.1.1.tar.bz2
mv rpi-arm-raspbian-8.0-1.1.1 snowboy
4.3 サウンドテスト
  speaker-test -c 2
  arecord -d 3 test.wav
  aplay test.wav
4.4 Hotwordの作成
 pip install requests
 cd snowboy
 wget https://github.com/wanleg/snowboyPi/raw/master/training_service.py
https://snowboy.kitt.ai にログインし、Profile settings をクリック、
 作成された API token をコピーしてメモする。
 training_service.pyの次のパラメタを設定する
 ############# MODIFY THE FOLLOWING #############
 token = “コピーしてメモしたAPI token”
 hotword_name = “ホットワードの名前”
 language = “jp”
 age_group = “30_39”
 gender = “M”
 microphone = “usb microphone”
 ############### END OF MODIFY ##################

 rec -r 16000 -c 1 -b 16 -e signed-integer 1.wav
 rec -r 16000 -c 1 -b 16 -e signed-integer 2.wav
 rec -r 16000 -c 1 -b 16 -e signed-integer 3.wav
 python training_service.py 1.wav 2.wav 3.wav NeGoogle.pmdl
 cp NeGoogle.pmdl resources/NeGoogle.pmdl
4.5 Hotwordのテスト
 python3 demo.py ~/snowboy/resources/NeGoogle.pmdl

 startAlexa.sh,assistant_grpc_snow_demo.pyのダウンロードと走行確認
 wget -O startAlexa.sh https://mori1-hakua.tokyo/test/startAlexa.txt
 wget -O _snowboydetect.so https://mori1-hakua.tokyo/test/_snowboydetect.so
 wget -O assistant_grpc_snow_demo.py https://mori1-hakua.tokyo/test/snow_demo.txt
 python3 assistant_grpc_snow_demo.py

5. Alexaのインストール
 参照:https://github.com/alexa/avs-device-sdk/wiki/Raspberry-Pi-Quick-Start-Guide-with-Script

cd
    wget https://raw.githubusercontent.com/alexa/avs-device-sdk/master/tools/Install/setup.sh
    wget https://raw.githubusercontent.com/alexa/avs-device-sdk/master/tools/Install/config.txt
    wget https://raw.githubusercontent.com/alexa/avs-device-sdk/master/tools/Install/pi.sh
    vi setup.sh で次の変更を実施
       en-US を ja-JP
    vi config.txtで次の設定を実施
       Client ID, Client Secret, and Product IDの設定
   vi avs-device-sdk/build/BuildDefaults.cmake で include(KeywordDetector) をコメント化
  
   sudo bash setup.sh config.txt
    sudo bash startauth.sh の起動後、http://localhost:3000をアクセス
    sudo cp ~/.asoundrc /root/
  sudo bash startsample.sh を実行し、c、1、6と入力して日本語モードにする

6. AlexaとGoogleAssistantの同時実行
  cd ~/snowboy
  python3 assistant_grpc_snow_demo.py NeGoogle.pmdl
  この他、
  python3 assistant_grpc_snow_demo.py snowboy.umdl も試せます。

カテゴリー: RaspberryPi, お知らせ | 4件のコメント

岩手日報webnews、大幅改装で追随大変!

//      $body = mb_convert_encoding ($response['body'],"utf-8","Shift_JIS");
      $body = $response['body'];
    }
    $pos = 10000;
    $table = ""; // mb_substr($body,$pos,$pos2-$pos);
	$pos = mb_strpos($body,$from,$pos);
	 if ($pos === false) { return($table.$body); }
	$pos2 = mb_strpos($body,$to,$pos+30);
	 if ($pos2 === false) print "<br>strpos2がfalseを返しました。<br>";
	if (substr($ton,0,1)=="+") {
		$pos2 += mb_strlen($to);
		if (strlen($ton)>1) $pos2 += substr($ton,1);
	}
	else $pos2 += $ton;
    $body1 = mb_substr($body,$pos,$pos2-$pos);
    if ($url=="") return ($body1);
    return (div_cut($body1));
}
function div_cut($str) {
    global $time;
	if ($str=="") return "";
	$pos = strpos($str,'<article>',0);
	if ($pos === false) return "";
	$pos2 = strpos($str,'<div class="outer">',$pos);
	if ($pos2 === false) return $str;
	$pos3 = strpos($str,'</h1>',$pos2);
	$time1 = substr($str,$pos3+24,19);
	if (strcmp($time,$time1)<0) $time = $time1;
	return str_replace("<a href=","<a target='_NEW' href=",substr($str,$pos,$pos2-$pos))."&nbsp;".
        substr($str,$pos2+36,$pos3-$pos2-36)."</a></article>".div_cut(substr($str,$pos3));  
// <div class="outer"><dl><dt><div><h1>

カテゴリー: お知らせ | コメントする