ocoge/blocks/sensors/amg8833/index.js
2023-05-13 18:42:06 +09:00

466 lines
17 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Blockly.Msg["UGJ_DRAW_GRIDEYEDATA_TITLE"] = "赤外線アレイセンサ画像表示 %1 温度データ %2 温度範囲上限 %3 %4 温度範囲下限 %5 %6";
Blockly.Msg["UGJ_DRAW_GRIDEYEDATA_TOOLTIP"] = "AMG8833の温度データを、画像としてキャンバスに描画します。「着色」をチェックすると、温度範囲で設定されている色をつけて表示します。";
Blockly.Msg["UGJ_GRIDEYE_INIT_TITLE"] = "赤外線アレイセンサ(アドレス: %1 )を初期化";
Blockly.Msg["UGJ_GRIDEYE_INIT_TOOLTIP"] = "赤外線アレイセンサ AMG8833 の使用準備をします。";
Blockly.Msg["UGJ_GRIDEYE_THERMISTOR_TITLE"] = "赤外線アレイセンサ本体温度";
Blockly.Msg["UGJ_GRIDEYE_THERMISTOR_TOOLTIP"] = "AMG8833に内蔵されたサーミスタ温度センサの値を取得します。";
Blockly.Msg["UGJ_GRIDEYE_READ_TITLE"] = "赤外線アレイセンサの値";
Blockly.Msg["UGJ_GRIDEYE_READ_TOOLTIP"] = "AMG8833から読み取った温度データを、8x8の配列で取得します。";
Blockly.Msg["UGJ_GRIDEYE_STOP_TITLE"] = "赤外線アレイセンサから切断";
Blockly.Msg["UGJ_GRIDEYE_STOP_TOOLTIP"] = "センサーとの接続を停止します。";
Blockly.Msg["UGJ_GRIDEYE_CANVAS_CREATE_TITLE"] = "赤外線アレイセンサデータ表示キャンバスを作成";
Blockly.Msg["UGJ_GRIDEYE_CANVAS_CREATE_TOOLTIP"] = "ディスプレイエリアにAMG8833データ表示用キャンバスを作成します。";
Blockly.Msg["UGJ_TEACHABLE_MACHINE_TITLE"] = "TensorFlow.jsによる画像分類器の準備";
Blockly.Msg["UGJ_TEACHABLE_MACHINE_TOOLTIP"] = "TensorFlow.jsにMobileNet, KNN Classifierを読み込んで、画像認識分類を行う準備をします。";
Blockly.Msg["UGJ_GRIDEYE_PREDICT_CLASS_TITLE"] = "赤外線アレイセンサの画像で推論を行う";
Blockly.Msg["UGJ_GRIDEYE_PREDICT_CLASS_TOOLTIP"] = "キャンバスに表示されたAMG8833の画像を元に画像分類の推論を行います。推論の結果として定義済みのラベルを返します。";
Blockly.Msg["UGJ_GRIDEYE_ADD_EXAMPLE_TITLE"] = "赤外線アレイセンサの画像にラベル %1 をつけてデータセットへ追加";
Blockly.Msg["UGJ_GRIDEYE_ADD_EXAMPLE_TOOLTIP"] = "キャンバスに表示されているAMG8833の画像にラベルクラス名をつけてデータセットへ追加します。";
Blockly.Msg["UGJ_TENSORSET_STRINGIFY_TITLE"] = "学習したクラスデータセットを文字列に変換";
Blockly.Msg["UGJ_TENSORSET_STRINGIFY_TOOLTIP"] = "学習したクラスデータセットを文字列に変換して保存します。";
Blockly.Msg["UGJ_TENSORSET_PARSE_TITLE"] = "クラスデータ文字列 %1 を画像分類器にセット";
Blockly.Msg["UGJ_TENSORSET_PARSE_TOOLTIP"] = "JSONテキストをパースして画像分類器に戻します。";
/******************* */
/** Init Grid-Eye ** */
/******************* */
Blockly.defineBlocksWithJsonArray([{
"type": "ugj_grideye_init",
"message0": "%{BKY_UGJ_GRIDEYE_INIT_TITLE}",
"args0": [
{
"type": "field_dropdown",
"name": "addr",
"options": [
[
"0x68",
"0x68"
],
[
"0x69",
"0x69"
]
]
}
],
"inputsInline": true,
"previousStatement": null,
"nextStatement": null,
"tooltip": "%{BKY_UGJ_GRIDEYE_INIT_TOOLTIP}",
"helpUrl": "",
"style": "sensor_blocks"
}]);
Blockly.JavaScript['ugj_grideye_init'] = function (block) {
var dropdown_addr = block.getFieldValue('addr');
// Blockly.JavaScript.provideFunction_(
// 'require_gpio', [`const _pi = require('` + apptool.gpio_lib + `');`]
// );
let modpath = apptool.path.join(apptool.blocks_dir, 'sensors', 'amg8833', `AMG8833x.js`);
Blockly.JavaScript.provideFunction_(
'require_amg8833', [`const _amg8833 = require('${modpath}');`]
);
var code = `await _amg8833.init(${apptool.i2c_bus}, ${dropdown_addr}, window.addEventListener);\n`;
return code;//
};
/********************** */
/** Grid-Eye 本体温度 ** */
/********************** */
Blockly.defineBlocksWithJsonArray([{
"type": "ugj_grideye_thermistor",
"message0": "%{BKY_UGJ_GRIDEYE_THERMISTOR_TITLE}",
"output": "Number",
"tooltip": "%{BKY_UGJ_GRIDEYE_THERMISTOR_TOOLTIP}",
"helpUrl": "",
"style": "sensor_blocks"
}]);
Blockly.JavaScript['ugj_grideye_thermistor'] = function (block) {
var code = `await _amg8833.read_thermistor()`;
return [code, Blockly.JavaScript.ORDER_NONE];
};
/**************************** */
/** Read Temperature Array ** */
/**************************** */
Blockly.defineBlocksWithJsonArray([{
"type": "ugj_grideye_read",
"message0": "%{BKY_UGJ_GRIDEYE_READ_TITLE}",
"inputsInline": true,
"output": "Array",
"tooltip": "%{BKY_UGJ_GRIDEYE_READ_TOOLTIP}",
"helpUrl": "",
"style": "sensor_blocks"
}]);
Blockly.JavaScript['ugj_grideye_read'] = function (block) {
var code = 'await _amg8833.read_temp_array()';
return [code, Blockly.JavaScript.ORDER_ATOMIC];
};
/******************* */
/** Stop Grid-Eye ** */
/******************* */
Blockly.defineBlocksWithJsonArray([{
"type": "ugj_grideye_stop",
"message0": "%{BKY_UGJ_GRIDEYE_STOP_TITLE}",
"inputsInline": true,
"previousStatement": null,
"nextStatement": null,
"tooltip": "%{BKY_UGJ_GRIDEYE_STOP_TOOLTIP}",
"helpUrl": "",
"style": "sensor_blocks"
}]);
Blockly.JavaScript['ugj_grideye_stop'] = function (block) {
var code = 'await _amg8833.stop();\n';
return code;
};
/***************************** */
/** GridEye 表示キャンバス作成 ** */
/***************************** */
Blockly.defineBlocksWithJsonArray([{
"type": "ugj_grideye_canvas_create",
"message0": "%{BKY_UGJ_GRIDEYE_CANVAS_CREATE_TITLE}",
"inputsInline": true,
"previousStatement": null,
"nextStatement": null,
"tooltip": "%{BKY_UGJ_GRIDEYE_CANVAS_CREATE_TOOLTIP}",
"helpUrl": "",
"style": "multimedia_blocks"
}]);
Blockly.JavaScript['ugj_grideye_canvas_create'] = function (block) {
var code = `let _grideye_canvas = document.createElement('canvas');
_grideye_canvas.setAttribute('width', 8);
_grideye_canvas.setAttribute('height', 8);
_grideye_canvas.className = 'subdisplay';
_grideye_canvas.style.width = '160px';
_grideye_canvas.style.height = '160px';
_grideye_canvas.id = 'subcanvas';
document.getElementById('display_area').appendChild(_grideye_canvas);
_grideye_ctx = _grideye_canvas.getContext('2d', {willReadFrequently: true});
_grideye_imgData = _grideye_ctx.createImageData(8, 8);
`;
return code;
};
/********************************************** */
/** Draw IR Array Data to Image Data ** */
/********************************************** */
Blockly.defineBlocksWithJsonArray([{
"type": "ugj_draw_grideyedata",
"message0": "%{BKY_UGJ_DRAW_GRIDEYEDATA_TITLE}",
"args0": [
{
"type": "input_dummy"
},
{
"type": "input_value",
"name": "amg8833data",
"check": "Array",
"align": "RIGHT"
},
{
"type": "field_colour",
"name": "color_high",
"colour": "#ff0000"
},
{
"type": "input_value",
"name": "temp_high",
"check": "Number",
"align": "RIGHT"
},
{
"type": "field_colour",
"name": "color_low",
"colour": "#3333ff"
},
{
"type": "input_value",
"name": "temp_low",
"check": "Number",
"align": "RIGHT"
}
],
"inputsInline": false,
"previousStatement": null,
"nextStatement": null,
"tooltip": "%{BKY_UGJ_DRAW_GRIDEYEDATA_TOOLTIP}",
"helpUrl": "",
"style": "multimedia_blocks"
}]);
Blockly.JavaScript['ugj_draw_grideyedata'] = function (block) {
var value_amg8833data = Blockly.JavaScript.valueToCode(block, 'amg8833data', Blockly.JavaScript.ORDER_ATOMIC);
var colour_color_high = block.getFieldValue('color_high');
var value_temp_high = Blockly.JavaScript.valueToCode(block, 'temp_high', Blockly.JavaScript.ORDER_ATOMIC);
var colour_color_low = block.getFieldValue('color_low');
var value_temp_low = Blockly.JavaScript.valueToCode(block, 'temp_low', Blockly.JavaScript.ORDER_ATOMIC);
var functionName = Blockly.JavaScript.provideFunction_(
'_mapVal',
['const ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + ' = (val, inMin, inMax, outMin, outMax) => {',
`return (val - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;`,
'}'
]
);
// 温度カラー
let hr, hg, hb, lr, lg, lb;
hr = '0x' + colour_color_high.slice(1, 3);
hg = '0x' + colour_color_high.slice(3, 5);
hb = '0x' + colour_color_high.slice(5, 7);
lr = '0x' + colour_color_low.slice(1, 3);
lg = '0x' + colour_color_low.slice(3, 5);
lb = '0x' + colour_color_low.slice(5, 7);
var code = ` const _color_range = [[${lr}, ${hr}], [${lg}, ${hg}], [${lb}, ${hb}]];
let _grideye_data = ${value_amg8833data};//読み取りブロックを入力に直接接続できるようにする
for (let raw = 0; raw < _grideye_canvas.height; raw++) {
for (let col = 0; col < _grideye_canvas.width; col++) {
for (let rgb = 0; rgb < 3; rgb++) {
let pixel = ${functionName}(_grideye_data[raw][col], ${value_temp_low}, ${value_temp_high}, _color_range[rgb][0], _color_range[rgb][1]);
_grideye_imgData.data[((raw * _grideye_canvas.width * 4) + col * 4) + rgb] = pixel;
}
_grideye_imgData.data[((raw * _grideye_canvas.width * 4) + col * 4) + 3] = 0xff;
}
}
_grideye_ctx.putImageData(_grideye_imgData, 0, 0);
`;
return code;
};
/**************************** */
/** Teachable Machine を開始** */
/**************************** */
Blockly.defineBlocksWithJsonArray([{
"type": "ugj_teachable_machine",
"message0": "%{BKY_UGJ_TEACHABLE_MACHINE_TITLE}",
"inputsInline": true,
"previousStatement": null,
"nextStatement": null,
"tooltip": "%{BKY_UGJ_TEACHABLE_MACHINE_TOOLTIP}",
"helpUrl": "",
"style": "multimedia_blocks"
}]);
Blockly.JavaScript['ugj_teachable_machine'] = function (block) {
Blockly.JavaScript.provideFunction_(
'require_ts', [`const _tf = require('@tensorflow/tfjs-node');`]
);
Blockly.JavaScript.provideFunction_(
'require_mobilenet', [`const _mobilenet = require('@tensorflow-models/mobilenet');`]
);
Blockly.JavaScript.provideFunction_(
'require_knn', [`const _knnClassifier = require('@tensorflow-models/knn-classifier');`]
);
var code = ` const _net = await _mobilenet.load({ version: 1, alpha: 0.25 }); // 高速・低精度
const _classifier = _knnClassifier.create();
`;
return code;
};
/************************* */
/** GridEye で推論を行う ** */
/************************* */
Blockly.defineBlocksWithJsonArray([{
"type": "ugj_grideye_predict_class",
"message0": "%{BKY_UGJ_GRIDEYE_PREDICT_CLASS_TITLE}",
"inputsInline": true,
"output": "Number",
"tooltip": "%{BKY_UGJ_GRIDEYE_PREDICT_CLASS_TOOLTIP}",
"helpUrl": "",
"style": "multimedia_blocks"
}]);
Blockly.JavaScript['ugj_grideye_predict_class'] = function (block) {
var functionName = Blockly.JavaScript.provideFunction_( // left output にするための関数化
'_predictClass',
[
`if (_confidence === undefined) var _confidence;`,
`const ${Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_} = async (img, clsfr, mblnet) => {`,
`if (clsfr.getNumClasses() > 0) {`,
`const result = await clsfr.predictClass(mblnet.infer(img, 'conv_preds'));`,
`_confidence = result.confidences[result.label];`,
`return result.label;`,
`}`,
`else return 0;`,
`}`
]
);
var code = `await ${functionName}(_grideye_canvas, _classifier, _net)`;
return [code, Blockly.JavaScript.ORDER_NONE];
};
/******************************************** */
/** ラベルをつけて Example をデータセットに追加 ** */
/******************************************** */
Blockly.defineBlocksWithJsonArray([{
"type": "ugj_grideye_add_example",
"message0": "%{BKY_UGJ_GRIDEYE_ADD_EXAMPLE_TITLE}",
"args0": [
{
"type": "input_value",
"name": "class_id",
"check": "Number"
}
],
"inputsInline": true,
"previousStatement": null,
"nextStatement": null,
"tooltip": "%{BKY_UGJ_GRIDEYE_ADD_EXAMPLE_TOOLTIP}",
"helpUrl": "",
"style": "multimedia_blocks"
}]);
Blockly.JavaScript['ugj_grideye_add_example'] = function (block) {
var value_class_id = Blockly.JavaScript.valueToCode(block, 'class_id', Blockly.JavaScript.ORDER_ATOMIC);
var code = `_classifier.addExample (_net.infer(_grideye_canvas, true), ${value_class_id});`;
return code;
};
/*************************** */
/** 学習したクラスを文字列化 ** */
/*************************** */
Blockly.defineBlocksWithJsonArray([{
"type": "ugj_tensorset_stringify",
"message0": "%{BKY_UGJ_TENSORSET_STRINGIFY_TITLE}",
"output": null,
"tooltip": "%{BKY_UGJ_TENSORSET_STRINGIFY_TOOLTIP}",
"helpUrl": "",
"style": "multimedia_blocks"
}]);
Blockly.JavaScript['ugj_tensorset_stringify'] = function (block) {
var code = `JSON.stringify( Object.entries(_classifier.getClassifierDataset()).map(([label, data])=>[label, Array.from(data.dataSync()), data.shape]) )`;
return [code, Blockly.JavaScript.ORDER_NONE];
};
/***************************************** */
/** jsonをデータセットに戻して分類器にセット ** */
/***************************************** */
Blockly.defineBlocksWithJsonArray([{
"type": "ugj_tensorset_parse",
"message0": "%{BKY_UGJ_TENSORSET_PARSE_TITLE}",
"args0": [
{
"type": "input_value",
"name": "class_data_json",
"check": "String"
}
],
"previousStatement": null,
"nextStatement": null,
"tooltip": "%{BKY_UGJ_TENSORSET_PARSE_TOOLTIP}",
"helpUrl": "",
"style": "multimedia_blocks"
}]);
Blockly.JavaScript['ugj_tensorset_parse'] = function (block) {
var value_class_data_json = Blockly.JavaScript.valueToCode(block, 'class_data_json', Blockly.JavaScript.ORDER_ATOMIC);
var code = `_classifier.setClassifierDataset( Object.fromEntries( JSON.parse(${value_class_data_json}).map(([label, data, shape])=>[label, _tf.tensor(data, shape)]) ) );`;
return code;
};
// 温度ブロック(ツールボックス上非表示)
Blockly.defineBlocksWithJsonArray([{
"type": "ugj_temp",
"message0": "%1",
"args0": [
{
"type": "field_slider",
"name": "temp",
"value": 15,
"min": 0,
"max": 40,
"precision": 1
}
],
"inputsInline": true,
"output": "Number",
"tooltip": "",
"helpUrl": "",
"style": "math_blocks"
}]);
Blockly.JavaScript['ugj_temp'] = function (block) {
var number_temp = block.getFieldValue('temp');
var code = `${number_temp}`;
return [code, Blockly.JavaScript.ORDER_NONE];
};
flyout_contents = flyout_contents.concat([
{
"kind": "label",
"text": "赤外線アレイセンサーサーマルカメラAMG8833",
"web-line": "4.0",
"web-line-width": "200"
},
{
"kind": "block",
"type": "ugj_grideye_init",
"fields": {
"addr": "0x69"
}
},
{
"kind": "block",
"type": "ugj_grideye_thermistor"
},
{
"kind": "block",
"type": "ugj_grideye_read"
},
{
"kind": "block",
"type": "ugj_grideye_stop"
},
{
"kind": "block",
"type": "ugj_grideye_canvas_create"
},
{
"kind": "block",
"type": "ugj_draw_grideyedata",
"fields": {
"color_high": "#ff0000",
"color_low": "#3333ff"
},
"inputs": {
"temp_high": {
"shadow": {
"type": "ugj_temp",
"fields": {
"temp": "28"
}
}
},
"temp_low": {
"shadow": {
"type": "ugj_temp",
"fields": {
"temp": "15"
}
}
}
}
},
{
"kind": "block",
"type": "ugj_teachable_machine"
},
{
"kind": "block",
"type": "ugj_grideye_predict_class"
},
{
"kind": "block",
"type": "ugj_grideye_add_example",
"inputs": {
"class_id": {
"shadow": {
"type": "math_number",
"fields": {
"NUM": "0"
}
}
}
}
},
{
"kind": "block",
"type": "ugj_tensorset_stringify"
},
{
"kind": "block",
"type": "ugj_tensorset_parse"
}
]);