20210511のNode.jsに関する記事は4件です。

プログラミング初心者向け!トイドローン「Tello」をScratchで飛ばす

仕事でTelloを使って職場を撮影するというミッションを与えられたので、先ずはプログラム制御できるようにScratchと繋いでみました。途中ちょっとつまずいたので備忘録がてら記事にしていきます。 Telloとは 中国のスタートアップ企業Ryze Techが開発・販売しているトイドローンです。 価格の割に性能がよく、ホバリングや姿勢制御などある程度のことは自動でやってくれる上に軽くてカメラの性能も結構良い感じです。 こんな見た目です。 Tello公式ホームページ また、Telloには専用のSDKが用意されており、PythonやScratchなどで制御することができます。 今回は初心者でも簡単にプログラミングができるScratchを使ってTelloを動かしてみました。 手順 Telloの公式HPからScratchの導入方法を見ると以下のように書かれています。 Tello Scratch README 1. Visit https://scratch.mit.edu/download and follow the instructions to install the Scratch 2.0 Offline Editor. 2. Download and install node.js from https://nodejs.org/en/. 3. Click here to download Tello.js and Tello.s2e, open the terminal, go to the file directory where you saved the previous files, and type "node Tello.js" 4. Open Scratch 2.0, hold the “Shift” key, click the “File” menu, click "Import Experimental HTTP Extension," and select "Tello.s2e" file in the file directory. 5. The Tello interface will be shown in Scratch under "More Blocks.” 順番に見ていきましょう。 ①Scratch2.0(オフライン用)のインストール 先ずはScratchの導入からです。ただ、Scratchなら何でも良い訳ではなく。 ■オフラインで動くもの ■Tello用の拡張モジュールを追加できるもの を入れておく必要があります。これが「Scratch2.0(オフライン用)」です。 以下のリンクからダウンロードできます。 Scratch2.0(オフライン用)のダウンロードページ ダウンロードページに行くと、最初にAdobeAIRを導入しておくように促されますが、私の環境(Windows10)だとScratch2.0をインストールしたらAdobeAIRも一緒にインストールされました。 (というか、先にAdobeAIRの最新版を入れたらScratch2.0のインストールができませんでした。。。) ②Node.jsの導入 次にNode.jsを導入します。これは次の手順でダウンロードするプログラムを動かすのに必要になります。 ダウンロードは以下からできます。 Node.jsダウンロードページ 特にこだわりが無ければ推奨版を入れておけば大丈夫だと思います。 (ちなみに筆者の環境は15.12.0です。) ③Tello用ファイルのダウンロード 公式が配布している制御用プログラムとScratchの拡張モジュールをダウンロードします。 ダウンロードリンクは以下です。 モジュールダウンロード ※リンク切れの場合は公式のREADME本文からダウンロードしてください。 ダウンロードしたモジュールは7z形式で圧縮されているので、デスクトップなど適当な場所に解凍しましょう。 解凍すると中にファイルが3つあります。 ・Tello.js   Scratchで書いた命令をTelloに伝える役割を果たすプログラムです。Node.js環境で動作させます。 ・Tello.s2e   Scratch2.0にTello制御用のブロックを追加します。 ・TelloChs.s2e   Tello.s2eの中国語版です。今回は使用しません。 ④ScratchにTello用のブロックを追加 先ほどインストールしたScratchを立ち上げましょう。 以下の様な画面が開くと思います。 開いたら左上にある地球儀のようなマークを押して言語を「日本語」に変えましょう。 次に、Shiftキーを押しながらファイルを押してみてください。 画像のようなメニューが表示されるので「実践的なHTTP拡張を読み込み」を選択してください。 ファイルを選択するダイアログが表示されるので③でダウンロードした「Tello.s2e」を選択しましょう。 拡張機能が追加されて「その他」にTello用のブロックが表示されます。 これらのブロックを組み合わせてTelloを操作していきます。 主なブロックの使い方を表にしました。 ブロック 概要 備考 takeoff 離陸します land 着陸します fly up x cm x cm 上昇します xは20~500の範囲で指定可能 fly down x cm x cm 下降します xは20~500の範囲で指定可能 fly left x cm x cm 左へ移動します xは20~500の範囲で指定可能 fly right x cm x cm 右へ移動します xは20~500の範囲で指定可能 fly forward x cm x cm 前へ移動します xは20~500の範囲で指定可能 fly backward x cm x cm 後ろへ移動します xは20~500の範囲で指定可能 rotate x degree clockwise x度分 時計回りに回転します xは1~3600の範囲で指定可能 rotate x degree counter clockwise x度分 反時計回りに回転します xは1~3600の範囲で指定可能 flip x 縦方向に宙返りします。 xの指定で方向が変わります。l(左)、r(右)、f(前)、b(後)、bl(後左)、br(後右)、fl(前左)、fr(前右) set speed to x cm/s 移動速度を x cm/sに設定します。 xは1~100の範囲で指定可能 ⑤Telloに制御を伝えるためのプログラムを起動 Scratch側の準備が整ったら実際に動かす準備に入ります。 先ず、コマンドプロンプトを起動してください。 Windowsキー+Rで「ファイルを指定して実行」の画面を立ち上げ、cmdと入力してエンターキーを押すと立ち上がります。 コマンドプロンプトが立ち上がったら先ほどファイルを解凍した場所まで移動しましょう。 コマンドプロンプトで cd [移動先のファイルパス] と入力すると移動できます。 上記の方法でコマンドプロンプトを立ち上げると自分のユーザーフォルダ直下に居ると思いますので、 C:¥Users¥[自身のユーザー名]>cd "Desktop\Scratch_For Tello\Scratch_普通版" と実行すると解凍先に移動できると思います。 ※デスクトップ以外の場所で回答した人はその場所のパスを入力するか、「Scratch For Tello」フォルダをデスクトップに移動してから実行してみてください。 次に、node [ファイル名]でプログラムを実行します。 C:¥Users¥[自身のユーザー名]¥Desktop¥Scratch_For Tello¥Scratch_普通版>node Tello.js と実行するとTello.jsファイルに記載されているプログラムが実行されます。 ここで、次のようなエラーが出た方は少し別の手順を踏む必要があります。 (私はここで大分つまづきました・・・) node:events:346 throw er; // Unhandled 'error' event ^ Error [ERR_STREAM_WRITE_AFTER_END]: write after end at new NodeError (node:internal/errors:329:5) at ServerResponse.end (node:_http_outgoing:826:15) at Server.<anonymous> (C:\Users\伊藤翔\Desktop\Scratch_For Tello\Scratch_普通版\Tello.js:168:11) at Server.emit (node:events:369:20) at parserOnIncoming (node:_http_server:933:12) at HTTPParser.parserOnHeadersComplete (node:_http_common:129:17) Emitted 'error' event on ServerResponse instance at: at emitErrorNt (node:_http_outgoing:706:9) at processTicksAndRejections (node:internal/process/task_queues:82:21) { code: 'ERR_STREAM_WRITE_AFTER_END' } ※エラーが出た方は以下の折り畳みを開いて中を確認してください。 エラー解消方法 エラー内容に表示されているERR_STREAM_WRITE_AFTER_ENDですが、 これは既に閉じられたストリームに書き込みを使用としてエラーになっていることを示しています。 また、このエラーが何処で出ているのかを追っていくと、以下の関数にたどり着きます。 http.createServer(function (request, response) { let url_params = request.url.split('/'); if (url_params.length < 2) { response.end('Hello Tello.\n'); return; } let command = url_params[1]; if(command=='poll') { let rst = ''; for(let k in osdData) { rst += `${k} ${osdData[k]}\n`; } response.end(rst); } else if(command=='takeoff') { sendCmd('command'); sendCmd('takeoff'); } else { let cmd = url_params.slice(1).join(' '); console.log('[lhp_debug]request.url.split: %s\n', cmd); sendCmd(cmd); } response.end('Hello Tello.\n'); }).listen(8001); このプログラムの下から2行目の response.end('Hello Tello.\n'); でエラーが出ていることが分かります。 これはプログラムの分岐によってresponse.end()が2回呼ばれているのが原因っぽいので、 以下のように修正してあげます。(コピーして関数ごと上書きで大丈夫です。) http.createServer(function (request, response) { let url_params = request.url.split('/'); if (url_params.length < 2) { response.end('Hello Tello.\n'); return; } let command = url_params[1]; if(command=='poll') { let rst = ''; for(let k in osdData) { rst += `${k} ${osdData[k]}\n`; } response.end(rst); } else if(command=='takeoff') { sendCmd('command'); sendCmd('takeoff'); } else { let cmd = url_params.slice(1).join(' '); console.log('[lhp_debug]request.url.split: %s\n', cmd); sendCmd(cmd); response.end('Hello Tello.\n'); } }).listen(8001); とりあえず、私はこれで元気に動いています。 ※単純に行を消すだけだと、離陸以外のコマンドを指示した後に、結果が戻って来ず、次のコマンドを実行できない状態になります。 ⑥PCとTelloを接続 もう少しです。Scratchで作成したプログラムをTelloに転送するために、PCとTelloを接続する必要があります。 Telloの電源を入れると、PCからWifiネットワークが見つけられますので、接続しましょう。 ⑦Scratchでプログラムを開始 PCとTelloが接続できたらScratchで組んだプログラムを実行してみましょう。 上手くいけばTelloがプログラム通りに動くはずです。 動かない場合はコマンドプロンプト上にエラーが出ていないか確認してみてください。 終わりに 長文になってしまいましたが、ScratchでTelloを動かす方法を書いてみました。 次回はTelloで撮影した画像をPC上に表示する方法を書きたいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DOMやwindowに依存しているPrismのプラグインをNode.js上で動かす方法

Prism.jsのline-numbersプラグインなどは、ブラウザ上での動作を前提とした設計でDOMやwindowに依存しているため、Node.jsのようなサーバーサイドでrequireしても動作しません。 解決策 ではどうやったら動くか?解決策は次の通りです。 DOMに依存している問題の解決策 DOMに依存しているコードが動くようにするために、jsdomを使います。 グローバルオブジェクトwindowに依存している問題の解決策 line-numbersプラグインなどは、window.Prismがundefinedだとプラグインのロードをやめてしまいます。この解決策としては、vmモジュールを使い、擬似的にグローバルオブジェクトとしてwindowがあるサンドボックス環境を作り、その中で、プラグインコードをevalしてやるようにします。要するにPrismにブラウザ環境だと思わせるようにするということです。 上の解決策を講じたコード 次が上の解決策を施したコードです。 loadPlugin.ts import fs from "fs"; import { JSDOM } from "jsdom"; import Prism from "prismjs"; import vm from "vm"; export function createLoadPlugin() { const { window } = new JSDOM(""); window.Prism = Prism; const ctx = vm.createContext(window); return function load(plugin: string): void { const filename = require.resolve( `prismjs/plugins/${plugin}/prism-${plugin}` ); const src = fs.readFileSync(filename, "utf-8"); vm.runInContext( // language=JavaScript ` try { const self = window; ${src}; } catch (err) { console.error(err); } `, ctx ); }; } 使い方は次の通り。 usage.ts import { createLoadPlugin } from "./loadPlugin"; const loadPlugin = createLoadPlugin(); loadPlugin("line-numbers"); loadPlugin("diff-highlight"); loadPlugin("autolinker"); loadPlugin("inline-color"); これで様々なプラグインがロードできるようになります。 ハイライトはPrism.highlightElementを用いる Node.jsでハイライトするにはPrism.highlightを用いるのが一般的ですが、DOM依存のプラグインはそのメソッドでは動かないので、Prism.highlightElementを使います。 実際にhighlightElementを使う場合は、DOMが必要なので次のようなユーティリティ関数を作っておくとよいです。 highlight.ts import { JSDOM } from "jsdom"; import Prism from "prismjs"; export function highlight( code: string, { language = "none", lineNumbers = false, }: { language?: string; lineNumbers?: boolean } = {} ): string { const { window } = new JSDOM(""); const pre = window.document.createElement("pre"); const codeElm = window.document.createElement("code"); pre.appendChild(codeElm); codeElm.textContent = code; codeElm.setAttribute( "class", [`language-${language}`] .concat(lineNumbers ? ["line-numbers"] : []) .join(" ") ); Prism.highlightElement(codeElm); return pre.outerHTML; } 最終的なコード 上で作った、loadPluginとhighlightを使った最終的なコードです。 main.ts import loadLanguages from "prismjs/components/index"; import { highlight } from "./highlight"; import { createLoadPlugin } from "./loadPlugin"; loadLanguages(); const loadPlugin = createLoadPlugin(); loadPlugin("line-numbers"); loadPlugin("diff-highlight"); loadPlugin("autolinker"); loadPlugin("inline-color"); const code = `span.foo { background-color: navy; color: #BFD; }`; const html = highlight(code, { language: "css", lineNumbers: true }); console.log(html); 上のhtml内容は次のようになります。 See the Pen Prism line-numbers inline-colors by suin (@suin) on CodePen.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Node.js】WatsonサービスをSDKを使わずに呼び出す

はじめに Node.jsでIBMの提供するWatsonサービスをSDK(ibm-watson)を使わずに呼び出すコードを備忘録のために残します。 IAM認証せずにWatsonサービスを呼び出すので、外部のpublicなインターネットに接続のできないIBM CloudのIaaS環境からWatsonサービスを呼びたいとき、Watsonサービスをさくっと触りたいときなどに有効な方法です。 ※アプリケーションがSDKを使ってWatsonサービスを呼び出す仕組みになっているが、実行環境でIAM認証出来ない(publicなインターネットに接続できない)場合には、IamAuthenticatorの代わりに、BasicAuthenticatorを使えばよいです。 今回はWatson DiscoveryというAI文書探索サービスのquery APIを呼び出すサンプルです。 セットアップ 今回はHttpクライアントとして、axiosを使用します。 npm install axios コード Watson Discoveryのquery APIにリクエストを送ってレスポンスをjsonファイルに出力するサンプルです。 <xxx>の部分は各自の環境の値に置き換えてください。 request_test.js const axios = require('axios').default; const fs = require('fs'); const username = 'apikey'; const password = <apikey>; const instanceId = <instanceId>; const projectId = <projectId>; const version = '2019-11-29' const endpoint = 'https://api.jp-tok.discovery.watson.cloud.ibm.com'; const headers = { 'Content-Type': 'application/json' }; const auth = 'Basic ' + Buffer.from(username + ':' + password).toString('base64'); const instance = axios.create({ baseURL: `${endpoint}/instances/${instanceId}`, timeout: 10000, headers, }); instance.defaults.headers.common['Authorization'] = auth; const url = `/v2/projects/${projectId}/query?version=${version}`; const count = 10000; const filter = ''; instance.post(url, { naturalLanguageQuery: 'サンプルクエリ', count, filter, }) .then(function (response) { fs.writeFileSync('./response.json', JSON.stringify(response.data, null, 2)); }) .catch(function (error) { console.log(error); }); 参考 IBM Cloud API Docs Discovery v2 IBM/node-sdk-core API Docsでサンプルで提示されているIamAuthenticatorの実装についてはここで確認できます。私はこのライブラリを眺めていてBasicAuthenticatorというauthenticatorの存在を知りました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

(入門)Node.jsで初めてのWebサーバーを立ち上げる Windoows10環境

node.js で サーバーを作成します。 環境 node v12.18.1 npm 6.14.4 windows10 nodeは以下のサイトを参考にして、インストールします。 https://qiita.com/satoyan419/items/56e0b5f35912b9374305 nodeのバージョン管理は以下のサイトを参考にします。 https://qiita.com/satoyan419/items/56e0b5f35912b9374305 vscodeでフォルダを作成して、 app.jsファイルに以下のコードを記入します。 app.js // モジュールをロードする DOMの代わり const http = require('http'); // サーバーを作る var server = http.createServer( (request,response)=>{ response.end('hello'); } ); // ポート番号:3000で受け付け開始 server.listen(port =3000); 最後のserver.listen(port =3000); のportの部分がないと エラー code: 'MODULE_NOT_FOUND', requireStack: [] が出きたので忘れないでください。 node.jsでは、javascriptで使用していたDOM要素の代わりに、 モジュールというものをロードします。 コマンドプロンプトを開いて、 コマンドプロンプト(cmd) node app.js localhost:3000にブラウザでアクセスしてください。 公式ドキュメントでも同様なコードが書いてあるので、参考に。 https://nodejs.org/ja/docs/guides/getting-started-guide/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む