ocoge/blocks/sensors/amg8833/index.js

409 lines
16 KiB
JavaScript
Raw Normal View History

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 ** */
/******************* */
var ugjGridEyeInitDefinition = {
"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.Blocks['ugj_grideye_init'] = {
init: function () {
this.jsonInit(ugjGridEyeInitDefinition);
}
};
Blockly.JavaScript['ugj_grideye_init'] = function (block) {
var dropdown_addr = block.getFieldValue('addr');
Blockly.JavaScript.provideFunction_(
'require_gpio', [`const _pi = require('@ocoge.club/` + apptool.gpio_backend + `');`]
);
let modpath = apptool.path.join(apptool.blocks_sensors_dir, '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 本体温度 ** */
/********************** */
var ugjGridEyeThermistorDefinition = {
"type": "ugj_grideye_thermistor",
"message0": "%{BKY_UGJ_GRIDEYE_THERMISTOR_TITLE}",
"output": "Number",
"tooltip": "%{BKY_UGJ_GRIDEYE_THERMISTOR_TOOLTIP}",
"helpUrl": "",
"style": "sensor_blocks"
};
Blockly.Blocks['ugj_grideye_thermistor'] = {
init: function () {
this.jsonInit(ugjGridEyeThermistorDefinition);
}
};
Blockly.JavaScript['ugj_grideye_thermistor'] = function (block) {
var code = `await _amg8833.read_thermistor()`;
return [code, Blockly.JavaScript.ORDER_NONE];
};
/**************************** */
/** Read Temperature Array ** */
/**************************** */
var ugjGridEyeReadDefinition = {
"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.Blocks['ugj_grideye_read'] = {
init: function () {
this.jsonInit(ugjGridEyeReadDefinition);
}
};
Blockly.JavaScript['ugj_grideye_read'] = function (block) {
var code = 'await _amg8833.read_temp_array()';
return [code, Blockly.JavaScript.ORDER_ATOMIC];
};
/******************* */
/** Stop Grid-Eye ** */
/******************* */
var ugjGridEyeStopDefinition = {
"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.Blocks['ugj_grideye_stop'] = {
init: function () {
this.jsonInit(ugjGridEyeStopDefinition);
}
};
Blockly.JavaScript['ugj_grideye_stop'] = function (block) {
var code = 'await _amg8833.stop();\n';
return code;
};
/***************************** */
/** GridEye 表示キャンバス作成 ** */
/***************************** */
var ugjGridEyeCanvasCreateDefinition = {
"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.Blocks['ugj_grideye_canvas_create'] = {
init: function () {
this.jsonInit(ugjGridEyeCanvasCreateDefinition);
}
};
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 ** */
/********************************************** */
var ugjDrawGrideyedataDefinition = {
"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.Blocks['ugj_draw_grideyedata'] = {
init: function () {
this.jsonInit(ugjDrawGrideyedataDefinition);
}
};
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 を開始** */
/**************************** */
var ugjTeachableMachineDefinition = {
"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.Blocks['ugj_teachable_machine'] = {
init: function () {
this.jsonInit(ugjTeachableMachineDefinition);
}
};
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 で推論を行う ** */
/************************* */
var ugjGridEyePredictClassDefinition = {
"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.Blocks['ugj_grideye_predict_class'] = {
init: function () {
this.jsonInit(ugjGridEyePredictClassDefinition);
}
};
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 をデータセットに追加 ** */
/******************************************** */
var ugjGridEyeAddExampleDefinition = {
"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.Blocks['ugj_grideye_add_example'] = {
init: function () {
this.jsonInit(ugjGridEyeAddExampleDefinition);
}
};
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;
};
/*************************** */
/** 学習したクラスを文字列化 ** */
/*************************** */
var ugjTensorsetStringifyDefinition = {
"type": "ugj_tensorset_stringify",
"message0": "%{BKY_UGJ_TENSORSET_STRINGIFY_TITLE}",
"output": null,
"tooltip": "%{BKY_UGJ_TENSORSET_STRINGIFY_TOOLTIP}",
"helpUrl": "",
"style": "multimedia_blocks"
};
Blockly.Blocks['ugj_tensorset_stringify'] = {
init: function () {
this.jsonInit(ugjTensorsetStringifyDefinition);
}
};
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をデータセットに戻して分類器にセット ** */
/***************************************** */
var ugjTensorsetParseDefinition = {
"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.Blocks['ugj_tensorset_parse'] = {
init: function () {
this.jsonInit(ugjTensorsetParseDefinition);
}
};
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;
};