「技術」カテゴリーアーカイブ

赤外線LED、レシーバを購入しました。

右が赤外線LED、左側が赤外線受信機です。

梅沢無線で買ってきました。

この二つがあれば、赤外線通信ができるはずです。

はい、今度は赤外線をやってみたいと思います。

目指すところは、テレビのリモコンの赤外線を受信機でトレースし、その信号を再現してテレビを操作しちゃおうと考えています。

で、まずは赤外線LED(信号送信側)を試してみようと思うのですが、

例によって、「抵抗は必要なのか?」という疑問が出てきます。

はい、過去に発光ダイオードを抵抗なしで電圧かけたことによって、発光ダイオードを破壊したことがあります。

初心者あるあるですよね??

秋月電子のオンラインショップのページにデータシートなどが掲載されているので、これを確認すると、

https://akizukidenshi.com/catalog/g/gI-03261/

やはり抵抗が必要なようです。

では、何Ωの抵抗が必要なのか。

計算式は、

(V - VF) ÷ IF = Ω

データシートからこの公式に当てはめると、

(5 - 1,6) ÷ 0.1 = 34Ω

手持ちにある20Ωの抵抗を1~2個使えば大体近い値になりそうです。

で、回路を組んでみた。

電圧をかけてみる。

抵抗2個の場合。

抵抗1個の場合。

肉眼では分かりませんが、スマホのカメラを通してみてみると、赤外線LEDの先っちょが赤く光っているのが分かると思います。

写真では1個と2個で違いが分かりませんが、実際にスマホのカメラのプレビュー画面を見てみると、1個の方が光が強いように見えます。

今回は入力を5V一定にしましたが、これをプログラマブルなパルス信号にすると、リモコンの赤外線通信を再現できると思います。

【ダイエット支援】【入力履歴機能】履歴データ処理の作成

前回作成した履歴一覧画面からデータテンプレートへ移動する機能を作成していきます。

<template>
    <div>
        <div>
            <p id="navi"> <a href="/home">HOME</a></p>
            <p id="inputbutton">
                <button @click="onClickSubmit">選択したデータを登録</button>
            </p>
            <table class="eatinghistory">
                <tbody>
                    <tr>
                        <th class="check">
                            <input type="checkbox" v-model="all" @click="onAllCheck" />
                        </th>
                        <th class="date">日時</th>
                        <th class="item">アイテム</th>
                        <th class="protein">タンパク質</th>
                        <th class="liqid">脂質</th>
                        <th class="carbo">炭水化物</th>
                        <th class="calorie">カロリー</th>
                    </tr>
                    <tr v-for="data in datalists">
                        <td class="check">
                            <input type="checkbox" v-model="data.check" />
                        </td>
                        <td class="date">{{ data.date}}</td>
                        <td class="item">{{ data.item}}</td>
                        <td class="protein">{{ data.protein}}</td>
                        <td class="liqid">{{ data.liqid}}</td>
                        <td class="carbo">{{ data.carbo}}</td>
                        <td class="calorie">{{ data.calorie}}</td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>
</template>

チェックボックスの処理と処理を行うボタンを配置しました。

リストのチェックボックスはリストデータとバインドさせています。

チェックした内容がそのままデータに反映されます。

        onClickSubmit: function() {
            var self = this;
            this.datalists.forEach(element => {
                if(element.check == true){
                    this.ids.push(element.id);
                }
            });
            this.param.contents = this.ids;
            axios.post('/api/eating/regist', this.param).then(function(response){
                self.updateList();
            }).catch(function(error){
            });
        },
        onAllCheck: function() {
            if(this.all == false) {
                this.datalists.forEach(element => {
                    element.check = true;
                });
            }else{
                this.datalists.forEach(element => {
                    element.check = false;
                });
            }
        }

ヘッダのチェックをクリックすると、リストの中の全項目にチェックを行うように処理しています。

そして、「選択したデータを登録」をクリックすると、チェックをつけたidのリストがバックエンド側に送信されます。

Route::post('api/eating/regist', 'Eating\ApiController@regist');
class ApiController extends Controller
{
    public function regist(Request $request)
    {
        $this->eatingManagement->registTemplate($request->contents);
        return response()->json();
    }
class EatingManagementRepository
{
    public function registTemplate($ids)
    {
        $records =EatingHistoryItem::whereIn('id', $ids )->get();
        foreach($records as $record)
        {
            $model = new EatingTemplateItem();
            foreach($this->templateParamNames as $name)
            {
                $model->$name = $record[$name];
            }
            $model->save();
            $record->delete();
        }
    }

idのリストを元にhistoryのデータをtemplateに移動させています。

この画面はまだまだ改良の余地がありますが、とりあえずこんな感じでいいでしょう。

次回はテンプレートから入力候補を検索する処理を作成していきます。

【Alexa】次のバスの時刻を教えてくれる。バス通勤とかに便利。

このスキルが意外と便利だったりする。

使い方は簡単。

Alexaアプリで、よく使うバス停(乗るバス停と降りるバス停)を登録するだけ。

設定が終わったら「アレクサ、次のバスは?」と話しかけるだけ。

そうすると、次のバスが何分後の何時何分に来るか、その次のバスは何分後か、というのを教えてくれます。

これ、自宅の近所、よく使うバス停と、降りるバス停を登録しておくと、家を出るタイミングが分かるので、非常に便利なんです。

【COCOS2D-X】アイコン画像をピッチリ並べる

とりあえず、アイコンをピッチリ並べてみました。

ポイントは、座標や拡大サイズを全て計算で算出すること。

こうしないと、機種が変わったときに、確実にレイアウトが崩れます。

    float buttonScale = visibleSize.height / (visibleSize.height / 4.0);
    float buttonBase = 0.0;
    auto homeButton = Sprite::create("btnHome.png");
    if (homeButton == nullptr)
    {
        problemLoading("'btnHome.png'");
    }
    else
    {
        homeButton->setPosition(Vec2(sprite->getPosition().x + sprite->getContentSize().width * scaleRate / 2 + origin.x, visibleSize.height + origin.y));
        homeButton->setAnchorPoint(Vec2(1.0,1.0));
        homeButton->setScale(buttonScale);
        buttonBase = visibleSize.height - homeButton->getContentSize().height * buttonScale;
        this->addChild(homeButton, 1);
    }

    auto charaButton = Sprite::create("btnChara.png");
    if (charaButton == nullptr)
    {
        problemLoading("'btnChara.png'");
    }
    else
    {
        charaButton->setPosition(Vec2(sprite->getPosition().x + sprite->getContentSize().width * scaleRate / 2 + origin.x,
                                      buttonBase + origin.y));
        charaButton->setAnchorPoint(Vec2(1.0,1.0));
        charaButton->setScale(buttonScale);
        buttonBase -= charaButton->getContentSize().height * buttonScale;
        this->addChild(charaButton, 1);
    }

    auto equipButton = Sprite::create("btnEquip.png");
    if (equipButton == nullptr)
    {
        problemLoading("'btnEquip.png'");
    }
    else
    {
        equipButton->setPosition(Vec2(sprite->getPosition().x + sprite->getContentSize().width * scaleRate / 2 + origin.x,
                                      buttonBase + origin.y));
        equipButton->setAnchorPoint(Vec2(1.0,1.0));
        equipButton->setScale(buttonScale);
        buttonBase -= equipButton->getContentSize().height * buttonScale;
        this->addChild(equipButton, 1);
    }

    auto questButton = Sprite::create("btnQuest.png");
    if (questButton == nullptr)
    {
        problemLoading("'btnQuest.png'");
    }
    else
    {
        auto scale = buttonBase / questButton->getContentSize().height;
        questButton->setPosition(Vec2(sprite->getPosition().x + sprite->getContentSize().width * scaleRate / 2 + origin.x,
                                      buttonBase + origin.y));
        questButton->setAnchorPoint(Vec2(1.0,1.0));
        questButton->setScale(scale);

        this->addChild(questButton, 1);
    }

例えば、「キャラ」のアイコンは「ホーム」のアイコンの下に並ぶように座標を計算して配置していますし、

その下の「装備」も「キャラ」の下に並ぶように座標を計算で算出しています。

「クエスト」のボタンは、上の3つのアイコンを並べた空きスペースにピッチリ収まるように、拡大率を算出して配置しています。

アイコンの拡大率も計算で算出しているので、機種や解像度が変化しても、アイコンの大きさが変わる程度で、大きくレイアウトは崩れないと思います。

思った以上に良い感じです。

ラズパイ 400(Raspberry Pi 400)が普段使いできるPCになるわけないだろう。

自分、ラズパイ4を使用しているが、この記事には唖然とした。

そりゃ、サイトとしてはラズパイを持ち上げざるを得ないかもしれないけどさぁ。

そもそも、CPUは他のPCと比べて遙かに劣っている。

ラズパイで動作しているOSやアプリケーションはラズパイ用に最適化・軽量化しているので、そんなマシンでPCが使用しているようなアプリがまともに動くわけがない。

Webツールも然りである。ブラウザ自体が軽量化されているので、まともにJSが動く保証はない。

それでもラズパイ4でだいぶマシになった方だけれども。

ただ、ラズパイ4で電子工作を行う場合としては、遙かに魅力的なマシンである事には間違いない。

VPSをHTTP2に対応させてみた。

簡単にできるんだね。

こちらのサイトを参考にしました。

http://www.dcom-web.co.jp/lab/web-server/nginx_with_http2

nginxの設定でlistenにhttp2と書き足すだけで良いらしい。

Protocolがh2になっていれば、HTTP2を使用しています。

HTTP2で何が変わるのか?

従来のHTTP1.1では、1リクエストに対して必ず1レスポンスを返す必要があります。

1ページの中に複数のコンテンツ(htmlとかjsとかcssとか)が合った場合、これらのファイルを一つずつダウンロードする必要がありました。

しかし、HTTP2では、多リクエスト、多レスポンスが可能になります。

これはどういうことかというと、送信中のリクエストの応答を待たずして次のリクエストを出せるのですね。

なので、複数のファイルを平行してダウンロード出来るようになります。

なので、その分ページの読み込みが早くなります。

今のブラウザはほとんどHTTP2に対応しているので、あとはサーバ側の設定を変えればHTTP2での通信になります。

あ、それと、HTTP2はデフォルトSSLによる暗号化通信なので、サーバ側に証明書が必要になりますよ。

HTTP2に関する小話

HTTP2は元々Googleによって開発された通信プロトコルで、後に正式にHTTP2の規格に採用されました。

TCPより上位のプロトコルなので、簡単に双方向の通信を行うことができます。

おそらく、最近のスマホゲームのマルチプレイなんかは、この技術が使われていると思われます。

それ以前は、一つ下位のプロトコルである、TCPで通信していたと思われます。

でも、TCPって思った以上に扱いが難しんですよね。

【北海道大戦】確認ダイアログ追加とバグ修正

https://github.com/takishita2nd/HokkaidoWar

最初のプレイヤーの都市選択で確認ダイアログを出すようにしました。

あとは、最後までプレイできることも確認しました。

ただ、戦力差がありすぎると、バトルがワンパンで決着が付いてしまうのが、ちょっとよろしくないですね。

【ラズパイ】【カメラ】クライアントを閉じたら動画撮影を終了する

前回のままだと、クライアント側(ブラウザ)を撮影中に閉じてしまうと、動画撮影を終了する人がいなくなってしまいます。

これを防ぐためには、クライアントが生存していることを常に確認する処理が必要になります。

まぁ、今回はプレビュー画面で常にデータのやりとりを行っているので、これを利用しましょう。

    def do_GET(self):
        parsed = urlparse(self.path)
        if parsed.path == '/Streaming':
            global lasttime
            lasttime = time.time()

            enc = sys.getfilesystemencoding()

プレビュー画をリクエストがあったら、その時間を記憶しておきます。

def videoCapture():
    global capture
    global out

    while capture:
        nowtime = time.time()
        if nowtime - lasttime > 10:
            capture = False
            out.release()
            out = None
            break
        _, img = cap.read()
        out.write(img)

ビデオキャプチャーの周期処理の中で、現在時刻と、プレビュー画要求時の時刻を比較します。

周期処理の時刻がキャプチャー時の時刻より10秒経過していたら撮影を終了します。

ブラウザを撮影途中で閉じた場合、プレビュー画要求時の時刻が更新されなくなりますので、こうすることで、ブラウザを閉じてから10秒後に撮影は終了します。

さて、カメラでやりたいことが終わってしまった・・・

次何しようかな。

【ダイエット支援】【入力履歴機能】履歴管理画面の作成

特に特筆することはやっていないので、進捗報告だけ。

https://github.com/takishita2nd/diet-mng

とりあえず画面の表示だけ。

全チェック処理とか、テンプレートに移す処理とか、データを削除する処理とかは次回やります。

あと、管理者アカウントを別に作って、他の人がこのページにアクセスできないようにする必要もありますね。

【COCOS2D-X】アイコン画像を配置する。

画像を配置するのは簡単なんですが、

その配置位置を調整するのがめちゃくちゃ大変だったりします。

    auto Button = Sprite::create("btnChara.png");
    if (Button == nullptr)
    {
        problemLoading("'btnChara.png'");
    }
    else
    {
        Button->setPosition(Vec2(sprite->getPosition().x + sprite->getContentSize().width * scaleRate / 2 + origin.x, visibleSize.height + origin.y));
        Button->setAnchorPoint(Vec2(1.0,1.0));
        Button->setScale(3.0);
        this->addChild(Button, 1);
    }

まず、setAnchorPoint()についてですが、

これは画像位置の基準となるポイントを設定する関数ですね。

デフォルトでは、アンカーポイントは中心(0.5, 0.5)の位置にあり、これを左下にするには(0, 0)、右上にするには(1, 1)と設定します。

今回は画像の右上を、背景の右上に合わせたいので、(1.0 , 1.0)、すなわち、画像のアンカーポイントを右上に設定しています。

次に背景画像の右上の座標を調べる必要があるのですが、

getContentSize()でspriteのサイズがわかりますが、

これはsetScale()で拡大する前の値になっていました。

なので、getContentSize()の値に拡大率を計算式に入れることで、見事に位置が合いました。

あとは、ちょうど良い感じで画像の大きさを調整。

もう少し大きくしても良いかな?

用意したアイコンを全部配置して、バランスを取ってみたいと思います。