From 7a98f7c4024235fba67306b8672e6d5942fddfa4 Mon Sep 17 00:00:00 2001 From: Jason Kim Date: Wed, 25 Sep 2024 11:10:27 +0900 Subject: [PATCH 1/9] =?UTF-8?q?=EC=BD=94=EC=95=8C=EB=9D=BC=EB=B4=87,=20?= =?UTF-8?q?=EB=A1=9C=EB=B4=87=EC=95=84=EC=9D=B4=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blocks/hardware/block_robotisRBKoala.js | 23 +- .../block_robotisRBPracticalAssembly.js | 21 +- .../block_robotis_robotai_lite.js | 245 +++++++++--------- 3 files changed, 153 insertions(+), 136 deletions(-) diff --git a/src/playground/blocks/hardware/block_robotisRBKoala.js b/src/playground/blocks/hardware/block_robotisRBKoala.js index b92b23597f..cba0085fbb 100644 --- a/src/playground/blocks/hardware/block_robotisRBKoala.js +++ b/src/playground/blocks/hardware/block_robotisRBKoala.js @@ -436,6 +436,9 @@ Entry.Robotis_rb_koala.setLanguage = function() { robotis_moveRG2: "앉기", robotis_moveRG3: "발버둥", robotis_moveRG4: "발들기", + robotis_fast: '빠른', + robotis_normal: '보통', + robotis_slow: '느린', robotis_stop: "정지", robotis_roll: "좌우 회전각 (roll)", robotis_pitch: "앞뒤 회전각 (pitch)", @@ -966,6 +969,9 @@ Entry.Robotis_rb_koala.setLanguage = function() { robotis_moveRG2: "Sit", robotis_moveRG3: "Struggle", robotis_moveRG4: "RaiseFeet", + robotis_fast: 'Fast', + robotis_normal: 'Normal', + robotis_slow: 'Slow', robotis_stop: "Stop", robotis_roll: "Left-right rotate angle (roll)", robotis_pitch: "Forward-backward rotate angle (pitch)", @@ -1560,7 +1566,7 @@ Entry.Robotis_rb_koala.getBlocks = function() { leftSpeed = 127; // 속도제어 안함 rightSpeed = wheelSpeed; } else { - leftSpeed = wheelSpeed; // 속도제어 안함 + leftSpeed = wheelSpeed; rightSpeed = wheelSpeed; } @@ -1721,7 +1727,7 @@ Entry.Robotis_rb_koala.getBlocks = function() { type: 'Dropdown', options: [ [Lang.Blocks.robotis_moveF, '1'], - [Lang.Blocks.robotis_moveB, '-1'], //Lang.Blocks.robotis_common_green_color + [Lang.Blocks.robotis_moveB, '-1'], ], value: '1', fontSize: 11, @@ -1881,10 +1887,9 @@ Entry.Robotis_rb_koala.getBlocks = function() { { type: 'Dropdown', options: [ - ['느린', '1'], - ['보통', '2'], - ['빠른', '3'], - + [Lang.Blocks.robotis_slow, '1'], + [Lang.Blocks.robotis_normal, '2'], + [Lang.Blocks.robotis_fast, '3'], ], value: '1', fontSize: 11, @@ -3118,7 +3123,7 @@ Entry.Robotis_rb_koala.getBlocks = function() { var data_sendqueue = [ [data_instruction, data_address, data_length, data_value], - [3, 162, 1, 1] + [Entry.Robotis_rb.INSTRUCTION.WRITE, 162, 1, 1] ]; @@ -3296,7 +3301,7 @@ Entry.Robotis_rb_koala.getBlocks = function() { var data_sendqueue = [ [data_instruction, data_address, data_length, data_value], - [3, 162, 1, 1] + [Entry.Robotis_rb.INSTRUCTION.WRITE, 162, 1, 1] ]; @@ -4395,7 +4400,7 @@ Entry.Robotis_rb_koala.getBlocks = function() { data_length, data_value, ], - [3, 162, 1, 1] + [Entry.Robotis_rb.INSTRUCTION.WRITE, 162, 1, 1] ]; return Entry.Robotis_carCont.postCallReturn( script, diff --git a/src/playground/blocks/hardware/block_robotisRBPracticalAssembly.js b/src/playground/blocks/hardware/block_robotisRBPracticalAssembly.js index 4128d7b09c..5be3e25c0c 100644 --- a/src/playground/blocks/hardware/block_robotisRBPracticalAssembly.js +++ b/src/playground/blocks/hardware/block_robotisRBPracticalAssembly.js @@ -333,7 +333,7 @@ Entry.Robotis_rb_P_Assembly.setLanguage = function () { // LED 제어 robotis_Practice_cm_led: "제어기의 지정한 LED를 켜거나 끄기", - robotis_Practice_cm_led_pattern: "제어기의 깜박임 패턴 설정", + robotis_Practice_cm_led_pattern: "제어기의 LED의 깜박임 패턴 설정", // DXL 제어 robotis_Practice_dxl_set_mode: "지정한 ID의 모터의 동작모드를 설정", @@ -507,6 +507,9 @@ Entry.Robotis_rb_P_Assembly.setLanguage = function () { robotis_moveRG2: "앉기", robotis_moveRG3: "발버둥", robotis_moveRG4: "발들기", + robotis_fast: '빠른', + robotis_normal: '보통', + robotis_slow: '느린', robotis_stop: "정지", robotis_roll: "좌우 회전각 (roll)", robotis_pitch: "앞뒤 회전각 (pitch)", @@ -1085,6 +1088,9 @@ Entry.Robotis_rb_P_Assembly.setLanguage = function () { robotis_moveRG2: "Sit", robotis_moveRG3: "Struggle", robotis_moveRG4: "RaiseFeet", + robotis_fast: 'Fast', + robotis_normal: 'Normal', + robotis_slow: 'Slow', robotis_stMotion1: "Standard", robotis_stMotion2: "Forward", robotis_stMotion3: "TurnRight", @@ -1830,10 +1836,9 @@ Entry.Robotis_rb_P_Assembly.getBlocks = function () { { type: 'Dropdown', options: [ - ['느린', '1'], - ['보통', '2'], - ['빠른', '3'], - + [Lang.Blocks.robotis_slow, '1'], + [Lang.Blocks.robotis_normal, '2'], + [Lang.Blocks.robotis_fast, '3'], ], value: '1', fontSize: 11, @@ -3757,7 +3762,7 @@ Entry.Robotis_rb_P_Assembly.getBlocks = function () { var data_sendqueue = [ [data_instruction, data_address, data_length, data_value], - [3, 162, 1, 1] + [Entry.Robotis_rb.INSTRUCTION.WRITE, 162, 1, 1] ]; @@ -3935,7 +3940,7 @@ Entry.Robotis_rb_P_Assembly.getBlocks = function () { var data_sendqueue = [ [data_instruction, data_address, data_length, data_value], - [3, 162, 1, 1] + [Entry.Robotis_rb.INSTRUCTION.WRITE, 162, 1, 1] ]; @@ -5037,7 +5042,7 @@ Entry.Robotis_rb_P_Assembly.getBlocks = function () { data_length, data_value, ], - [3, 162, 1, 1] + [Entry.Robotis_rb.INSTRUCTION.WRITE, 162, 1, 1] ]; return Entry.Robotis_carCont.postCallReturn( script, diff --git a/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js b/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js index 420a9d2edc..101fe83518 100644 --- a/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js +++ b/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js @@ -676,7 +676,7 @@ let camera_id_for_use = 0; // LED 제어 robotis_robotai_lite_cm_led: '제어기의 지정한 LED를 켜거나 끄기', - robotis_robotai_lite_cm_led_pattern: '제어기의 깜박임 패턴 설정', + robotis_robotai_lite_cm_led_pattern: '제어기의 LED의 깜박임 패턴 설정', // DXL 제어 robotis_robotai_lite_dxl_set_mode: '지정한 ID의 모터의 동작모드를 설정', @@ -865,6 +865,9 @@ let camera_id_for_use = 0; robotis_moveRG2: '앉기', robotis_moveRG3: '발버둥', robotis_moveRG4: '발들기', + robotis_fast: '빠른', + robotis_normal: '보통', + robotis_slow: '느린', robotis_stop: '정지', robotis_roll: '좌우 회전각 (roll)', robotis_pitch: '앞뒤 회전각 (pitch)', @@ -1548,6 +1551,9 @@ let camera_id_for_use = 0; robotis_moveRG2: 'Sit', robotis_moveRG3: 'Struggle', robotis_moveRG4: 'RaiseFeet', + robotis_fast: 'Fast', + robotis_normal: 'Normal', + robotis_slow: 'Slow', robotis_stop: 'Stop', robotis_roll: 'Left-right rotate angle (roll)', robotis_pitch: 'Forward-backward rotate angle (pitch)', @@ -1846,7 +1852,7 @@ let camera_id_for_use = 0; const speed = script.getNumberValue('SPEED', script); const direction = script.getField('DIRECTION', script); - const data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + const data_instruction = INST_WRITE; const data_address = 710; const data_length = 2; let data_value = 0; @@ -1883,51 +1889,6 @@ let camera_id_for_use = 0; py: ['Robotailite.go_simple(%1, %2)'], }, }, - robotis_robotai_lite_drive_stop: { - color: EntryStatic.colorSet.block.default.HARDWARE, - outerLine: EntryStatic.colorSet.block.darken.HARDWARE, - skeleton: 'basic', - statements: [], - params: [ - { - type: 'Indicator', - img: 'block_icon/hardware_icon.svg', - size: 12, - }, - ], - events: {}, - def: { - params: [null], - type: 'robotis_robotai_lite_drive_stop', - }, - paramsKeyMap: { - DIRECTION: 0, - }, - class: 'robotis_robotai_lite_move', - isNotFor: ['RobotisRobotaiLite'], - func(sprite, script) { - // instruction / address / length / value / default length - - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; - let data_address = 710; - let data_length = 2; - let data_value = 0; - - let data_sendqueue = [ - [data_instruction, 5200, 1, 0], - [data_instruction, data_address, data_length, data_value], - ]; - return Entry.RobotisRobotaiLite.postCallReturn( - script, - data_sendqueue, - DEFAULT_DELAY - ); - }, - syntax: { - js: [], - py: ['Robotailite.stop(%1, %2)'], - }, - }, robotis_robotai_lite_drive_advanced: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, @@ -2001,7 +1962,7 @@ let camera_id_for_use = 0; let rightSpeed = script.getNumberValue('RIGHT_SPEED', script); const rightDirection = script.getField('RIGHT_DIRECTION', script); - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 710; let data_length = 2; let data_value = 0; @@ -2059,6 +2020,7 @@ let camera_id_for_use = 0; options: [ [Lang.Blocks.robotis_left, '1'], [Lang.Blocks.robotis_right, '0'], + [Lang.Blocks.robotis_both, '2'], ], value: '1', fontSize: 11, @@ -2113,7 +2075,7 @@ let camera_id_for_use = 0; let leftSpeed = 0; let rightSpeed = 0; - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 710; let data_length = 2; let data_value = 0; @@ -2216,7 +2178,7 @@ let camera_id_for_use = 0; let wheelAngle = script.getNumberValue('WHEEL_ANGLE', script); let wheelDirection = script.getNumberValue('WHEEL_DIRECTION', script); - const data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + const data_instruction = INST_WRITE; let data_address = 580; let data_length = 8; let angleValue = 0; @@ -2302,7 +2264,7 @@ let camera_id_for_use = 0; params: [ { type: 'number', - params: ['10'], + params: ['5'], }, null, ], @@ -2325,7 +2287,7 @@ let camera_id_for_use = 0; distance = -1000; } - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 270; let data_length = 4; let data_value = Math.floor(10 * distance * direction); @@ -2403,7 +2365,7 @@ let camera_id_for_use = 0; angle = -720; } - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 270; let data_length = 4; let data_value = Math.floor(angle); @@ -2432,9 +2394,9 @@ let camera_id_for_use = 0; { type: 'Dropdown', options: [ - ['느린', '1'], - ['보통', '2'], - ['빠른', '3'], + [Lang.Blocks.robotis_slow, '1'], + [Lang.Blocks.robotis_normal, '2'], + [Lang.Blocks.robotis_fast, '3'], ], value: '1', fontSize: 11, @@ -2461,7 +2423,7 @@ let camera_id_for_use = 0; // instruction / address / length / value / default length let speed_level = script.getNumberValue('SPEED', script); - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 5200; let data_length = 1; @@ -2530,7 +2492,7 @@ let camera_id_for_use = 0; } } - let data_sendqueue = [[Entry.Robotis_rb.INSTRUCTION.WRITE, 5200, 1, 0]]; + let data_sendqueue = [[INST_WRITE, 5200, 1, 0]]; return Entry.RobotisRobotaiLite.postCallReturn( script, @@ -2581,7 +2543,7 @@ let camera_id_for_use = 0; // instruction / address / length / value / default length let turn_type = script.getNumberValue('TURN_TYPE', script); - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 66; let data_length = 2; @@ -2596,7 +2558,52 @@ let camera_id_for_use = 0; }, syntax: { js: [], - py: ['Robotailite.follow_line(%1)'], + py: ['Robotailite.turn_at_line(%1)'], + }, + }, + robotis_robotai_lite_drive_stop: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'robotis_robotai_lite_drive_stop', + }, + paramsKeyMap: { + DIRECTION: 0, + }, + class: 'robotis_robotai_lite_move', + isNotFor: ['RobotisRobotaiLite'], + func(sprite, script) { + // instruction / address / length / value / default length + + let data_instruction = INST_WRITE; + let data_address = 710; + let data_length = 2; + let data_value = 0; + + let data_sendqueue = [ + [data_instruction, 5200, 1, 0], + [data_instruction, data_address, data_length, data_value], + ]; + return Entry.RobotisRobotaiLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + ); + }, + syntax: { + js: [], + py: ['Robotailite.stop(%1, %2)'], }, }, robotis_robotai_lite_securitybot_init: { @@ -2622,7 +2629,7 @@ let camera_id_for_use = 0; func(sprite, script) { // instruction / address / length / value / default length - let data_sendqueue = [[Entry.Robotis_rb.INSTRUCTION.WRITE, 2110, 1, 1]]; + let data_sendqueue = [[INST_WRITE, 2110, 1, 1]]; return Entry.RobotisRobotaiLite.postCallReturn( script, data_sendqueue, @@ -2657,7 +2664,7 @@ let camera_id_for_use = 0; func(sprite, script) { // instruction / address / length / value / default length - let data_sendqueue = [[Entry.Robotis_rb.INSTRUCTION.WRITE, 2111, 1, 1]]; + let data_sendqueue = [[INST_WRITE, 2111, 1, 1]]; return Entry.RobotisRobotaiLite.postCallReturn( script, data_sendqueue, @@ -2692,7 +2699,7 @@ let camera_id_for_use = 0; func(sprite, script) { // instruction / address / length / value / default length - let data_sendqueue = [[Entry.Robotis_rb.INSTRUCTION.WRITE, 2112, 1, 1]]; + let data_sendqueue = [[INST_WRITE, 2112, 1, 1]]; return Entry.RobotisRobotaiLite.postCallReturn( script, data_sendqueue, @@ -2727,7 +2734,7 @@ let camera_id_for_use = 0; func(sprite, script) { // instruction / address / length / value / default length - let data_sendqueue = [[Entry.Robotis_rb.INSTRUCTION.WRITE, 2121, 1, 1]]; + let data_sendqueue = [[INST_WRITE, 2121, 1, 1]]; return Entry.RobotisRobotaiLite.postCallReturn( script, data_sendqueue, @@ -2762,7 +2769,7 @@ let camera_id_for_use = 0; func(sprite, script) { // instruction / address / length / value / default length - let data_sendqueue = [[Entry.Robotis_rb.INSTRUCTION.WRITE, 2122, 1, 1]]; + let data_sendqueue = [[INST_WRITE, 2122, 1, 1]]; return Entry.RobotisRobotaiLite.postCallReturn( script, data_sendqueue, @@ -2796,7 +2803,7 @@ let camera_id_for_use = 0; class: 'robotis_robotai_lite_special', isNotFor: ['RobotisRobotaiLite'], func(sprite, script) { - let data_sendqueue = [[Entry.Robotis_rb.INSTRUCTION.WRITE, 2130, 1, 1]]; + let data_sendqueue = [[INST_WRITE, 2130, 1, 1]]; return Entry.RobotisRobotaiLite.postCallReturn( script, data_sendqueue, @@ -2831,7 +2838,7 @@ let camera_id_for_use = 0; func(sprite, script) { // instruction / address / length / value / default length - let data_sendqueue = [[Entry.Robotis_rb.INSTRUCTION.WRITE, 2131, 1, 1]]; + let data_sendqueue = [[INST_WRITE, 2131, 1, 1]]; return Entry.RobotisRobotaiLite.postCallReturn(script, data_sendqueue, 200); }, syntax: { @@ -2936,7 +2943,7 @@ let camera_id_for_use = 0; break; } - let data_sendqueue = [[Entry.Robotis_rb.INSTRUCTION.WRITE, address, 1, 1]]; + let data_sendqueue = [[INST_WRITE, address, 1, 1]]; return Entry.RobotisRobotaiLite.postCallReturn( script, data_sendqueue, @@ -3527,7 +3534,7 @@ let camera_id_for_use = 0; { type: 'Block', accept: 'string', - value: 'asdfasdf', + value: '', }, { type: 'Dropdown', @@ -3804,7 +3811,7 @@ let camera_id_for_use = 0; let robotType = script.getNumberValue('ROBOT_TYPE', script); let screenValue = script.getNumberValue('BACKGROUND', script); - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 163; let data_length = 2; let data_value = screenValue + robotType * 256; @@ -3893,7 +3900,7 @@ let camera_id_for_use = 0; let data_sendqueue = [ [data_instruction, data_address, data_length, data_value], - [3, 162, 1, 1], + [INST_WRITE, 162, 1, 1], ]; return Entry.RobotisRobotaiLite.postCallReturn( @@ -3976,7 +3983,7 @@ let camera_id_for_use = 0; let robotType = script.getNumberValue('ROBOT_TYPE', script); let screenValue = script.getNumberValue('BACKGROUND', script); - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 163; let data_length = 2; let data_value = screenValue; @@ -4066,7 +4073,7 @@ let camera_id_for_use = 0; let data_sendqueue = [ [data_instruction, data_address, data_length, data_value], - [3, 162, 1, 1], + [INST_WRITE, 162, 1, 1], ]; return Entry.RobotisRobotaiLite.postCallReturn( @@ -4166,7 +4173,7 @@ let camera_id_for_use = 0; let y = script.getNumberValue('Y', script); let size = script.getNumberValue('SIZE', script) * 2; - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 166; let data_length = 2; let data_value = 10496; @@ -4192,11 +4199,11 @@ let camera_id_for_use = 0; data_value = iconNum; let data_sendqueue = [ - [Entry.Robotis_rb.INSTRUCTION.WRITE, 130, 2, x], - [Entry.Robotis_rb.INSTRUCTION.WRITE, 132, 2, y], - [Entry.Robotis_rb.INSTRUCTION.WRITE, 149, 2, size], + [INST_WRITE, 130, 2, x], + [INST_WRITE, 132, 2, y], + [INST_WRITE, 149, 2, size], [data_instruction, data_address, data_length, data_value], - [Entry.Robotis_rb.INSTRUCTION.WRITE, 162, 1, 1], + [INST_WRITE, 162, 1, 1], ]; return Entry.RobotisRobotaiLite.postCallReturn( @@ -4309,7 +4316,7 @@ let camera_id_for_use = 0; let y = script.getNumberValue('Y', script); let size = script.getNumberValue('SIZE', script) * 2; - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 166; let data_length = 2; let data_value = 10496; @@ -4335,11 +4342,11 @@ let camera_id_for_use = 0; data_value = iconNum; let data_sendqueue = [ - [Entry.Robotis_rb.INSTRUCTION.WRITE, 130, 2, x], - [Entry.Robotis_rb.INSTRUCTION.WRITE, 132, 2, y], - [Entry.Robotis_rb.INSTRUCTION.WRITE, 149, 2, size], + [INST_WRITE, 130, 2, x], + [INST_WRITE, 132, 2, y], + [INST_WRITE, 149, 2, size], [data_instruction, data_address, data_length, data_value], - [Entry.Robotis_rb.INSTRUCTION.WRITE, 162, 1, 1], + [INST_WRITE, 162, 1, 1], ]; return Entry.RobotisRobotaiLite.postCallReturn( @@ -4454,7 +4461,7 @@ let camera_id_for_use = 0; let y = script.getNumberValue('Y', script); let size = script.getNumberValue('SIZE', script) * 2; - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 166; let data_length = 2; let data_value = 10496; @@ -4480,11 +4487,11 @@ let camera_id_for_use = 0; data_value = iconNum; let data_sendqueue = [ - [Entry.Robotis_rb.INSTRUCTION.WRITE, 130, 2, x], - [Entry.Robotis_rb.INSTRUCTION.WRITE, 132, 2, y], - [Entry.Robotis_rb.INSTRUCTION.WRITE, 149, 2, size], + [INST_WRITE, 130, 2, x], + [INST_WRITE, 132, 2, y], + [INST_WRITE, 149, 2, size], [data_instruction, data_address, data_length, data_value], - [Entry.Robotis_rb.INSTRUCTION.WRITE, 162, 1, 1], + [INST_WRITE, 162, 1, 1], ]; return Entry.RobotisRobotaiLite.postCallReturn( @@ -4601,7 +4608,7 @@ let camera_id_for_use = 0; let y = script.getNumberValue('Y', script); let size = script.getNumberValue('SIZE', script) * 2; - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 166; let data_length = 2; let data_value = 10496; @@ -4627,11 +4634,11 @@ let camera_id_for_use = 0; data_value = iconNum; let data_sendqueue = [ - [Entry.Robotis_rb.INSTRUCTION.WRITE, 130, 2, x], - [Entry.Robotis_rb.INSTRUCTION.WRITE, 132, 2, y], - [Entry.Robotis_rb.INSTRUCTION.WRITE, 149, 2, size], + [INST_WRITE, 130, 2, x], + [INST_WRITE, 132, 2, y], + [INST_WRITE, 149, 2, size], [data_instruction, data_address, data_length, data_value], - [Entry.Robotis_rb.INSTRUCTION.WRITE, 162, 1, 1], + [INST_WRITE, 162, 1, 1], ]; return Entry.RobotisRobotaiLite.postCallReturn( @@ -4735,7 +4742,7 @@ let camera_id_for_use = 0; let data_buf = []; let i = 0; - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 900; let data_length = 2; @@ -4771,7 +4778,7 @@ let camera_id_for_use = 0; let data_sendqueue = [ [data_instruction, data_address, data_length, data_buf], - [Entry.Robotis_rb.INSTRUCTION.WRITE, 162, 1, 1], + [INST_WRITE, 162, 1, 1], ]; return Entry.RobotisRobotaiLite.postCallReturn( @@ -4853,7 +4860,7 @@ let camera_id_for_use = 0; let color = script.getNumberValue('COLOR', script); let data_buf = []; - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 130; let data_length = 11; @@ -4883,7 +4890,7 @@ let camera_id_for_use = 0; let data_sendqueue = [ [data_instruction, data_address, data_length, data_buf], - [Entry.Robotis_rb.INSTRUCTION.WRITE, 161, 2, 1 * 256 + 8], + [INST_WRITE, 161, 2, 1 * 256 + 8], ]; return Entry.RobotisRobotaiLite.postCallReturn( @@ -5002,13 +5009,13 @@ let camera_id_for_use = 0; data_buf.push(byteArray[i]); } - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 900; let data_length = 9 + byteArray.length; let data_sendqueue = [ [data_instruction, data_address, data_length, data_buf], - [Entry.Robotis_rb.INSTRUCTION.WRITE, 162, 1, 1], + [INST_WRITE, 162, 1, 1], ]; return Entry.RobotisRobotaiLite.postCallReturn( @@ -5052,7 +5059,7 @@ let camera_id_for_use = 0; // instruction / address / length / value / default length let bright = script.getNumberValue('BRIGHT', script); - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 180; let data_length = 1; let data_value = 0; @@ -5120,7 +5127,7 @@ let camera_id_for_use = 0; // instruction / address / length / value / default length let color = script.getNumberValue('COLOR', script); - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 163; let data_length = 2; let data_value = 0; @@ -5129,9 +5136,9 @@ let camera_id_for_use = 0; bg_color = color; let data_sendqueue = [ - [Entry.Robotis_rb.INSTRUCTION.WRITE, 163, 2, 2817], + [INST_WRITE, 163, 2, 2817], [data_instruction, data_address, data_length, data_value], - [3, 162, 1, 1], + [INST_WRITE, 162, 1, 1], ]; return Entry.RobotisRobotaiLite.postCallReturn( script, @@ -5246,8 +5253,8 @@ let camera_id_for_use = 0; const time_parameter = 0x8000 + (period << 8) + period; let data_sendqueue = [ - [Entry.Robotis_rb.INSTRUCTION.WRITE, 158, 2, colors], - [Entry.Robotis_rb.INSTRUCTION.WRITE, 163, 2, time_parameter], + [INST_WRITE, 158, 2, colors], + [INST_WRITE, 163, 2, time_parameter], ]; return Entry.RobotisRobotaiLite.postCallReturn( script, @@ -5312,7 +5319,7 @@ let camera_id_for_use = 0; let cmLed = script.getField('RB_LED', script); let value = script.getField('VALUE', script); - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 40; let data_length = 1; let data_value = 0; @@ -5394,7 +5401,7 @@ let camera_id_for_use = 0; let pattern = script.getNumberValue('PATTERN', script); let speed = script.getNumberValue('SPEED', script); - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 40; let data_length = 1; let data_value = 0; @@ -5928,7 +5935,7 @@ let camera_id_for_use = 0; let dxl_round = script.getNumberValue('DXL_ROUND', script); let dxl_direction = script.getNumberValue('DXL_DIRECTION', script); - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address_1 = 0; let data_length_1 = 0; let data_value_1 = 0; @@ -6082,7 +6089,7 @@ let camera_id_for_use = 0; let cmBuzzerNote = script.getNumberValue('CM_BUZZER_NOTE', script); let cmBuzzerTime = 0; - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 0; let data_value = 0; let interval = 0; @@ -6231,7 +6238,7 @@ let camera_id_for_use = 0; cmBuzzerBeat = Math.min(Math.max(cmBuzzerBeat, 0), 100); - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address_1 = 0; let data_length_1 = 0; let data_value_1 = 0; @@ -6536,7 +6543,7 @@ let camera_id_for_use = 0; // instruction / address / length / value / default length let cmHello = script.getField('HELLO', script); - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 110; let data_length = 2; let data_value = 0; @@ -6618,7 +6625,7 @@ let camera_id_for_use = 0; // instruction / address / length / value / default length let cmHello = script.getField('HELLO', script); - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 110; let data_length = 2; let data_value = 0; @@ -6695,7 +6702,7 @@ let camera_id_for_use = 0; // instruction / address / length / value / default length let roomNum = script.getField('ROOM', script); - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 115; let data_length = 1; let data_value = 0; @@ -6757,7 +6764,7 @@ let camera_id_for_use = 0; // instruction / address / length / value / default length let roomNum = script.getField('ROOM', script); - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 116; let data_length = 1; let data_value = 0; @@ -6992,7 +6999,7 @@ let camera_id_for_use = 0; let scope = script.executor.scope; // instruction / address / length / value / default length - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 4029; // ID_FOR_USE let data_length = 2; let data_value = script.getNumberValue('ID'); @@ -7080,7 +7087,7 @@ let camera_id_for_use = 0; let scope = script.executor.scope; // instruction / address / length / value / default length - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 4029; // ID_FOR_USE let data_length = 2; let data_value = script.getNumberValue('ID'); @@ -7257,7 +7264,7 @@ let camera_id_for_use = 0; // instruction / address / length / value / default length let ai_camera_mode = script.getField('AI_CAMERA_MODE', script); - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 4001; let data_length = 1; @@ -7360,7 +7367,7 @@ let camera_id_for_use = 0; data_buf.push(text[i]); } - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 4200; let data_length = 6 + text_len; @@ -7402,7 +7409,7 @@ let camera_id_for_use = 0; func(sprite, script) { // instruction / address / length / value / default length - let data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; + let data_instruction = INST_WRITE; let data_address = 4250; let data_length = 1; From 245af876abb0911e2fbdfb4d9690a53303c67cf5 Mon Sep 17 00:00:00 2001 From: Jason Kim Date: Wed, 25 Sep 2024 11:10:58 +0900 Subject: [PATCH 2/9] =?UTF-8?q?=EC=96=91=EC=AA=BD=EB=B0=94=ED=80=B4=20?= =?UTF-8?q?=EB=8F=99=EC=8B=9C=20=EC=86=8D=EB=8F=84=EC=A0=9C=EC=96=B4=20?= =?UTF-8?q?=EA=B2=BD=EC=9A=B0=20=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blocks/hardwareLite/block_robotis_robotai_lite.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js b/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js index 101fe83518..a94550831f 100644 --- a/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js +++ b/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js @@ -2094,9 +2094,12 @@ let camera_id_for_use = 0; if (wheelSide == 1) { leftSpeed = wheelSpeed; rightSpeed = 127; // 속도제어 안함 - } else { + } else if (wheelSide == 0) { leftSpeed = 127; // 속도제어 안함 rightSpeed = wheelSpeed; + } else { + leftSpeed = wheelSpeed; + rightSpeed = wheelSpeed; } data_value = leftSpeed + rightSpeed * 256; From b69f262d285543924c60b0e606d6a0f9988790e3 Mon Sep 17 00:00:00 2001 From: Jason Kim Date: Wed, 25 Sep 2024 11:11:27 +0900 Subject: [PATCH 3/9] =?UTF-8?q?AI=20Camera=20UTF-8=20=ED=85=8D=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EB=AC=B8=EA=B5=AC=ED=91=9C=EC=8B=9C=20=EC=A7=80?= =?UTF-8?q?=EC=9B=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hardwareLite/block_robotis_robotai_lite.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js b/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js index a94550831f..b954cc6d8a 100644 --- a/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js +++ b/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js @@ -7337,10 +7337,18 @@ let camera_id_for_use = 0; let x = script.getNumberValue('X', script); let y = script.getNumberValue('Y', script); let text = script.getStringValue('TEXT', script); - let text_len = text.length; let data_buf = []; let i = 0; + // Encode the text as UTF-8 + let encoder = new TextEncoder(); + let utf8Array = encoder.encode(text); + + // utf8Array is now a Uint8Array containing the UTF-8 bytes of the text + let text_len = utf8Array.length; + + if (text_len > 45) text_len = 45; + if (x < -160) { x = 160; } else if (x > 160) { @@ -7367,7 +7375,7 @@ let camera_id_for_use = 0; data_buf.push(0); data_buf.push(0); for (i = 0; i < text_len; i++) { - data_buf.push(text[i]); + data_buf.push(utf8Array[i]); } let data_instruction = INST_WRITE; From bf584bda0ea2e77dbcfd1bacc16ee89366b9b88d Mon Sep 17 00:00:00 2001 From: Jason Kim Date: Wed, 25 Sep 2024 11:11:57 +0900 Subject: [PATCH 4/9] =?UTF-8?q?=EC=BD=94=EC=95=8C=EB=9D=BC=EB=B4=87=20?= =?UTF-8?q?=EB=B8=8C=EB=9D=BC=EC=9A=B0=EC=A0=80=20=EC=97=B0=EA=B2=B0=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- images/hw_lite/robotis_koalabot_lite.png | Bin 0 -> 83622 bytes .../block_robotis_koalabot_lite.js | 6434 +++++++++++++++++ .../metadata_robotis_koalabot_lite.json | 9 + 3 files changed, 6443 insertions(+) create mode 100644 images/hw_lite/robotis_koalabot_lite.png create mode 100644 src/playground/blocks/hardwareLite/block_robotis_koalabot_lite.js create mode 100644 src/playground/blocks/hardwareLite/metadata_robotis_koalabot_lite.json diff --git a/images/hw_lite/robotis_koalabot_lite.png b/images/hw_lite/robotis_koalabot_lite.png new file mode 100644 index 0000000000000000000000000000000000000000..3658a1aff2918acbe43935bb3ec6d047c29bacea GIT binary patch literal 83622 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 Hw=)ip@R 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 literal 0 HcmV?d00001 diff --git a/src/playground/blocks/hardwareLite/block_robotis_koalabot_lite.js b/src/playground/blocks/hardwareLite/block_robotis_koalabot_lite.js new file mode 100644 index 0000000000..1399b83cc9 --- /dev/null +++ b/src/playground/blocks/hardwareLite/block_robotis_koalabot_lite.js @@ -0,0 +1,6434 @@ +'use strict'; + +const INST_NONE = 0; +const INST_READ = 2; +const INST_WRITE = 3; +const INST_DXL_SYNCWRITE = 4; +const INST_DXL_REGWRITE = 5; +const INST_DXL_ACTION = 6; +const INST_BYPASS_READ = 0xa2; +const INST_BYPASS_WRITE = 0xa3; + +const INST_STATUS = 0x55; + +const PACKET_STATE_IDLE = 0; +const PACKET_STATE_RESERVED = 1; +const PACKET_STATE_ID = 2; +const PACKET_STATE_LENGTH_L = 3; +const PACKET_STATE_LENGTH_H = 4; +const PACKET_STATE_DATA = 5; +const PACKET_STATE_CRC_L = 6; +const PACKET_STATE_CRC_H = 7; + +const DEFAULT_DELAY = 50; + +const rxPacket = { + header: [0, 0, 0], + reserved: 0, + id: 0, + cmd: 0, + error: 0, + type: 0, + index: 0, + packetLength: 0, + paramLength: 0, + crc: 0, + crcReceived: 0, + checksum: 0, + checksumReceived: 0, + data: [], +}; + +const addrMap = [ + [0, 4, 302], + [4, 1, 42], + [5, 1, 44], + [6, 1, 45], + [7, 1, 47], + [8, 1, 50], + [9, 1, 51], + [10, 1, 52], + [11, 1, 68], + [12, 2, 70], + [14, 2, 72], + [16, 2, 74], + [18, 2, 76], + [20, 2, 78], + [22, 2, 80], + [24, 2, 82], + [26, 2, 84], + [28, 1, 86], + [29, 1, 87], + [30, 2, 88], + [32, 2, 90], + [34, 1, 112], + [35, 1, 118], + [36, 1, 119], + [37, 1, 122], + [38, 1, 123], + [39, 1, 124], + [40, 1, 125], + [41, 1, 160], + [42, 1, 220], + [43, 2, 360], + [45, 2, 362], + [47, 2, 364], + [49, 2, 366], + [51, 2, 368], + [53, 2, 370], + [55, 1, 372], + [56, 1, 373], + [57, 1, 374], + [58, 1, 375], + [59, 1, 376], + [60, 1, 377], + [61, 1, 378], + [62, 1, 379], + [63, 1, 380], + [64, 1, 381], + [65, 1, 382], + [66, 1, 383], + [67, 1, 500], + [68, 1, 501], + [69, 8, 502], + [77, 1, 700], + [78, 1, 810], + [79, 1, 2134], + [80, 1, 5015], + [81, 1, 5030], + [82, 1, 5031], + [83, 1, 5040], +]; + +const addrMap2 = [ + [153, 1, 4000], + [154, 2, 4003], + [156, 1, 4005], + [157, 1, 4006], + [158, 2, 4009], + [160, 2, 4011], + [162, 2, 4013], + [164, 2, 4015], + [166, 2, 4017], + [168, 2, 4019], + [170, 2, 4021], + [172, 2, 4023], + [174, 2, 4025], + [176, 2, 4027], + [178, 1, 4031], + [179, 1, 4032], + [180, 1, 4033], + [181, 2, 4036], + [183, 2, 4038], + [185, 2, 4040], + [187, 2, 4042], + [189, 2, 4044], + [191, 2, 4046], + [193, 2, 4048], + [195, 2, 4050], +]; + +const crcTable = [ + 0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011, 0x8033, 0x0036, 0x003c, 0x8039, + 0x0028, 0x802d, 0x8027, 0x0022, 0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072, + 0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041, 0x80c3, 0x00c6, 0x00cc, 0x80c9, + 0x00d8, 0x80dd, 0x80d7, 0x00d2, 0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1, + 0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1, 0x8093, 0x0096, 0x009c, 0x8099, + 0x0088, 0x808d, 0x8087, 0x0082, 0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192, + 0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1, 0x01e0, 0x81e5, 0x81ef, 0x01ea, + 0x81fb, 0x01fe, 0x01f4, 0x81f1, 0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2, + 0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151, 0x8173, 0x0176, 0x017c, 0x8179, + 0x0168, 0x816d, 0x8167, 0x0162, 0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132, + 0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101, 0x8303, 0x0306, 0x030c, 0x8309, + 0x0318, 0x831d, 0x8317, 0x0312, 0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321, + 0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371, 0x8353, 0x0356, 0x035c, 0x8359, + 0x0348, 0x834d, 0x8347, 0x0342, 0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1, + 0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2, 0x83a3, 0x03a6, 0x03ac, 0x83a9, + 0x03b8, 0x83bd, 0x83b7, 0x03b2, 0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381, + 0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291, 0x82b3, 0x02b6, 0x02bc, 0x82b9, + 0x02a8, 0x82ad, 0x82a7, 0x02a2, 0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2, + 0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1, 0x8243, 0x0246, 0x024c, 0x8249, + 0x0258, 0x825d, 0x8257, 0x0252, 0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261, + 0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231, 0x8213, 0x0216, 0x021c, 0x8219, + 0x0208, 0x820d, 0x8207, 0x0202, +]; + +const rb100_last_valid_value = []; +let bg_color = 0; +let beat_per_minute = 75; +let camera_id_for_use = 0; + +(function () { + Entry.RobotisKoalabotLite = new (class RobotisKoalabotLite { + constructor() { + this.id = '070C01'; + this.url = 'http://www.robotis.com'; + this.imageName = 'robotis_koalabot_lite.png'; + this.name = 'RobotisKoalabotLite'; + this.blockMenuBlocks = [ + // 주행 제어 + 'robotis_koalabot_lite_drive_simple', + 'robotis_koalabot_lite_drive_advanced', + 'robotis_koalabot_lite_drive_seperate', + 'robotis_koalabot_lite_drive_angle', + 'robotis_koalabot_lite_go_distance', + 'robotis_koalabot_lite_turn_angle', + 'robotis_koalabot_lite_follow_line', + 'robotis_koalabot_lite_stop_at_cross', + 'robotis_koalabot_lite_turn_at_line', + 'robotis_koalabot_lite_drive_stop', + + // 값 블록 + 'robotis_koalabot_lite_cm_ir_value', + 'robotis_koalabot_lite_cm_ir_compare', + 'robotis_koalabot_lite_detectFrontObj', + 'robotis_koalabot_lite_cm_btn_value', + 'robotis_koalabot_lite_cm_joystick_value', + 'robotis_koalabot_lite_mic', + 'robotis_koalabot_lite_detectSound_compare', + 'robotis_koalabot_lite_imu', + 'robotis_koalabot_lite_roll_pitch', + 'robotis_koalabot_lite_distance_value', + 'robotis_koalabot_lite_distance_compare', + 'robotis_koalabot_lite_dxl_value', + 'robotis_koalabot_lite_line_cross_compare', + + // 소리 + 'robotis_koalabot_lite_scale_simple', + 'robotis_koalabot_lite_scale_advanced', + 'robotis_koalabot_lite_rest_simple', + 'robotis_koalabot_lite_rest_advanced', + 'robotis_koalabot_lite_beat_per_minute', + 'robotis_koalabot_lite_Hello', + 'robotis_koalabot_lite_effectSound', + 'robotis_koalabot_lite_record', + 'robotis_koalabot_lite_playRecord', + + // LCD 제어 + 'robotis_koalabot_lite_screen', + 'robotis_koalabot_lite_anim_screen', + 'robotis_koalabot_lite_icon_screen_food_plant', + 'robotis_koalabot_lite_icon_screen_animal_human', + 'robotis_koalabot_lite_icon_screen_object_tool', + 'robotis_koalabot_lite_icon_screen_vehicle_number', + 'robotis_koalabot_lite_text_screen', + 'robotis_koalabot_lite_text_screen_redraw', + 'robotis_koalabot_lite_pixel', + 'robotis_koalabot_lite_LCDColor', + 'robotis_koalabot_lite_LCDBright', + + // LED 제어 + 'robotis_koalabot_lite_cm_led', + 'robotis_koalabot_lite_cm_led_pattern', + + // AI 카메라 값 블록 + 'robotis_koalabot_lite_ai_camera_connection_status', + 'robotis_koalabot_lite_ai_camera_if_detected', + + 'robotis_koalabot_lite_ai_camera_block_value_closest_to_center', + 'robotis_koalabot_lite_ai_camera_arrow_value_closest_to_center', + 'robotis_koalabot_lite_ai_camera_number_of_learned_id', + 'robotis_koalabot_lite_ai_camera_block_value_of_id', + 'robotis_koalabot_lite_ai_camera_arrow_value_of_id', + + 'robotis_koalabot_lite_ai_camera_if_learned_id', + 'robotis_koalabot_lite_ai_camera_if_detected_id_type', + + // AI Camera 제어 + 'robotis_koalabot_lite_ai_camera_set_mode', + 'robotis_koalabot_lite_ai_camera_print_custom_text', + 'robotis_koalabot_lite_ai_camera_clear_custom_text', + ]; + this.portData = { + baudRate: 115200, + dataBits: 8, + parity: 'none', + stopBits: 1, + connectionType: 'bytestream', + bufferSize: 128, + constantServing: true, + }; + this.duration = 15; + this.setZero(); + + this.timeouts = []; + + this.robotisBuffer = []; // buffer to transmit to H/W + this.receiveBuffer = []; // buffer to receive from H/W + this.dataBuffer = []; // saved control table value buffer + + this.packetReceiveState = 0; + this.headerCount = 0; + + this.dxlPositions = []; + + this.pirPir = []; + this.pirTemperature = []; + this.pirHumidity = []; + this.pirBrightness = []; + this.distanceDistance = []; + this.distanceButton = []; + this.distanceBrightness = []; + } + + setZero() { + this.timeouts = []; + this.__removeAllTimeouts(); + this.robotisBuffer = []; + this.robotisBuffer.push([INST_WRITE, 2100, 1, 1]); + camera_id_for_use = 0; + if (Entry.hwLite && Entry.hwLite.serial) { + Entry.hwLite.serial.update(); + } + } + + __removeTimeout(id) { + clearTimeout(id); + const idx = this.timeouts.indexOf(id); + if (idx >= 0) { + this.timeouts.splice(idx, 1); + } + } + + __removeAllTimeouts() { + const timeouts = this.timeouts; + for (const i in timeouts) { + clearTimeout(timeouts[i]); + } + this.timeouts = []; + } + + getMonitorPort() { + return { ...this.sensory, ...this.motoring, ...this.lineTracer }; + } + + writePacket(id, address, length, value) { + if (length > 256) { + console.log(`######### invalid length: ${length}`); + return null; + } + console.log('######### writePacket'); + const packet = []; + let i = 0; + packet.push(0xff); + packet.push(0xff); + packet.push(0xfd); + packet.push(0x00); + packet.push(id); + packet.push(length + 5); + packet.push(0x00); + packet.push(INST_WRITE); + packet.push(this.getLowByte(address)); + packet.push(this.getHighByte(address)); + switch (length) { + case 1: + packet.push(this.getLowByte(value)); + break; + case 2: + packet.push(this.getLowByte(value)); + packet.push(this.getHighByte(value)); + break; + case 4: + packet.push(this.getLowByte(this.getLowWord(value))); + packet.push(this.getHighByte(this.getLowWord(value))); + packet.push(this.getLowByte(this.getHighWord(value))); + packet.push(this.getHighByte(this.getHighWord(value))); + break; + default: + for (i = 0; i < length; i++) { + if (typeof value[i] == 'number') { + packet.push(value[i]); + } else if (typeof value[i] == 'string') { + packet.push(value[i].charCodeAt(0)); + } + } + break; + } + const crc = this.updateCRC(0, packet, packet.length); + packet.push(this.getLowByte(crc)); + packet.push(this.getHighByte(crc)); + return packet; + } + + makeWord(a, b) { + return (a & 0xff) | ((b & 0xff) << 8); + } + + getLowByte(a) { + return a & 0xff; + } + + getHighByte(a) { + return (a >> 8) & 0xff; + } + + getLowWord(a) { + return a & 0xffff; + } + + getHighWord(a) { + return (a >> 16) & 0xffff; + } + + updateCRC(crcAccum, dataBlkPtr, dataBlkSize) { + let i = 0; + let j = 0; + let crc = crcAccum; + + for (j = 0; j < dataBlkSize; j++) { + i = ((crc >> 8) ^ dataBlkPtr[j]) & 0xff; + crc = (crc << 8) ^ crcTable[i]; + } + + return crc; + } + + removeStuffing(buffer, length) { + let i = 0; + let stuffLength = 0; + let index = 0; + + for (i = 0; i < length; i++) { + if (i >= 2) { + if (buffer[i - 2] == 0xff && buffer[i - 1] == 0xff && buffer[i] == 0xfd) { + i++; + stuffLength++; + } + } + buffer[index++] = buffer[i]; + } + + return stuffLength; + } + + postCallReturn(script, data, ms) { + /* + if (data == null) { + Entry.engine.isContinue = false; + return script.callReturn(); + } else if (data.length == 0) { + Entry.engine.isContinue = false; + return script.callReturn(); + } + */ + if (!script.isStart) { + script.isStart = true; + script.timeFlag = 1; + for (let i = 0; i < data.length; i++) { + this.robotisBuffer.push(data[i]); + } + //delay ms + setTimeout(() => { + script.timeFlag = 0; + }, ms); + return script; + } else if (script.timeFlag) { + return script; + } else { + delete script.isStart; + delete script.timeFlag; + Entry.engine.isContinue = false; + return script.callReturn(); + } + } + + setLanguage() { + return { + ko: { + template: { + // 주행 제어 + robotis_koalabot_lite_drive_simple: '속도 %1 (으)로 %2 하기 %3', + robotis_koalabot_lite_drive_advanced: + '왼쪽바퀴 %1 속도로 %2, 오른쪽바퀴 %3 속도로 %4 %5', + robotis_koalabot_lite_drive_seperate: + '%1 바퀴 %2 속도로 %3 으로 회전하기 %4', + robotis_koalabot_lite_drive_angle: + '양쪽 바퀴 %1 도만큼 %2 으로 회전하기 %3', + robotis_koalabot_lite_go_distance: '%1 cm %2 하기 %3', + robotis_koalabot_lite_turn_angle: '로봇 %1 도 %2 하기%3', + robotis_koalabot_lite_follow_line: '%1 속도로 라인 따라가기 %2', + robotis_koalabot_lite_stop_at_cross: '교차로 %1 에서 멈추기 %2', + robotis_koalabot_lite_turn_at_line: '교차로에서 %1 하고 멈추기 %2', + robotis_koalabot_lite_drive_stop: '정지하기 %1', + + // 값 블록 + robotis_koalabot_lite_cm_ir_value: '%1 적외선센서 값', + robotis_koalabot_lite_cm_ir_compare: '%1 적외선센서 값이 %2 보다 %3', + robotis_koalabot_lite_detectFrontObj: '%1의 앞에 물체가 있으면', + robotis_koalabot_lite_cm_btn_value: '로봇의 %1 버튼을 눌렀을 때', + robotis_koalabot_lite_cm_joystick_value: + '로봇의 노랑 조이스틱 위치가 %1 이면', + robotis_koalabot_lite_mic: '소리의 크기(dB)', + robotis_koalabot_lite_detectSound_compare: '소리가 로봇의 %1에서 들리면', + robotis_koalabot_lite_imu: '%1축의 %2 값', + robotis_koalabot_lite_roll_pitch: '로봇의 %1 값', + robotis_koalabot_lite_distance_value: '%1 값', + robotis_koalabot_lite_distance_compare: '%1 값이 %2보다 %3', + robotis_koalabot_lite_line_cross_compare: '교차로 모양이 %1이면', + robotis_koalabot_lite_dxl_value: '%1의 각도값', + + // 소리 + robotis_koalabot_lite_scale_simple: '옥타브%1 로 %2 음을 %3로 연주하기 %4', + robotis_koalabot_lite_scale_advanced: + '옥타브%1 로 %2 음을 %3박자 연주하기 %4', + robotis_koalabot_lite_rest_simple: '%1 %2', + robotis_koalabot_lite_rest_advanced: '쉼표 %1 박자 %2', + robotis_koalabot_lite_beat_per_minute: '연주 빠르기를 %1 (으)로 정하기 %2', + robotis_koalabot_lite_Hello: '로봇 %1 말하기 %2', + robotis_koalabot_lite_effectSound: '효과음 %1 재생하기 %2', + robotis_koalabot_lite_record: '소리 %1번에 녹음하기 %2', + robotis_koalabot_lite_playRecord: '소리 %1번을 재생하기 %2', + + // LCD 제어 + robotis_koalabot_lite_screen: '화면 표정을 %1 %2 (으)로 정하기 %3', + robotis_koalabot_lite_anim_screen: + '화면 애니메이션을 %1 %2 (으)로 정하기 %3', + robotis_koalabot_lite_icon_screen_food_plant: + '화면에 [음식/식물]중 %1 (%2, %3)위치에 %4 크기로 표시 %5', + robotis_koalabot_lite_icon_screen_animal_human: + '화면에 [동물/사람]중 %1 (%2, %3)위치에 %4 크기로 표시 %5', + robotis_koalabot_lite_icon_screen_object_tool: + '화면에 [물건/도구]중 %1 (%2, %3)위치에 %4 크기로 표시 %5', + robotis_koalabot_lite_icon_screen_vehicle_number: + '화면에 [탈것/숫자]중 %1 (%2, %3)위치에 %4 크기로 표시 %5', + robotis_koalabot_lite_text_screen: + '화면에 %1 (%2, %3)위치에 %4 로 %5으로 표시 %6', + robotis_koalabot_lite_text_screen_redraw: + '화면에 %1 (%2, %3)위치에 %4으로 새로 표시 %5', + robotis_koalabot_lite_pixel: '화면 (%1, %2)위치에 %3 색 점 표시 %4', + robotis_koalabot_lite_LCDBright: '화면 밝기를 %1 (으)로 정하기 %2', + robotis_koalabot_lite_LCDColor: '화면 색상을 %1 (으)로 정하기 %2', + + // LED 제어 + robotis_koalabot_lite_cm_led: '로봇 %1 LED %2 %3', + robotis_koalabot_lite_cm_led_pattern: 'LED %1 %2로 깜박이기 %3', + + // AI Camera 값 블록 + robotis_koalabot_lite_ai_camera_connection_status: 'AI 카메라 %1이면', + robotis_koalabot_lite_ai_camera_if_detected: 'AI 카메라 %1 이/가 표시되면', + + robotis_koalabot_lite_ai_camera_block_value_closest_to_center: + 'AI 카메라 화면 중앙과 가장 가까운 사각형의 %1', + robotis_koalabot_lite_ai_camera_arrow_value_closest_to_center: + 'AI 카메라 화면 중앙과 가장 가까운 화살표의 %1', + robotis_koalabot_lite_ai_camera_number_of_learned_id: + 'AI 카메라 학습한 ID의 갯수', + robotis_koalabot_lite_ai_camera_block_value_of_id: + 'AI 카메라 감지된 ID가 %1인 사각형의 %2', + robotis_koalabot_lite_ai_camera_arrow_value_of_id: + 'AI 카메라 감지된 ID가 %1인 화살표의 %2', + + robotis_koalabot_lite_ai_camera_if_learned_id: + 'AI 카메라 ID가 %1인 데이터를 학습하였으면', + robotis_koalabot_lite_ai_camera_if_detected_id_type: + 'AI 카메라 ID가 %1인 %2데이터를 인식하였으면', + + // AI 카메라 제어 + robotis_koalabot_lite_ai_camera_set_mode: + 'AI 카메라 모드를 %1(으)로 설정 %2', + robotis_koalabot_lite_ai_camera_print_custom_text: + 'AI 카메라 화면 위치 (%1,%2)에 %3를 보여주기%4', + robotis_koalabot_lite_ai_camera_clear_custom_text: + 'AI 카메라 화면의 글 지우기 %1', + }, + Helper: { + // 주행 제어 + robotis_koalabot_lite_drive_simple: + '코알라봇을 지정한 속도와 방향으로 주행\n속도범위: -100 ~ 100\n속도단위: %', + robotis_koalabot_lite_drive_advanced: + '코알라봇의 좌,우 바퀴를 각각 지정한 속도와 방향으로 회전\n속도범위: -100 ~ 100\n속도단위: %', + robotis_koalabot_lite_drive_seperate: + '코알라봇의 지정한 바퀴를 지정한 속도와 방향으로 회전\n속도범위: -100 ~ 100\n속도단위: %', + robotis_koalabot_lite_drive_angle: + '코알라봇의 지정한 바퀴를 지정한 방향과 지정한 각도만큼 회전\n각도범위: -5760 ~ 5760\n각도단위: 도', + robotis_koalabot_lite_go_distance: + '지정거리만큼 앞 또는 뒤로 이동\n거리범위: -1000 ~ 1000\n거리단위: mm', + robotis_koalabot_lite_turn_angle: + '지정한 각도와 방향으로 제자리회전\n각도범위: -360 ~ 360\n각도단위: 도', + robotis_koalabot_lite_follow_line: + '지정한 수준의 속도로 라인 따라가기 시작', + robotis_koalabot_lite_stop_at_cross: '지정한 교차로에서 멈추기', + robotis_koalabot_lite_turn_at_line: '교차로에서 지정한 회전을 하고 멈추기', + robotis_koalabot_lite_drive_stop: '코알라봇 정지하기', + + // 값 블록 + robotis_koalabot_lite_cm_ir_value: + '지정한 번호의 IR 센서 값(범위: 0 ~ 200)', + robotis_koalabot_lite_cm_ir_compare: + "지정한 번호의 IR 센서 값과 지정한 값의 비교식이 맞으면 '참', 아니면 '거짓'으로 판단합니다.", + robotis_koalabot_lite_detectFrontObj: + "지정한 센서 앞에 물체가 감지되면 '참', 아니면 '거짓'으로 판단합니다.", + robotis_koalabot_lite_cm_btn_value: + "지정한 버튼이 눌렸다가 해제되면 '참', 아니면 '거짓'으로 판단합니다.", + robotis_koalabot_lite_cm_joystick_value: + "조이스틱 위치가 지정한 상태이면 '참', 아니면 '거짓'으로 판단합니다..", + robotis_koalabot_lite_mic: + '마이크로 감지된 소리의 세기를 데시벨(dB)로 표시합니다.', + robotis_koalabot_lite_detectSound_compare: + "소리가 나는 방향이 지정한 방향과 동일하면 '참', 아니면 '거짓'으로 판단합니다.", + robotis_koalabot_lite_imu: + '지정한 축의 지정한 가속도센서/자이로센서의 값\n범위: -100 ~ 100', + robotis_koalabot_lite_roll_pitch: + 'roll/pitch 값\nroll: -180° ~ 180°, pitch: -90° ~ 90°', + robotis_koalabot_lite_distance_value: + '지정한 센서값\n거리범위: 0 ~ 1000mm\n밝기범위: 0 ~ 100%\n버튼센서: 0(눌리지 않음) / 1(눌림)', + robotis_koalabot_lite_distance_compare: + "지정한 센서값의 지정한 수식이 맞으면 '참', 아니면 '거짓'으로 판단합니다.", + robotis_koalabot_lite_line_cross_compare: + "지정한 교차로 모양이면 '참', 아니면 '거짓'으로 판단합니다.", + robotis_koalabot_lite_dxl_value: + '지정한 모터의 위치 각도값\n범위: -180° ~ 180°', + + // 소리 + robotis_koalabot_lite_scale_simple: '지정한 옥타브, 음계, 음표로 연주하기', + robotis_koalabot_lite_scale_advanced: + '지정한 옥타브, 음계, 박자로 연주하기', + robotis_koalabot_lite_rest_simple: '지정한 쉼표 쉬기', + robotis_koalabot_lite_rest_advanced: '지정한 박자 쉬기', + robotis_koalabot_lite_beat_per_minute: + '연주 빠르기를 지정하기 (BPM)\n범위: 10 ~ 600', + robotis_koalabot_lite_Hello: '로봇이 지정한 말소리를 재생하기', + robotis_koalabot_lite_effectSound: '로봇이 지정한 효과음을 재생하기', + robotis_koalabot_lite_record: '지정번호 보관함에 녹음하여 저장하기', + robotis_koalabot_lite_playRecord: '지정번호 보관함의 녹음음성을 재생하기', + + // LCD 제어 + robotis_koalabot_lite_screen: '제어기 화면배경의 캐릭터와 표정을 설정', + robotis_koalabot_lite_anim_screen: + '제어기 화면 애니메이션의 캐릭터와 표정을 설정', + robotis_koalabot_lite_icon_screen_food_plant: + '화면에 [음식/식물]중 특정 아이콘을 표시할 위치와 크기를 설정\nX좌표: -160 ~ 160\nY좌표: -120 ~ 120\n크기: 0 ~ 200', + robotis_koalabot_lite_icon_screen_animal_human: + '화면에 [동물/사람]중 특정 아이콘을 표시할 위치와 크기를 설정\nX좌표: -160 ~ 160\nY좌표: -120 ~ 120\n크기: 0 ~ 200', + robotis_koalabot_lite_icon_screen_object_tool: + '화면에 [물건/도구]중 특정 아이콘을 표시할 위치와 크기를 설정\nX좌표: -160 ~ 160\nY좌표: -120 ~ 120\n크기: 0 ~ 200', + robotis_koalabot_lite_icon_screen_vehicle_number: + '화면에 [탈것/숫자]중 특정 아이콘을 표시할 위치와 크기를 설정\nX좌표: -160 ~ 160\nY좌표: -120 ~ 120\n크기: 0 ~ 200', + robotis_koalabot_lite_text_screen: + '화면에 지정한 문구를 표시할 위치와 폰트크기, 색상을 설정\nX좌표: -160 ~ 160\nY좌표: -120 ~ 120', + robotis_koalabot_lite_text_screen_redraw: + '화면에 지정한 문구를 새롭게(문구의 배경 지움) 표시할 위치와 색상을 설정\nX좌표: -160 ~ 160\nY좌표: -120 ~ 120\n크기: 0 ~ 200', + robotis_koalabot_lite_pixel: + '화면에 표시할 점의 위치와 색상을 설정\nX좌표: -160 ~ 160\nY좌표: -120 ~ 120', + robotis_koalabot_lite_LCDBright: '화면 밝기를 설정\n밝기범위: 1% ~ 100%', + robotis_koalabot_lite_LCDColor: '화면 색상을 설정', + + // LED 제어 + robotis_koalabot_lite_cm_led: '제어기의 지정한 LED를 켜거나 끄기', + robotis_koalabot_lite_cm_led_pattern: '제어기의 LED의 깜박임 패턴 설정', + + // AI Camera 값 블록 + robotis_koalabot_lite_ai_camera_connection_status: + "AI 카메라가 연결된 상태이면 '참', 아니면 '거짓'으로 판단합니다.", + robotis_koalabot_lite_ai_camera_if_detected: + "AI 카메라의 LCD화면에 선택한 기호(사각형/화살표)가 표시되면 '참', 아니면 '거짓'으로 판단합니다.", + + robotis_koalabot_lite_ai_camera_block_value_closest_to_center: + 'AI 카메라 화면 중앙과 가장 가까운 사각형의 X좌표/Y좌표/너비/높이/학습ID', + robotis_koalabot_lite_ai_camera_arrow_value_closest_to_center: + 'AI 카메라 화면 중앙과 가장 가까운 화살표의 시작점X좌표/시작점Y좌표/끝점X좌표/끝점Y좌표/학습ID', + robotis_koalabot_lite_ai_camera_number_of_learned_id: + 'AI 카메라가 학습한 ID의 갯수', + robotis_koalabot_lite_ai_camera_block_value_of_id: + 'AI 카메라가 감지한 사각형중 지정한 ID의 사각형의 X좌표/Y좌표/너비/높이', + robotis_koalabot_lite_ai_camera_arrow_value_of_id: + 'AI 카메라가 감지한 화살표중 지정한 ID의 화살표의 시작점X좌표/시작점Y좌표/끝점X좌표/끝점Y좌표', + + robotis_koalabot_lite_ai_camera_if_learned_id: + "AI 카메라가 지정한 ID인 데이터를 학습하였으면 '참', 아니면 '거짓'으로 판단합니다.", + robotis_koalabot_lite_ai_camera_if_detected_id_type: + "AI 카메라가 지정한 ID인 지정한 데이터(사각형/화살표)를 학습하였으면 '참', 아니면 '거짓'으로 판단합니다.", + + // AI 카메라 제어 + robotis_koalabot_lite_ai_camera_set_mode: 'AI 카메라의 모드를 설정', + robotis_koalabot_lite_ai_camera_print_custom_text: + 'AI 카메라 화면의 지정한 위치에 지정한 문구 출력\nX좌표: -160 ~ 160\nY좌표: -120 ~ 120', + robotis_koalabot_lite_ai_camera_clear_custom_text: + 'AI 카메라 화면에 표시한 모든 문구 지우기', + }, + Blocks: { + robotis_red: '빨강', + robotis_orange: '주황', + robotis_yellow: '노랑', + robotis_green: '초록', + robotis_blue: '파랑', + robotis_brown: '갈색', + robotis_black: '검정', + robotis_white: '흰색', + robotis_left: '왼쪽', + robotis_center: '중앙', + robotis_right: '오른쪽', + robotis_both: '양쪽', + robotis_rgee: '알쥐', + robotis_rla: '알라', + robotis_kkokdu: '꼭두', + robotis_korean1: '안녕하세요', + robotis_korean2: '반가워요', + robotis_korean3: '알겠어요', + robotis_korean4: '아니에요', + robotis_korean5: '모르겠어요', + robotis_korean6: '좋아요', + robotis_korean7: '싫어요', + robotis_korean8: '이름을말하세요', + robotis_korean9: '무엇을도와줄까?', + robotis_korean10: '잘했어', + robotis_korean11: '괜찮아', + robotis_korean12: '다시해보자', + robotis_korean13: '고마워', + robotis_korean14: '다시말해줄래?', + robotis_korean15: '최고야!', + robotis_korean16: '신나요', + robotis_korean17: '즐거워요', + robotis_korean18: '미안해요', + robotis_korean19: '화나요', + robotis_korean20: '부끄러워요', + robotis_korean21: '무서워요', + robotis_korean22: '속상해요', + robotis_korean23: '사랑해요', + robotis_korean24: '예뻐요', + robotis_korean25: '신기해요', + robotis_korean26: '초조해요', + robotis_korean27: '앞으로가자', + robotis_korean28: '뒤로가자', + robotis_korean29: '일어나자', + robotis_korean30: '넘어졌네?', + robotis_korean31: '오예', + robotis_korean32: '아싸', + robotis_korean33: '어머', + robotis_korean34: '이런', + robotis_korean35: '오호', + robotis_korean36: '하하하', + robotis_korean37: '호호호', + robotis_korean38: '졸려', + robotis_korean39: '자장가를들려줘', + robotis_korean40: '안녕', + robotis_korean41: '배고프다', + robotis_korean42: '도토리땡긴다', + robotis_korean43: '아.씻고싶어', + robotis_korean44: '비누목욕시간이야', + robotis_korean45: '심심한데', + robotis_korean46: '간식먹을까', + robotis_korean47: '아파요', + robotis_korean48: '약은없나요?', + robotis_korean49: '어디로가야하지?', + robotis_korean50: '와아도착이다', + robotis_korean51: '왼쪽으로가자', + robotis_korean52: '오른쪽으로가자', + robotis_korean53: '깜짝이야', + robotis_korean54: '찾았다', + robotis_korean55: '여긴없네', + robotis_korean56: '혹시나불렀어?', + robotis_korean57: '내려주세요', + robotis_korean58: '앗', + robotis_korean59: '힝', + robotis_korean60: '이익', + robotis_dog: '개', + robotis_frog: '개구리', + robotis_cat: '고양이', + robotis_chicken: '닭', + robotis_tiger: '호랑이', + robotis_mouse: '쥐', + robotis_ambul: '앰뷸런스', + robotis_Horn: '경적(빵빵)', + robotis_siren: '사이렌(경찰차)', + robotis_whistle: '호루라기', + robotis_gun: '총소리', + robotis_clap: '박수소리', + robotis_melody1: '멜로디1', + robotis_melody2: '멜로디2', + robotis_melody3: '멜로디3', + robotis_melody4: '멜로디4', + robotis_forward: '앞으로', + robotis_backward: '뒤로', + robotis_acceleration: '가속도', + robotis_gyro: '자이로', + robotis_run: '실행', + robotis_cancel: '취소', + robotis_push: '눌림', + robotis_notPush: '안눌림', + robotis_play: '연주', + robotis_rest: '쉼표', + robotis_face01: '와하하', + robotis_face02: '싱글벙글', + robotis_face03: '큭큭큭', + robotis_face04: '냠냠', + robotis_face05: '겁먹음', + robotis_face06: '답답', + robotis_face07: '갸우뚱', + robotis_face08: '어벙벙', + robotis_face09: '고함', + robotis_face10: '화남', + robotis_face11: '킁킁(왼쪽)', + robotis_face12: '킁킁(오른쪽)', + robotis_face13: '킁킁(아래)', + robotis_face14: '안심', + robotis_face15: '기절', + robotis_face16: '헤롱헤롱', + robotis_face17: '하품', + robotis_face18: '졸림', + robotis_face19: '잠듦', + robotis_face20: '마음앓이', + robotis_face21: '폭풍눈물', + robotis_face22: '목욕', + robotis_face23: '햐트뿅뿅', + + robotis_pattern1: '패턴1', + robotis_pattern2: '패턴2', + robotis_pattern3: '패턴3', + robotis_moveF: '전진', + robotis_moveB: '후진', + robotis_moveL: '좌회전', + robotis_moveR: '우회전', + robotis_moveU: 'U턴', + robotis_moveL_in_place: '제자리 좌회전', + robotis_moveR_in_place: '제자리 우회전', + robotis_moveU_in_place: '제자리 U턴', + robotis_moveRG1: '일어서기', + robotis_moveRG2: '앉기', + robotis_moveRG3: '발버둥', + robotis_moveRG4: '발들기', + robotis_fast: '빠른', + robotis_normal: '보통', + robotis_slow: '느린', + robotis_stop: '정지', + robotis_roll: '좌우 회전각 (roll)', + robotis_pitch: '앞뒤 회전각 (pitch)', + robotis_direction_forward: '전진방향', + robotis_direction_backward: '후진방향', + robotis_stMotion1: '기본자세', + robotis_stMotion2: '전진', + robotis_stMotion3: '우전진', + robotis_stMotion4: '좌전진', + robotis_stMotion5: '후진', + robotis_stMotion6: '오른쪽으로', + robotis_stMotion7: '왼쪽으로', + robotis_stMotion8: '우회전', + robotis_stMotion9: '좌회전', + robotis_spMotion1: '오른손 들기', + robotis_spMotion2: '오른손 내리기', + robotis_spMotion3: '왼손 들기', + robotis_spMotion4: '왼손 내리기', + robotis_spMotion5: '양손 들기', + robotis_spMotion6: '양손 내리기', + robotis_spMotion7: '뒤로 넘어지기', + robotis_spMotion8: '앞으로 넘어지기', + robotis_spMotion9: '앞으로 일어서기', + robotis_spMotion10: '뒤로 일어서기', + robotis_spMotion11: '방어', + robotis_spMotion12: '공격1', + robotis_spMotion13: '공격2', + robotis_spMotion14: '공격3', + robotis_spMotion15: '공격4', + robotis_screen1: '가위', + robotis_screen2: '바위', + robotis_screen3: '보', + robotis_icon_food_plant_1: '우유', + robotis_icon_food_plant_2: '나무', + robotis_icon_food_plant_3: '스프', + robotis_icon_food_plant_4: '케익', + robotis_icon_food_plant_5: '물', + robotis_icon_food_plant_6: '주스', + robotis_icon_food_plant_7: '당근', + robotis_icon_food_plant_8: '사과', + robotis_icon_food_plant_9: '오렌지', + robotis_icon_food_plant_10: '고기', + robotis_icon_food_plant_11: '화분', + robotis_icon_food_plant_12: '장미', + robotis_icon_food_plant_13: '포도', + robotis_icon_food_plant_14: '감자', + robotis_icon_food_plant_15: '사탕', + robotis_icon_food_plant_16: '치즈', + robotis_icon_food_plant_17: '식빵', + robotis_icon_food_plant_18: '꽃들', + robotis_icon_food_plant_19: '커피', + robotis_icon_food_plant_20: '튤립', + robotis_icon_food_plant_21: '바나나', + robotis_icon_food_plant_22: '과일들', + robotis_icon_food_plant_23: '햄버거', + robotis_icon_food_plant_24: '피자', + robotis_icon_animal_human_1: '시바견', + robotis_icon_animal_human_2: '강아지', + robotis_icon_animal_human_3: '곰', + robotis_icon_animal_human_4: '새', + robotis_icon_animal_human_5: '오리', + robotis_icon_animal_human_6: '사자', + robotis_icon_animal_human_7: '호랑이', + robotis_icon_animal_human_8: '말', + robotis_icon_animal_human_9: '양', + robotis_icon_animal_human_10: '상어1(왼쪽)', + robotis_icon_animal_human_11: '상어1(오른쪽)', + robotis_icon_animal_human_12: '상어2(왼쪽)', + robotis_icon_animal_human_13: '상어2(오른쪽)', + robotis_icon_animal_human_14: '물고기1', + robotis_icon_animal_human_15: '물고기2', + robotis_icon_animal_human_16: '물고기3', + robotis_icon_animal_human_17: '문어', + robotis_icon_animal_human_18: '원숭이', + robotis_icon_animal_human_19: '닭', + robotis_icon_animal_human_20: '돼지', + robotis_icon_animal_human_21: '사람(살찐)', + robotis_icon_animal_human_22: '사람(수영복)', + robotis_icon_animal_human_23: '아기', + robotis_icon_animal_human_24: '사람(달리는)', + robotis_icon_animal_human_25: '사람(노래하는)', + robotis_icon_animal_human_26: '사람(앉은)', + robotis_icon_animal_human_27: '사람(화난)', + robotis_icon_animal_human_28: '사람(만세)', + robotis_icon_animal_human_29: '왕', + robotis_icon_animal_human_30: '왕자', + robotis_icon_animal_human_31: '공주', + robotis_icon_animal_human_32: '요리사', + robotis_icon_animal_human_33: '의사', + robotis_icon_animal_human_34: '간호사', + robotis_icon_object_tool_1: '가방', + robotis_icon_object_tool_2: '상자', + robotis_icon_object_tool_3: '머그컵', + robotis_icon_object_tool_4: '모자(중절모)', + robotis_icon_object_tool_5: '모자(캡모자)', + robotis_icon_object_tool_6: '열쇠', + robotis_icon_object_tool_7: '장난감', + robotis_icon_object_tool_8: '책', + robotis_icon_object_tool_9: '곰인형', + robotis_icon_object_tool_10: '드럼', + robotis_icon_object_tool_11: '메모장', + robotis_icon_object_tool_12: '볼펜', + robotis_icon_object_tool_13: '책상', + robotis_icon_object_tool_14: '테이블', + robotis_icon_object_tool_15: '의자', + robotis_icon_object_tool_16: '침대', + robotis_icon_object_tool_17: '텐트', + robotis_icon_object_tool_18: '접시', + robotis_icon_object_tool_19: '축구공', + robotis_icon_object_tool_20: '종', + robotis_icon_object_tool_21: '손목시계', + robotis_icon_object_tool_22: '신발', + robotis_icon_object_tool_23: '전등', + robotis_icon_object_tool_24: '라디오', + robotis_icon_object_tool_25: '지폐', + robotis_icon_object_tool_26: '자', + robotis_icon_object_tool_27: '카메라', + robotis_icon_object_tool_28: '스푼', + robotis_icon_object_tool_29: '건반', + robotis_icon_object_tool_30: '달력', + robotis_icon_object_tool_31: '칼', + robotis_icon_object_tool_32: '풍선', + robotis_icon_object_tool_33: '물통', + robotis_icon_object_tool_34: '나무막대(세로)', + robotis_icon_object_tool_35: '나무막대(가로)', + robotis_icon_object_tool_36: '낚시바늘', + robotis_icon_vehicle_number_1: '자동차', + robotis_icon_vehicle_number_2: '버스', + robotis_icon_vehicle_number_3: '트럭', + robotis_icon_vehicle_number_4: '지프', + robotis_icon_vehicle_number_5: '자전거', + robotis_icon_vehicle_number_6: '전철', + robotis_icon_vehicle_number_7: '기차', + robotis_icon_vehicle_number_8: '비행기', + robotis_icon_vehicle_number_9: '전투기(세로)', + robotis_icon_vehicle_number_10: '전투기(가로)', + robotis_icon_vehicle_number_11: '로켓', + robotis_icon_vehicle_number_12: '어선', + robotis_icon_vehicle_number_13: '여객선', + robotis_icon_vehicle_number_14: '잠수항(왼쪽)', + robotis_icon_vehicle_number_15: '잠수함(오른쪽)', + robotis_icon_vehicle_number_16: '비행기(왼쪽)', + robotis_icon_vehicle_number_17: '비행기(오른쪽)', + robotis_icon_vehicle_number_18: '비행기(윗쪽)', + robotis_icon_vehicle_number_19: '우주선(왼쪽)', + robotis_icon_vehicle_number_20: '우주선(오른쪽)', + robotis_icon_vehicle_number_21: '우주선(윗쪽)', + robotis_icon_vehicle_number_22: '주사위(1)', + robotis_icon_vehicle_number_23: '주사위(2)', + robotis_icon_vehicle_number_24: '주사위(3)', + robotis_icon_vehicle_number_25: '주사위(4)', + robotis_icon_vehicle_number_26: '주사위(5)', + robotis_icon_vehicle_number_27: '주사위(6)', + robotis_icon_vehicle_number_28: '0', + robotis_icon_vehicle_number_29: '1', + robotis_icon_vehicle_number_30: '2', + robotis_icon_vehicle_number_31: '3', + robotis_icon_vehicle_number_32: '4', + robotis_icon_vehicle_number_33: '5', + robotis_icon_vehicle_number_34: '6', + robotis_icon_vehicle_number_35: '7', + robotis_icon_vehicle_number_36: '8', + robotis_icon_vehicle_number_37: '9', + robotis_icon_vehicle_number_38: '10', + robotis_speed_fast: '빠른 속도', + robotis_speed_midium: '중간 속도', + robotis_speed_slow: '느린 속도', + robotis_clockwise: '시계방향', + robotis_counterclockwise: '반시계방향', + robotis_up: '들기', + robotis_down: '내리기', + robotis_if_greater: '크면', + robotis_if_smaller: '작으면', + robotis_if_equal: '같으면', + robotis_front_right: '앞 오른쪽', + robotis_front_left: '앞 왼쪽', + robotis_bottom_right: '아래 오른쪽', + robotis_bottom_left: '아래 왼쪽', + robotis_side_right: '우측', + robotis_side_left: '좌측', + robotis_front_ir_sensor: '적외선센서', + robotis_distance_sensor: '거리센서', + robotis_front: '앞', + robotis_right: '오른쪽', + robotis_left_wheel: '왼쪽바퀴', + robotis_right_wheel: '오른쪽바퀴', + // https://namu.wiki/w/%EC%9D%8C%ED%91%9C + robotis_beat_sound_8th_note: '8분음표 (♪)', + robotis_beat_sound_dotted_8th_note: '점8분음표 (♪.)', + robotis_beat_sound_quarter_note: '4분음표 (♩)', + robotis_beat_sound_dotted_quarter_note: '점4분음표 (♩.)', + robotis_beat_sound_half_note: '2분음표 (𝅗𝅥)', + robotis_beat_sound_dotted_half_note: '점2분음표 (𝅗𝅥.)', + robotis_beat_sound_whole_note: '온음표 (𝅝)', + robotis_beat_sound_dotted_note: '점온음표 (𝅝.)', + robotis_beat_rest_8th_note: '8분쉼표 (𝄾)', + robotis_beat_rest_dotted_8th_note: '점8분쉼표 (𝄾.)', + robotis_beat_rest_quarter_note: '4분쉼표 (𝄽)', + robotis_beat_rest_dotted_quarter_note: '점4분쉼표 (𝄽.)', + robotis_beat_rest_half_note: '2분쉼표 (𝄼)', + robotis_beat_rest_dotted_half_note: '점2분쉼표 (𝄼˙)', + robotis_beat_rest_whole_note: '온쉼표 (𝄻)', + robotis_beat_rest_dotted_note: '점온쉼표 (𝄻˙)', + robotis_line_cross_type_0: '|', + robotis_line_cross_type_1: ' (공백)', + robotis_line_cross_type_5: '🞣', + robotis_line_cross_type_6: '⏉', + robotis_line_cross_type_7: '⊣', + robotis_line_cross_type_8: '⊢', + robotis_line_cross_type_9: '⏋', + robotis_line_cross_type_10: '⎾', + robotis_line_cross_type_11: '¦', + robotis_line_cross_type_12: '︙', + + robotis_connected: '연결', + robotis_disconnected: '없음', + robotis_ai_camera_mode_face_recognition: '얼굴인식', + robotis_ai_camera_mode_object_tracking: '물체추적', + robotis_ai_camera_mode_object_recognition: '물체인식', + robotis_ai_camera_mode_line_tracking: '라인인식', + robotis_ai_camera_mode_color_recognition: '색상인식', + robotis_ai_camera_mode_tag_recognition: '태그인식', + robotis_ai_camera_mode_object_classification: '물체분류', + robotis_ai_camera_block: '사각형', + robotis_ai_camera_arrow: '화살표', + robotis_ai_camera_center_block_center_x: '중심 X좌표', + robotis_ai_camera_center_block_center_y: '중심 Y좌표', + robotis_ai_camera_center_block_width: '너비', + robotis_ai_camera_center_block_height: '높이', + robotis_ai_camera_center_leared_id: '학습ID', + robotis_ai_camera_center_arrow_origin_x: '시작점 X좌표', + robotis_ai_camera_center_arrow_origin_y: '시작점 Y좌표', + robotis_ai_camera_center_arrow_target_x: '끝점 X좌표', + robotis_ai_camera_center_arrow_target_y: '끝점 Y좌표', + }, + }, + en: { + template: { + // 주행 제어 + robotis_koalabot_lite_drive_simple: 'Move %2 with velocity %1 %3', + robotis_koalabot_lite_drive_advanced: + 'Left wheel %2 with velocity %1, right wheel %4 with velocity %3 %5', + robotis_koalabot_lite_drive_seperate: + '%1 wheel rotate %3 with velocity %2 %4', + robotis_koalabot_lite_drive_angle: 'Both wheels rotate %1 degree %2 %3', + robotis_koalabot_lite_go_distance: 'Moves %2 %1 cm %3', + robotis_koalabot_lite_turn_angle: 'Rotates %1 degree(s) %2 in place %3', + robotis_koalabot_lite_follow_line: 'Follow line with %1 speed %2', + robotis_koalabot_lite_stop_at_cross: 'Stop at cross %1 %2', + robotis_koalabot_lite_turn_at_line: '%1 at cross and stop %2', + robotis_koalabot_lite_drive_stop: 'Stop %1', + + // 값 블록 + robotis_koalabot_lite_cm_ir_value: 'Value of %1 IR Sensor', + robotis_koalabot_lite_cm_ir_compare: + 'If the number %1 IR sensor value is %3 than %2', + robotis_koalabot_lite_detectFrontObj: + 'If there is an object in front of %1', + robotis_koalabot_lite_cm_btn_value: "When the robot's %1 button is pressed", + robotis_koalabot_lite_cm_joystick_value: + "If the robot's yellow joystick position is %1", + robotis_koalabot_lite_mic: 'MIC volume(dB)', + robotis_koalabot_lite_detectSound_compare: + 'If sound is detected from %1 of the robot', + robotis_koalabot_lite_imu: "%1 axis' %2 value", + robotis_koalabot_lite_roll_pitch: '%1 value of the controller', + robotis_koalabot_lite_distance_value: '%1 value', + robotis_koalabot_lite_distance_compare: 'If %1 value is %3 than %2', + robotis_koalabot_lite_line_cross_compare: 'If the type of cross is %1', + robotis_koalabot_lite_dxl_value: 'The angle of ID %1', + + // 소리 + robotis_koalabot_lite_scale_simple: + 'Play the note %2 as %3 in octave %1 %4', + robotis_koalabot_lite_scale_advanced: + 'Play the note %2 in octave %1 for %3 beat %4', + robotis_koalabot_lite_rest_simple: '%1 %2', + robotis_koalabot_lite_rest_advanced: 'Rest %1 beat %2', + robotis_koalabot_lite_beat_per_minute: 'Set playing speed to %1 %2', + robotis_koalabot_lite_Hello: 'Robot speaks %1 %2', + robotis_koalabot_lite_effectSound: 'Play sound effect %1 %2', + robotis_koalabot_lite_record: 'Record to sound slot %1 %2', + robotis_koalabot_lite_playRecord: 'Play sound from slot %1 %2', + + // LCD 제어 + robotis_koalabot_lite_screen: 'Set screen expression to %1 %2 %3', + robotis_koalabot_lite_anim_screen: 'Set screen animation to %1 %2 %3', + robotis_koalabot_lite_icon_screen_food_plant: + 'Display %1 from [Food/Plants] at position (%2, %3) in size %4 %5', + robotis_koalabot_lite_icon_screen_animal_human: + 'Display %1 from [Animal/Human] at position (%2, %3) in size %4 %5', + robotis_koalabot_lite_icon_screen_object_tool: + 'Display %1 from [Object/Tool] at position (%2, %3) in size %4 %5', + robotis_koalabot_lite_icon_screen_vehicle_number: + 'Display %1 from [Vehicle/Number] at position (%2, %3) in size %4 %5', + robotis_koalabot_lite_text_screen: + 'Display %1 in %5 in %4 at (%2, %3) on the screen %6', + robotis_koalabot_lite_text_screen_redraw: + 'Newly display %1 in %4 at (%2, %3) %5', + robotis_koalabot_lite_pixel: 'Display %3 colored dot at (%1, %2) %4', + robotis_koalabot_lite_LCDBright: 'Set screen brightness as %1 %2', + robotis_koalabot_lite_LCDColor: 'Set screen color as %1 %2', + + // LED 제어 + robotis_koalabot_lite_cm_led: "%2 the robot's %1 LED %3", + robotis_koalabot_lite_cm_led_pattern: 'LED %1 blinks at a %2 speed %3', + + // AI Camera 값 블록 + robotis_koalabot_lite_ai_camera_connection_status: 'AI Camera: If %1', + robotis_koalabot_lite_ai_camera_if_detected: + 'AI Camera: If %1 is displayed', + + robotis_koalabot_lite_ai_camera_block_value_closest_to_center: + 'AI Camera: %1 of the rectangle closest to the center of the screen', + robotis_koalabot_lite_ai_camera_arrow_value_closest_to_center: + 'AI Camera: %1 of the arrow closest to the center of the screen', + robotis_koalabot_lite_ai_camera_number_of_learned_id: + 'AI Camera: the number of learned ID', + robotis_koalabot_lite_ai_camera_block_value_of_id: + 'AI Camera: %2 of rectangle with detected ID %1', + robotis_koalabot_lite_ai_camera_arrow_value_of_id: + 'AI Camera: %2 of arrow with detected ID %1', + + robotis_koalabot_lite_ai_camera_if_learned_id: + 'AI Camera: If learned data with ID %1', + robotis_koalabot_lite_ai_camera_if_detected_id_type: + 'AI Camera: If learned %2 data with ID %1', + + // AI 카메라 제어 + robotis_koalabot_lite_ai_camera_set_mode: 'AI Camera: Set mode to %1 %2', + robotis_koalabot_lite_ai_camera_print_custom_text: + 'AI Camera: Display %3 at screen position (%1, %2) %4', + robotis_koalabot_lite_ai_camera_clear_custom_text: + 'AI Camera: Clear screen text %1', + }, + Blocks: { + // Driving Control + robotis_koalabot_lite_drive_simple: + 'Drive the robot at the specified speed and direction\nSpeed range: -100 ~ 100\nSpeed unit: %', + robotis_koalabot_lite_drive_advanced: + 'Rotate the left and right wheels of the robot at the specified speed and direction\nSpeed range: -100 ~ 100\nSpeed unit: %', + robotis_koalabot_lite_drive_seperate: + 'Rotate the specified wheel of the robot at the specified speed and direction\nSpeed range: -100 ~ 100\nSpeed unit: %', + robotis_koalabot_lite_drive_angle: + 'Rotate the two wheels of the robot in the specified direction and by the specified angle\nAngle range: -5760 ~ 5760\nAngle unit: degrees', + robotis_koalabot_lite_go_distance: + 'Move forward or backward by the specified distance\nDistance range: -1000 ~ 1000\nDistance unit: mm', + robotis_koalabot_lite_turn_angle: + 'Rotate in place by the specified angle and direction\nAngle range: -360 ~ 360\nAngle unit: degrees', + robotis_koalabot_lite_follow_line: + 'Start following the line at the specified speed', + robotis_koalabot_lite_stop_at_cross: 'Stop at the specified intersection', + robotis_koalabot_lite_turn_at_line: + 'Make the specified turn at the intersection and stop', + robotis_koalabot_lite_drive_stop: 'Stop the robot', + + // Value Blocks + robotis_koalabot_lite_cm_ir_value: + 'IR sensor value of the specified number (range: 0 ~ 200)', + robotis_koalabot_lite_cm_ir_compare: + "If the IR sensor value of the specified number matches the specified value, it is determined as 'true'; otherwise, 'false'.", + robotis_koalabot_lite_detectFrontObj: + "If an object is detected in front of the specified sensor, it is determined as 'true'; otherwise, 'false'.", + robotis_koalabot_lite_cm_btn_value: + "If the specified button is clicked, it is determined as 'true'; otherwise, 'false'.", + robotis_koalabot_lite_cm_joystick_value: + "If the joystick position is in the specified state, it is determined as 'true'; otherwise, 'false'.", + robotis_koalabot_lite_mic: + 'Displays the intensity of the sound detected by the microphone in decibels (dB).', + robotis_koalabot_lite_detectSound_compare: + "If the direction of the sound matches the specified direction, it is determined as 'true'; otherwise, 'false'.", + robotis_koalabot_lite_imu: + 'Value of the specified accelerometer/gyro sensor on the specified axis\nRange: -100 ~ 100', + robotis_koalabot_lite_roll_pitch: + 'roll/pitch value\nroll: -180° ~ 180°, pitch: -90° ~ 90°', + robotis_koalabot_lite_distance_value: + 'Value of the specified sensor\nDistance range: 0 ~ 1000mm\nIlluminance range: 0 ~ 100%\nButton sensor: 0 (not pressed) / 1 (pressed)', + robotis_koalabot_lite_distance_compare: + "If the specified equation of the specified sensor value is correct, it is determined as 'true'; otherwise, 'false'.", + robotis_koalabot_lite_line_cross_compare: + "If the specified intersection shape is correct, it is determined as 'true'; otherwise, 'false'.", + robotis_koalabot_lite_dxl_value: + 'Position angle value of the specified motor\nRange: -180° ~ 180°', + + // Sound + robotis_koalabot_lite_scale_simple: + 'Play with the specified octave, scale, and note', + robotis_koalabot_lite_scale_advanced: + 'Play with the specified octave, scale, and beat', + robotis_koalabot_lite_rest_simple: 'Rest for the specified rest note', + robotis_koalabot_lite_rest_advanced: 'Rest for the specified beat', + robotis_koalabot_lite_beat_per_minute: + 'Set the playing speed (BPM)\nRange: 10 ~ 600', + robotis_koalabot_lite_Hello: 'Play the specified voice of the robot', + robotis_koalabot_lite_effectSound: + 'Play the specified sound effect of the robot', + robotis_koalabot_lite_record: + 'Record and save to the specified number storage', + robotis_koalabot_lite_playRecord: + 'Play the recorded voice in the specified number storage', + + // LCD Control + robotis_koalabot_lite_screen: + 'Set the character and expression of the controller screen background', + robotis_koalabot_lite_anim_screen: + 'Set the character and expression of the controller screen animation', + robotis_koalabot_lite_icon_screen_food_plant: + 'Set the position and size of a specific icon in [food/plant] on the screen\nX coordinate: -160 ~ 160\nY coordinate: -120 ~ 120\nSize: 0 ~ 200', + robotis_koalabot_lite_icon_screen_animal_human: + 'Set the position and size of a specific icon in [animal/human] on the screen\nX coordinate: -160 ~ 160\nY coordinate: -120 ~ 120\nSize: 0 ~ 200', + robotis_koalabot_lite_icon_screen_object_tool: + 'Set the position and size of a specific icon in [object/tool] on the screen\nX coordinate: -160 ~ 160\nY coordinate: -120 ~ 120\nSize: 0 ~ 200', + robotis_koalabot_lite_icon_screen_vehicle_number: + 'Set the position and size of a specific icon in [vehicle/number] on the screen\nX coordinate: -160 ~ 160\nY coordinate: -120 ~ 120\nSize: 0 ~ 200', + robotis_koalabot_lite_text_screen: + 'Set the position, font size, and color of the specified text on the screen\nX coordinate: -160 ~ 160\nY coordinate: -120 ~ 120', + robotis_koalabot_lite_text_screen_redraw: + 'Set the position and color of the specified text to be newly displayed (clearing the background of the text) on the screen\nX coordinate: -160 ~ 160\nY coordinate: -120 ~ 120\nSize: 0 ~ 200', + robotis_koalabot_lite_pixel: + 'Set the position and color of the dot to be displayed on the screen\nX coordinate: -160 ~ 160\nY coordinate: -120 ~ 120', + robotis_koalabot_lite_LCDBright: + 'Set the screen brightness\nBrightness range: 0% ~ 100%', + robotis_koalabot_lite_LCDColor: 'Set the screen color', + + // LED Control + robotis_koalabot_lite_cm_led: + 'Turn the specified LED of the controller on or off', + robotis_koalabot_lite_cm_led_pattern: + 'Set the blinking pattern of LEDs of the controller', + + // AI Camera Value Blocks + robotis_koalabot_lite_ai_camera_connection_status: + "If the AI camera is connected, it is determined as 'true'; otherwise, 'false'.", + robotis_koalabot_lite_ai_camera_if_detected: + "If the selected symbol (rectangle/arrow) is displayed on the LCD screen of the AI camera, it is determined as 'true'; otherwise, 'false'.", + + robotis_koalabot_lite_ai_camera_block_value_closest_to_center: + 'X coordinate/Y coordinate/width/height/learning ID of the rectangle closest to the center of the AI camera screen', + robotis_koalabot_lite_ai_camera_arrow_value_closest_to_center: + 'Starting point X coordinate/starting point Y coordinate/end point X coordinate/end point Y coordinate/learning ID of the arrow closest to the center of the AI camera screen', + robotis_koalabot_lite_ai_camera_number_of_learned_id: + 'Number of IDs learned by the AI camera', + robotis_koalabot_lite_ai_camera_block_value_of_id: + 'X coordinate/Y coordinate/width/height of the rectangle with the specified ID detected by the AI camera', + robotis_koalabot_lite_ai_camera_arrow_value_of_id: + 'Starting point X coordinate/starting point Y coordinate/end point X coordinate/end point Y coordinate of the arrow with the specified ID detected by the AI camera', + + robotis_koalabot_lite_ai_camera_if_learned_id: + "If the AI camera has learned data with the specified ID, it is determined as 'true'; otherwise, 'false'.", + robotis_koalabot_lite_ai_camera_if_detected_id_type: + "If the AI camera has learned the specified data (rectangle/arrow) with the specified ID, it is determined as 'true'; otherwise, 'false'.", + + // AI Camera Control + robotis_koalabot_lite_ai_camera_set_mode: 'Set the mode of the AI camera', + robotis_koalabot_lite_ai_camera_print_custom_text: + 'Print the specified text at the specified position on the AI camera screen\nX coordinate: -160 ~ 160\nY coordinate: -120 ~ 120', + robotis_koalabot_lite_ai_camera_clear_custom_text: + 'Clear all texts displayed on the AI camera screen', + }, + + Blocks: { + robotis_red: 'Red', + robotis_orange: 'Orange', + robotis_yellow: 'Yellow', + robotis_green: 'Green', + robotis_blue: 'Blue', + robotis_brown: 'Brown', + robotis_black: 'Black', + robotis_white: 'White', + robotis_left: 'Left', + robotis_center: 'Center', + robotis_right: 'Right', + robotis_both: 'Both', + robotis_rgee: 'R-GEE', + robotis_rla: 'KODALA', + robotis_kkokdu: 'TIG', + robotis_korean1: 'Hello!', + robotis_korean2: 'Great to see you.', + robotis_korean3: 'Okay ~', + robotis_korean4: 'No!', + robotis_korean5: "I don't know.", + robotis_korean6: 'I like it.', + robotis_korean7: "I don't like it.", + robotis_korean8: 'What is your name? ', + robotis_korean9: 'How can I help you? ', + robotis_korean10: 'Great job! ', + robotis_korean11: "It's alright.", + robotis_korean12: "Let's do it again! ", + robotis_korean13: 'Thank you! ', + robotis_korean14: 'Can you say that one more time?', + robotis_korean15: 'Awesome!', + robotis_korean16: "I'm excited! ", + robotis_korean17: "I'm having a great time! ", + robotis_korean18: "I'm sorry.", + robotis_korean19: "I'm angry! ", + robotis_korean20: "I'm embarassed.", + robotis_korean21: "I'm scared.", + robotis_korean22: "I'm upset.", + robotis_korean23: 'I love you.', + robotis_korean24: 'Very pretty! ', + robotis_korean25: 'Interesting.', + robotis_korean26: "I'm nervous.", + robotis_korean27: "Let's move forward! ", + robotis_korean28: "Let's move backward! ", + robotis_korean29: "Let's stand up! ", + robotis_korean30: 'Did you fall down? ', + robotis_korean31: 'Oh Yeah~', + robotis_korean32: 'Sweet! ', + robotis_korean33: 'Oh no', + robotis_korean34: 'My My ', + robotis_korean35: 'Whoo hoo! ', + robotis_korean36: 'Ha Ha Ha', + robotis_korean37: 'Ho Ho Ho ', + robotis_korean38: "I'm sleepy.", + robotis_korean39: 'Sing me a bedtime song! ', + robotis_korean40: 'Hello!', + robotis_korean41: "I'm hungry.", + robotis_korean42: "I'm craving an acorn! ", + robotis_korean43: 'I want to take a bath! ', + robotis_korean44: 'Time for a bath! ', + robotis_korean45: "I'm bored. ", + robotis_korean46: 'Do you want a snack? ', + robotis_korean47: "I'm sick.", + robotis_korean48: 'Do you have any medicine? ', + robotis_korean49: 'Where do we have to go? ', + robotis_korean50: "We're here! ", + robotis_korean51: "Let's go to the left side! ", + robotis_korean52: "Let's go to the right side! ", + robotis_korean53: 'Oh my, you scared me! ', + robotis_korean54: 'Found you! ', + robotis_korean55: "There's nothing here. ", + robotis_korean56: 'Did you call me?', + robotis_korean57: 'Please let me down. ', + robotis_korean58: 'Oops! ', + robotis_korean59: 'Hmmph! ', + robotis_korean60: 'Eek! ', + robotis_dog: 'Dog', + robotis_frog: 'Frog', + robotis_cat: 'Cat', + robotis_chicken: 'Rooster', + robotis_tiger: 'Tiger', + robotis_mouse: 'Mouse', + robotis_whistle: 'Whistle', + robotis_ambul: 'Ambulance', + robotis_Horn: 'CarHorn', + robotis_siren: 'Siren', + robotis_gun: 'Gunshot', + robotis_clap: 'Clap', + robotis_melody1: 'Melody1', + robotis_melody2: 'Melody2', + robotis_melody3: 'Melody3', + robotis_melody4: 'Melody4', + robotis_forward: 'Forward', + robotis_backward: 'Backward', + robotis_acceleration: 'acceleration', + robotis_gyro: 'gyro', + robotis_run: 'Run', + robotis_cancel: 'Cancel', + robotis_push: 'Pressed', + robotis_notPush: 'Unpressed', + robotis_play: 'Play', + robotis_rest: 'Rest', + robotis_face01: 'Haha', + robotis_face02: 'Smile', + robotis_face03: 'Laugh', + robotis_face04: 'Yum Yum', + robotis_face05: 'Scared', + robotis_face06: 'Uncomfortable', + robotis_face07: 'Confused', + robotis_face08: 'Dazed', + robotis_face09: 'Yell', + robotis_face10: 'Angry', + robotis_face11: 'Sniff (Left)', + robotis_face12: 'Sniff (Right)', + robotis_face13: 'Sniff (Down)', + robotis_face14: 'Whew', + robotis_face15: 'Faint', + robotis_face16: 'Dizzy', + robotis_face17: 'Yawn', + robotis_face18: 'Sleepy', + robotis_face19: 'Sleep', + robotis_face20: 'Sad', + robotis_face21: 'Cry', + robotis_face22: 'Bath', + robotis_face23: 'Heart-Eyes', + + robotis_pattern1: 'Pattern1', + robotis_pattern2: 'Pattern2', + robotis_pattern3: 'Pattern3', + robotis_moveF: 'Forward', + robotis_moveB: 'Backward', + robotis_moveL: 'LeftTurn', + robotis_moveR: 'RightTurn', + robotis_moveU: 'U-turn', + robotis_moveL_in_place: 'Turn left in place', + robotis_moveR_in_place: 'Trun right in place', + robotis_moveU_in_place: 'U-turn in place', + robotis_moveRG1: 'Stand', + robotis_moveRG2: 'Sit', + robotis_moveRG3: 'Struggle', + robotis_moveRG4: 'RaiseFeet', + robotis_fast: 'Fast', + robotis_normal: 'Normal', + robotis_slow: 'Slow', + robotis_stop: 'Stop', + robotis_roll: 'Left-right rotate angle (roll)', + robotis_pitch: 'Forward-backward rotate angle (pitch)', + robotis_direction_forward: 'Forward', + robotis_direction_backward: 'Backward', + robotis_stMotion1: 'Standard', + robotis_stMotion2: 'Forward', + robotis_stMotion3: 'TurnRight', + robotis_stMotion4: 'TurnLeft', + robotis_stMotion5: 'Backward', + robotis_stMotion6: 'ToRight', + robotis_stMotion7: 'ToLeft', + robotis_stMotion8: 'TurnAroundRight', + robotis_stMotion9: 'TurnAroundLeft', + robotis_spMotion1: 'RightHandUp', + robotis_spMotion2: 'RightHandDown', + robotis_spMotion3: 'LeftHandUp', + robotis_spMotion4: 'LeftHandDown', + robotis_spMotion5: 'BothHandsUp', + robotis_spMotion6: 'BothHandsDown', + robotis_spMotion7: 'FallBackward', + robotis_spMotion8: 'FallForward', + robotis_spMotion9: 'StandForward', + robotis_spMotion10: 'StandBackward', + robotis_spMotion11: 'Defence', + robotis_spMotion12: 'Offense1', + robotis_spMotion13: 'Offense2', + robotis_spMotion14: 'Offense3', + robotis_spMotion15: 'Offense4', + robotis_screen1: 'Sissor', + robotis_screen2: 'Rock', + robotis_screen3: 'Paper', + robotis_icon_food_plant_1: 'Milk', + robotis_icon_food_plant_2: 'Tree', + robotis_icon_food_plant_3: 'Soup', + robotis_icon_food_plant_4: 'Cake', + robotis_icon_food_plant_5: 'Water', + robotis_icon_food_plant_6: 'Juice', + robotis_icon_food_plant_7: 'Carrot', + robotis_icon_food_plant_8: 'Apple', + robotis_icon_food_plant_9: 'Orange', + robotis_icon_food_plant_10: 'Meat', + robotis_icon_food_plant_11: 'Flowerpot', + robotis_icon_food_plant_12: 'Rose', + robotis_icon_food_plant_13: 'Grape', + robotis_icon_food_plant_14: 'Potato', + robotis_icon_food_plant_15: 'Candy', + robotis_icon_food_plant_16: 'Cheese', + robotis_icon_food_plant_17: 'Bread', + robotis_icon_food_plant_18: 'Flowers', + robotis_icon_food_plant_19: 'Coffee', + robotis_icon_food_plant_20: 'Tulip', + robotis_icon_food_plant_21: 'Banana', + robotis_icon_food_plant_22: 'Fruits', + robotis_icon_food_plant_23: 'Hamburger', + robotis_icon_food_plant_24: 'Pizza', + robotis_icon_animal_human_1: 'Shiba Dog', + robotis_icon_animal_human_2: 'Puppy', + robotis_icon_animal_human_3: 'Bear', + robotis_icon_animal_human_4: 'Bird', + robotis_icon_animal_human_5: 'Duck', + robotis_icon_animal_human_6: 'Lion', + robotis_icon_animal_human_7: 'Tiger', + robotis_icon_animal_human_8: 'Horse', + robotis_icon_animal_human_9: 'Sheep', + robotis_icon_animal_human_10: 'Shark 1 (Left)', + robotis_icon_animal_human_11: 'Shark 1 (Right)', + robotis_icon_animal_human_12: 'Shark 2 (Left)', + robotis_icon_animal_human_13: 'Shark 2 (Right)', + robotis_icon_animal_human_14: 'Fish 1', + robotis_icon_animal_human_15: 'Fish 2', + robotis_icon_animal_human_16: 'Fish 3', + robotis_icon_animal_human_17: 'Octopus', + robotis_icon_animal_human_18: 'Monkey', + robotis_icon_animal_human_19: 'Chicken', + robotis_icon_animal_human_20: 'Pig', + robotis_icon_animal_human_21: 'Person (Chubby)', + robotis_icon_animal_human_22: 'Person (Swimsuit)', + robotis_icon_animal_human_23: 'Baby', + robotis_icon_animal_human_24: 'Person (Running)', + robotis_icon_animal_human_25: 'Person (Singing)', + robotis_icon_animal_human_26: 'Person (Sitting)', + robotis_icon_animal_human_27: 'Person (Angry)', + robotis_icon_animal_human_28: 'Person (Cheering)', + robotis_icon_animal_human_29: 'King', + robotis_icon_animal_human_30: 'Prince', + robotis_icon_animal_human_31: 'Princess', + robotis_icon_animal_human_32: 'Chef', + robotis_icon_animal_human_33: 'Doctor', + robotis_icon_animal_human_34: 'Nurse', + robotis_icon_object_tool_1: 'Bag', + robotis_icon_object_tool_2: 'Box', + robotis_icon_object_tool_3: 'Mug', + robotis_icon_object_tool_4: 'Hat (Fedora)', + robotis_icon_object_tool_5: 'Hat (Cap)', + robotis_icon_object_tool_6: 'Key', + robotis_icon_object_tool_7: 'Toy', + robotis_icon_object_tool_8: 'Book', + robotis_icon_object_tool_9: 'Teddy Bear', + robotis_icon_object_tool_10: 'Drum', + robotis_icon_object_tool_11: 'Notebook', + robotis_icon_object_tool_12: 'Pen', + robotis_icon_object_tool_13: 'Desk', + robotis_icon_object_tool_14: 'Table', + robotis_icon_object_tool_15: 'Chair', + robotis_icon_object_tool_16: 'Bed', + robotis_icon_object_tool_17: 'Tent', + robotis_icon_object_tool_18: 'Plate', + robotis_icon_object_tool_19: 'Soccer Ball', + robotis_icon_object_tool_20: 'Bell', + robotis_icon_object_tool_21: 'Watch', + robotis_icon_object_tool_22: 'Shoes', + robotis_icon_object_tool_23: 'Lamp', + robotis_icon_object_tool_24: 'Radio', + robotis_icon_object_tool_25: 'Banknote', + robotis_icon_object_tool_26: 'Ruler', + robotis_icon_object_tool_27: 'Camera', + robotis_icon_object_tool_28: 'Spoon', + robotis_icon_object_tool_29: 'Keyboard', + robotis_icon_object_tool_30: 'Calendar', + robotis_icon_object_tool_31: 'Knife', + robotis_icon_object_tool_32: 'Balloon', + robotis_icon_object_tool_33: 'Water Bottle', + robotis_icon_object_tool_34: 'Wooden Stick (Horizontal)', + robotis_icon_object_tool_35: 'Wooden Stick (Vertical)', + robotis_icon_object_tool_36: 'Fishing Hook', + robotis_icon_vehicle_number_1: 'Car', + robotis_icon_vehicle_number_2: 'Bus', + robotis_icon_vehicle_number_3: 'Truck', + robotis_icon_vehicle_number_4: 'Jeep', + robotis_icon_vehicle_number_5: 'Bicycle', + robotis_icon_vehicle_number_6: 'Subway', + robotis_icon_vehicle_number_7: 'Train', + robotis_icon_vehicle_number_8: 'Airplane', + robotis_icon_vehicle_number_9: 'Fighter Jet (Vertical)', + robotis_icon_vehicle_number_10: 'Fighter Jet (Horizontal)', + robotis_icon_vehicle_number_11: 'Rocket', + robotis_icon_vehicle_number_12: 'Fishing Boat', + robotis_icon_vehicle_number_13: 'Passenger Ship', + robotis_icon_vehicle_number_14: 'Submarine (Left)', + robotis_icon_vehicle_number_15: 'Submarine (Right)', + robotis_icon_vehicle_number_16: 'Airplane (Left)', + robotis_icon_vehicle_number_17: 'Airplane (Right)', + robotis_icon_vehicle_number_18: 'Airplane (Top)', + robotis_icon_vehicle_number_19: 'Spaceship (Left)', + robotis_icon_vehicle_number_20: 'Spaceship (Right)', + robotis_icon_vehicle_number_21: 'Spaceship (Top)', + robotis_icon_vehicle_number_22: 'Dice (1)', + robotis_icon_vehicle_number_23: 'Dice (2)', + robotis_icon_vehicle_number_24: 'Dice (3)', + robotis_icon_vehicle_number_25: 'Dice (4)', + robotis_icon_vehicle_number_26: 'Dice (5)', + robotis_icon_vehicle_number_27: 'Dice (6)', + robotis_icon_vehicle_number_28: '0', + robotis_icon_vehicle_number_29: '1', + robotis_icon_vehicle_number_30: '2', + robotis_icon_vehicle_number_31: '3', + robotis_icon_vehicle_number_32: '4', + robotis_icon_vehicle_number_33: '5', + robotis_icon_vehicle_number_34: '6', + robotis_icon_vehicle_number_35: '7', + robotis_icon_vehicle_number_36: '8', + robotis_icon_vehicle_number_37: '9', + robotis_icon_vehicle_number_38: '10', + robotis_speed_fast: 'Fast Speed', + robotis_speed_midium: 'Medium Speed', + robotis_speed_slow: 'Slow Speed', + robotis_clockwise: 'Clockwise', + robotis_counterclockwise: 'Counterclockwise', + robotis_up: 'Lift', + robotis_down: 'Lower', + robotis_if_greater: 'If Greater', + robotis_if_smaller: 'If Smaller', + robotis_if_equal: 'If Equal', + robotis_front_right: 'Front Right', + robotis_front_left: 'Front Left', + robotis_bottom_right: 'Bottom Right', + robotis_bottom_left: 'Bottom Left', + robotis_side_right: 'Right Edge', + robotis_side_left: 'Left Edge', + robotis_front_ir_sensor: 'Infrared Sensor', + robotis_distance_sensor: 'Distance Sensor', + robotis_front: 'Front', + robotis_right: 'Right', + robotis_left_wheel: 'Left Wheel', + robotis_right_wheel: 'Right Wheel', + robotis_beat_sound_8th_note: 'Eighth Note (♪)', + robotis_beat_sound_dotted_8th_note: 'Dotted Eighth Note (♪.)', + robotis_beat_sound_quarter_note: 'Quarter Note (♩)', + robotis_beat_sound_dotted_quarter_note: 'Dotted Quarter Note (♩.)', + robotis_beat_sound_half_note: 'Half Note (𝅗𝅥)', + robotis_beat_sound_dotted_half_note: 'Dotted Half Note (𝅗𝅥.)', + robotis_beat_sound_whole_note: 'Whole Note (𝅝)', + robotis_beat_sound_dotted_note: 'Dotted Whole Note (𝅝.)', + robotis_beat_rest_8th_note: 'Eighth Rest (𝄾)', + robotis_beat_rest_dotted_8th_note: 'Dotted Eighth Rest (𝄾.)', + robotis_beat_rest_quarter_note: 'Quarter Rest (𝄽)', + robotis_beat_rest_dotted_quarter_note: 'Dotted Quarter Rest (𝄽.)', + robotis_beat_rest_half_note: 'Half Rest (𝄼)', + robotis_beat_rest_dotted_half_note: 'Dotted Half Rest (𝄼˙)', + robotis_beat_rest_whole_note: 'Whole Rest (𝄻)', + robotis_beat_rest_dotted_note: 'Dotted Whole Rest (𝄻˙)', + robotis_line_cross_type_0: '|', + robotis_line_cross_type_1: ' (Blank)', + robotis_line_cross_type_5: '🞣', + robotis_line_cross_type_6: '⏉', + robotis_line_cross_type_7: '⊣', + robotis_line_cross_type_8: '⊢', + robotis_line_cross_type_9: '⏋', + robotis_line_cross_type_10: '⎾', + robotis_line_cross_type_11: '¦', + robotis_line_cross_type_12: '︙', + robotis_connected: 'Connected', + robotis_disconnected: 'Not connected', + robotis_ai_camera_mode_face_recognition: 'Face Recognition', + robotis_ai_camera_mode_object_tracking: 'Object Tracking', + robotis_ai_camera_mode_object_recognition: 'Object Recognition', + robotis_ai_camera_mode_line_tracking: 'Line Tracking', + robotis_ai_camera_mode_color_recognition: 'Color Recognition', + robotis_ai_camera_mode_tag_recognition: 'Tag Recognition', + robotis_ai_camera_mode_object_classification: 'Object Classification', + robotis_ai_camera_block: 'Block', + robotis_ai_camera_arrow: 'Arrow', + robotis_ai_camera_center_block_center_x: 'Center X Coordinate', + robotis_ai_camera_center_block_center_y: 'Center Y Coordinate', + robotis_ai_camera_center_block_width: 'Width', + robotis_ai_camera_center_block_height: 'Height', + robotis_ai_camera_center_leared_id: 'Learned ID', + robotis_ai_camera_center_arrow_origin_x: 'Start X Coordinate', + robotis_ai_camera_center_arrow_origin_y: 'Start Y Coordinate', + robotis_ai_camera_center_arrow_target_x: 'End X Coordinate', + robotis_ai_camera_center_arrow_target_y: 'End Y Coordinate', + }, + }, + }; + } + getBlocks() { + return { + robotis_koalabot_lite_drive_simple: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_moveF, '1'], + [Lang.Blocks.robotis_moveB, '2'], + [Lang.Blocks.robotis_moveL_in_place, '3'], + [Lang.Blocks.robotis_moveR_in_place, '4'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [5, null, null], + type: 'robotis_koalabot_lite_drive_simple', + }, + paramsKeyMap: { + SPEED: 0, + DIRECTION: 1, + }, + class: 'robotis_koalabot_lite_move', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + const speed = script.getNumberValue('SPEED', script); + const direction = script.getField('DIRECTION', script); + + const data_instruction = INST_WRITE; + const data_address = 710; + const data_length = 2; + let data_value = 0; + + switch (direction) { + case '1': + data_value = speed * 256 + speed; + break; + case '2': + data_value = (256 - speed) * 256 + (256 - speed); + break; + case '3': + data_value = speed * 256 + (256 - speed); + break; + case '4': + data_value = (256 - speed) * 256 + speed; + break; + default: + data_value = 0; + break; + } + + const data_sendqueue = [ + [data_instruction, data_address, data_length, data_value], + ]; + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + ); + }, + syntax: { + js: [], + py: ['Koalabot.go_simple(%1, %2)'], + }, + }, + robotis_koalabot_lite_drive_advanced: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_moveF, '1'], + [Lang.Blocks.robotis_moveB, '2'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_moveF, '1'], + [Lang.Blocks.robotis_moveB, '2'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + { + type: 'number', + params: ['5'], + }, + null, + { + type: 'number', + params: ['5'], + }, + null, + ], + type: 'robotis_koalabot_lite_drive_advanced', + }, + paramsKeyMap: { + LEFT_SPEED: 0, + LEFT_DIRECTION: 1, + RIGHT_SPEED: 2, + RIGHT_DIRECTION: 3, + }, + class: 'robotis_koalabot_lite_move', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let leftSpeed = script.getNumberValue('LEFT_SPEED', script); + const leftDirection = script.getField('LEFT_DIRECTION', script); + let rightSpeed = script.getNumberValue('RIGHT_SPEED', script); + const rightDirection = script.getField('RIGHT_DIRECTION', script); + + let data_instruction = INST_WRITE; + let data_address = 710; + let data_length = 2; + let data_value = 0; + + if (leftSpeed < -100) { + leftSpeed = -100; + } else if (leftSpeed > 100) { + leftSpeed = 100; + } + + if (rightSpeed < -100) { + rightSpeed = -100; + } else if (rightSpeed > 100) { + rightSpeed = 100; + } + + if (leftDirection == '2') { + leftSpeed = -leftSpeed; + } + if (rightDirection == '2') { + rightSpeed = -rightSpeed; + } + + if (leftSpeed < 0) { + leftSpeed = 256 + leftSpeed; + } + if (rightSpeed < 0) { + rightSpeed = 256 + rightSpeed; + } + + data_value = leftSpeed + rightSpeed * 256; + + let data_sendqueue = [ + [data_instruction, data_address, data_length, data_value], + ]; + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + ); + }, + syntax: { + js: [], + py: ['Koalabot.go_advanced(%1, %2)'], + }, + }, + robotis_koalabot_lite_drive_seperate: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_left, '1'], + [Lang.Blocks.robotis_right, '0'], + [Lang.Blocks.robotis_both, '2'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_direction_forward, '1'], + [Lang.Blocks.robotis_direction_backward, '2'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + { + type: 'number', + params: ['5'], + }, + null, + ], + type: 'robotis_koalabot_lite_drive_seperate', + }, + paramsKeyMap: { + WHEEL_SIDE: 0, + WHEEL_SPEED: 1, + WHEEL_DIRECTION: 2, + }, + class: 'robotis_koalabot_lite_move', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let wheelSide = script.getNumberValue('WHEEL_SIDE', script); + let wheelSpeed = script.getNumberValue('WHEEL_SPEED', script); + let wheelDirection = script.getNumberValue('WHEEL_DIRECTION', script); + + let leftSpeed = 0; + let rightSpeed = 0; + let data_instruction = INST_WRITE; + let data_address = 710; + let data_length = 2; + let data_value = 0; + + if (wheelSpeed < -100) { + wheelSpeed = -100; + } else if (wheelSpeed > 100) { + wheelSpeed = 100; + } + + wheelSpeed = (wheelSpeed + 256) % 256; + if (wheelDirection == '2') { + wheelSpeed = (256 - wheelSpeed) % 256; + } + + if (wheelSide == 1) { + leftSpeed = wheelSpeed; + rightSpeed = 127; // 속도제어 안함 + } else if (wheelSide == 0) { + leftSpeed = 127; // 속도제어 안함 + rightSpeed = wheelSpeed; + } else { + leftSpeed = wheelSpeed; + rightSpeed = wheelSpeed; + } + + data_value = leftSpeed + rightSpeed * 256; + + let data_sendqueue = [ + [data_instruction, data_address, data_length, data_value], + ]; + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + 25 //DEFAULT_DELAY + ); + }, + syntax: { + js: [], + py: ['Koalabot.go_seperate(%1, %2)'], + }, + }, + robotis_koalabot_lite_drive_angle: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_direction_forward, '1'], + [Lang.Blocks.robotis_direction_backward, '2'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + { + type: 'number', + params: ['180'], + }, + null, + ], + type: 'robotis_koalabot_lite_drive_angle', + }, + paramsKeyMap: { + WHEEL_ANGLE: 0, + WHEEL_DIRECTION: 1, + }, + class: 'robotis_koalabot_lite_move', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let wheelAngle = script.getNumberValue('WHEEL_ANGLE', script); + let wheelDirection = script.getNumberValue('WHEEL_DIRECTION', script); + + const data_instruction = INST_WRITE; + let data_address = 580; + let data_length = 8; + let angleValue = 0; + let data_buf_left = []; + let data_buf_right = []; + let i = 0; + let speed = 50; + + if (wheelDirection == '2') { + wheelAngle = -wheelAngle; + } + + wheelAngle = Math.round((wheelAngle * 4096) / 360); + + if (wheelAngle > 65535) { + wheelAngle = 65535; + } else if (wheelAngle < -65535) { + wheelAngle = -65535; + } + + angleValue = wheelAngle; + if (wheelAngle < 0) { + angleValue = 65536 + angleValue; + } + data_buf_left.push(35); + data_buf_left.push(0); + data_buf_left.push(speed % 256); + data_buf_left.push(Math.floor(speed / 256)); + data_buf_left.push(angleValue % 256); + data_buf_left.push(Math.floor(angleValue / 256) % 256); + if (wheelAngle >= 0) { + data_buf_left.push(0); + data_buf_left.push(0); + } else { + data_buf_left.push(0xff); + data_buf_left.push(0xff); + } + + data_buf_right.push(36); + data_buf_right.push(0); + data_buf_right.push(speed % 256); + data_buf_right.push(Math.floor(speed / 256)); + data_buf_right.push(angleValue % 256); + data_buf_right.push(Math.floor(angleValue / 256) % 256); + if (wheelAngle >= 0) { + data_buf_right.push(0); + data_buf_right.push(0); + } else { + data_buf_right.push(0xff); + data_buf_right.push(0xff); + } + + let data_sendqueue = [ + [data_instruction, data_address, data_length, data_buf_left], + [data_instruction, data_address, data_length, data_buf_right], + ]; + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + ); + }, + syntax: { + js: [], + py: ['Koalabot.go_angle(%1, %2)'], + }, + }, + robotis_koalabot_lite_go_distance: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_moveF, '1'], + [Lang.Blocks.robotis_moveB, '-1'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + { + type: 'number', + params: ['5'], + }, + null, + ], + type: 'robotis_koalabot_lite_go_distance', + }, + + paramsKeyMap: { + DISTANCE: 0, + DIRECTION: 1, + }, + class: 'robotis_koalabot_lite_move', + isNotFor: ['RobotisKoalabotLite'], + func(entity, script) { + let distance = script.getNumberValue('DISTANCE', script); + let direction = script.getField('DIRECTION', script); + + if (distance > 1000) { + distance = 1000; + } else if (distance < -1000) { + distance = -1000; + } + + let data_instruction = INST_WRITE; + let data_address = 270; + let data_length = 4; + let data_value = Math.floor(10 * distance * direction); + + let data_sendqueue = [ + [data_instruction, data_address, data_length, data_value], + ]; + + data_sendqueue.push([data_instruction, 66, 2, 50491]); + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + 150 * Math.abs(distance) + 1200 + //DEFAULT_DELAY + ); + }, + syntax: { js: [], py: ['Koalabot.dxl_each_control(%1)'] }, + }, + + robotis_koalabot_lite_turn_angle: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_moveL_in_place, '1'], + [Lang.Blocks.robotis_moveR_in_place, '-1'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + { + type: 'number', + params: ['90'], + }, + null, + ], + type: 'robotis_koalabot_lite_turn_angle', + }, + + paramsKeyMap: { + ANGLE: 0, + DIRECTION: 1, + }, + class: 'robotis_koalabot_lite_move', + isNotFor: ['RobotisKoalabotLite'], + func(entity, script) { + let angle = script.getNumberValue('ANGLE', script); + let direction = script.getNumberValue('DIRECTION', script); + + angle *= direction; + + if (angle > 360) { + angle = 360; + } else if (angle < -360) { + angle = -360; + } + + let data_instruction = INST_WRITE; + let data_address = 270; + let data_length = 4; + let data_value = Math.floor(angle); + + let data_sendqueue = [ + [data_instruction, data_address, data_length, data_value], + ]; + + data_sendqueue.push([data_instruction, 66, 2, 50492]); + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + Math.abs(angle) * 16 + 1500 + //DEFAULT_DELAY + ); + }, + syntax: { js: [], py: ['Koalabot.dxl_each_control(%1)'] }, + }, + robotis_koalabot_lite_follow_line: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_slow, '1'], + [Lang.Blocks.robotis_normal, '2'], + [Lang.Blocks.robotis_fast, '3'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'robotis_koalabot_lite_follow_line', + }, + paramsKeyMap: { + SPEED: 0, + }, + class: 'robotis_koalabot_lite_move', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let speed_level = script.getNumberValue('SPEED', script); + + let data_instruction = INST_WRITE; + let data_address = 5200; + let data_length = 1; + + let data_sendqueue = [ + [data_instruction, data_address, data_length, speed_level], + ]; + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + ); + }, + syntax: { + js: [], + py: ['Koalabot.follow_line(%1)'], + }, + }, + robotis_koalabot_lite_stop_at_cross: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_line_cross_type_5, '5'], + [Lang.Blocks.robotis_line_cross_type_6, '6'], + [Lang.Blocks.robotis_line_cross_type_7, '7'], + [Lang.Blocks.robotis_line_cross_type_8, '8'], + ], + value: '5', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'robotis_koalabot_lite_stop_at_cross', + }, + paramsKeyMap: { + CROSS: 0, + }, + class: 'robotis_koalabot_lite_move', + isNotFor: ['RobotisKoalabotLite'], + async func(sprite, script) { + // instruction / address / length / value / default length + let cross_type = script.getNumberValue('CROSS', script); + let data_address = 5201; + + // max 10 seconds + for (let i = 0; i < 100; i++) { + await Entry.Utils.sleep(100); + if (Entry.RobotisKoalabotLite.dataBuffer[data_address] == cross_type) { + break; + } + if (Entry.engine.isState('stop') == true) { + break; + } + } + + let data_sendqueue = [[INST_WRITE, 5200, 1, 0]]; + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + ); + }, + syntax: { + js: [], + py: ['Koalabot.stop_at_cross(%1)'], + }, + }, + robotis_koalabot_lite_turn_at_line: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_moveL_in_place, '0'], + [Lang.Blocks.robotis_moveR_in_place, '1'], + [Lang.Blocks.robotis_moveU_in_place, '2'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'robotis_koalabot_lite_turn_at_line', + }, + paramsKeyMap: { + TURN_TYPE: 0, + }, + class: 'robotis_koalabot_lite_move', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let turn_type = script.getNumberValue('TURN_TYPE', script); + + let data_instruction = INST_WRITE; + let data_address = 66; + let data_length = 2; + let extra_delay = 0; + + switch (turn_type) { + case 0: + case 1: + extra_delay = 2000; + break; + + case 2: + extra_delay = 3500; + break; + } + + let data_sendqueue = [ + [data_instruction, data_address, data_length, 50045 + turn_type], + ]; + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + extra_delay + ); + }, + syntax: { + js: [], + py: ['Koalabot.turn_at_line(%1)'], + }, + }, + robotis_koalabot_lite_drive_stop: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'robotis_koalabot_lite_drive_stop', + }, + paramsKeyMap: { + DIRECTION: 0, + }, + class: 'robotis_koalabot_lite_move', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + + let data_instruction = INST_WRITE; + let data_address = 710; + let data_length = 2; + let data_value = 0; + + let data_sendqueue = [ + [data_instruction, 5200, 1, 0], + [data_instruction, data_address, data_length, data_value], + ]; + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + ); + }, + syntax: { + js: [], + py: ['Koalabot.stop(%1, %2)'], + }, + }, + + robotis_koalabot_lite_cm_ir_value: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_front_right, '360'], + [Lang.Blocks.robotis_front_left, '362'], + [Lang.Blocks.robotis_bottom_right, '364'], + [Lang.Blocks.robotis_bottom_left, '366'], + [Lang.Blocks.robotis_side_right, '368'], + [Lang.Blocks.robotis_side_left, '370'], + ], + value: '360', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'robotis_koalabot_lite_cm_ir_value', + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'robotis_koalabot_lite_value', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + const scope = script.executor.scope; + + const data_default_address = script.getNumberValue('VALUE'); + + let result = Entry.RobotisKoalabotLite.dataBuffer[data_default_address]; + if (result == undefined) { + result = rb100_last_valid_value[data_default_address]; + } else { + rb100_last_valid_value[data_default_address] = result; + } + if (typeof result == 'undefined') { + return 0; + } + return Math.round((result % 65536) / 2); + }, + syntax: { + js: [], + py: ['Koalabot.ir_value(%1)'], + }, + }, + robotis_koalabot_lite_cm_ir_compare: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_front_right, '360'], + [Lang.Blocks.robotis_front_left, '362'], + [Lang.Blocks.robotis_bottom_right, '364'], + [Lang.Blocks.robotis_bottom_left, '366'], + [Lang.Blocks.robotis_side_right, '368'], + [Lang.Blocks.robotis_side_left, '370'], + ], + value: '360', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_if_greater, '0'], + [Lang.Blocks.robotis_if_smaller, '1'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null, 50, null], + type: 'robotis_koalabot_lite_cm_ir_compare', + }, + paramsKeyMap: { + VALUE: 0, + COMPARE_VAL: 1, + COMPARE_OP: 2, + }, + class: 'robotis_koalabot_lite_value', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + let scope = script.executor.scope; + let data_address = script.getNumberValue('VALUE'); + let compareValue = script.getNumberValue('COMPARE_VAL'); + let compareOP = script.getNumberValue('COMPARE_OP'); + + let result = Entry.RobotisKoalabotLite.dataBuffer[data_address]; + + if (result == undefined) { + return false; + } + + result = Math.round((result % 65536) / 2); + + switch (compareOP) { + case 0: + return result > compareValue; + case 1: + return result < compareValue; + default: + return false; + } + }, + syntax: { + js: [], + py: ['Koalabot.ir_compare(%1)'], + }, + }, + robotis_koalabot_lite_detectFrontObj: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_front_ir_sensor, '0'], + [Lang.Blocks.robotis_distance_sensor, '1'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'robotis_koalabot_lite_detectFrontObj', + }, + paramsKeyMap: { + SENSOR: 0, + }, + class: 'robotis_koalabot_lite_value', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + let scope = script.executor.scope; + + // instruction / address / length / value / default length + let sensorType = script.getNumberValue('SENSOR'); + let ir_1 = 0; + let ir_2 = 0; + + if (sensorType == 0) { + ir_1 = Entry.RobotisKoalabotLite.dataBuffer[360]; + ir_2 = Entry.RobotisKoalabotLite.dataBuffer[362]; + if (ir_1 == undefined) { + ir_1 = 0; + } + if (ir_2 == undefined) { + ir_2 = 0; + } + return ir_1 > 100 || ir_2 > 100; + } else if (sensorType == 1) { + result = Entry.RobotisKoalabotLite.distanceDistance[0]; + if (result == undefined) { + return false; + } else { + return result < 200; + } + } + }, + syntax: { + js: [], + py: ['Koalabot.detectFrontObj()'], + }, + }, + robotis_koalabot_lite_cm_btn_value: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_blue, '47'], + [Lang.Blocks.robotis_red, '44'], + ], + value: '47', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'robotis_koalabot_lite_cm_btn_value', + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'robotis_koalabot_lite_value', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + let scope = script.executor.scope; + let data_address = script.getNumberValue('VALUE'); + let compareValue = 1; + + let result = Entry.RobotisKoalabotLite.dataBuffer[data_address]; + if (result == undefined) { + return false; + } + + return result == compareValue; + }, + syntax: { + js: [], + py: ['Koalabot.btn_value(%1)'], + }, + }, + robotis_koalabot_lite_cm_joystick_value: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_center, '0'], + ['←', '1'], + ['→', '2'], + ['↑', '3'], + ['↓', '4'], + ['↖', '5'], + ['↗', '6'], + ['↙', '7'], + ['↘', '8'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'robotis_koalabot_lite_cm_joystick_value', + }, + paramsKeyMap: { + COMPARE_VAL: 0, + }, + class: 'robotis_koalabot_lite_value', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + let scope = script.executor.scope; + let data_address = 50; + let compareValue = script.getNumberValue('COMPARE_VAL', script); + + let result = Entry.RobotisKoalabotLite.dataBuffer[data_address]; + if (result == undefined) { + return false; + } + + return result == compareValue; + }, + syntax: { + js: [], + py: ['Koalabot.joystick_value()'], + }, + }, + robotis_koalabot_lite_mic: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_string_field', + statements: [], + params: [], + events: {}, + def: { + params: [null], + type: 'robotis_koalabot_lite_mic', + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'robotis_koalabot_lite_value', + isNotFor: ['RobotisKoalabotLite'], + async func(sprite, script) { + let scope = script.executor.scope; + let data_address = 119; + + let result = Entry.RobotisKoalabotLite.dataBuffer[data_address]; + + if (typeof result == 'undefined') { + return 0; + } + return result; + }, + syntax: { + js: [], + py: ['Koalabot.mic()'], + }, + }, + robotis_koalabot_lite_detectSound_compare: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_left, '1'], + [Lang.Blocks.robotis_center, '0'], + [Lang.Blocks.robotis_right, '255'], + ], + value: '255', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'robotis_koalabot_lite_detectSound_compare', + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'robotis_koalabot_lite_value', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + let scope = script.executor.scope; + let data_address = 5031; + let compareValue = script.getNumberValue('VALUE'); + + let result = Entry.RobotisKoalabotLite.dataBuffer[data_address]; + if (result == undefined) { + return false; + } + + return result == compareValue; + }, + syntax: { + js: [], + py: ['Koalabot.detectSound_compare(%1)'], + }, + }, + robotis_koalabot_lite_imu: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['x', '78'], //72 + ['y', '80'], //74 + ['z', '82'], //76 + ], + value: '78', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_acceleration, '0'], //72 + [Lang.Blocks.robotis_gyro, '6'], //74 + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'robotis_koalabot_lite_imu', + }, + paramsKeyMap: { + AXIS: 0, + MODE: 1, + }, + class: 'robotis_koalabot_lite_value', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + let scope = script.executor.scope; + let data_address = + script.getField('AXIS', script) - script.getField('MODE', script); + + let result = Entry.RobotisKoalabotLite.dataBuffer[data_address]; + + if (typeof result == 'undefined') { + return 0; + } + return result; + }, + syntax: { + js: [], + py: ['Koalabot.imu()'], + }, + }, + robotis_koalabot_lite_roll_pitch: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_roll, '70'], //72 + [Lang.Blocks.robotis_pitch, '88'], //74 + ], + value: '70', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'robotis_koalabot_lite_roll_pitch', + }, + paramsKeyMap: { + AXIS: 0, + }, + class: 'robotis_koalabot_lite_value', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + let scope = script.executor.scope; + let data_address = script.getNumberValue('AXIS'); + + let result = Entry.RobotisKoalabotLite.dataBuffer[data_address]; + + if (typeof result == 'undefined') { + return 0; + } + return result; + }, + syntax: { + js: [], + py: ['Koalabot.roll_pitch(%1)'], + }, + }, + robotis_koalabot_lite_distance_value: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_sensing_distance, '25'], + [Lang.Blocks.robotis_sensing_button, '24'], + [Lang.Blocks.robotis_sensing_brightness, '30'], + ], + value: '25', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'robotis_koalabot_lite_distance_value', + }, + paramsKeyMap: { + ADDR: 0, + }, + class: 'robotis_koalabot_lite_value', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + let scope = script.executor.scope; + let data_address = script.getNumberValue('ADDR'); + + let result = 0; + + switch (data_address) { + case 25: + result = Entry.RobotisKoalabotLite.distanceDistance[0]; + break; + + case 24: + result = Entry.RobotisKoalabotLite.distanceButton[0]; + break; + + case 30: + result = Entry.RobotisKoalabotLite.distanceBrightness[0]; + break; + } + + if (typeof result == 'undefined') { + return 0; + } + + if (data_address == 25) { + if (result > 1000) result = 1000; + } + return result; + }, + syntax: { + js: [], + py: ['Koalabot.distance_value(%1)'], + }, + }, + robotis_koalabot_lite_distance_compare: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_sensing_distance, '25'], + [Lang.Blocks.robotis_sensing_button, '24'], + [Lang.Blocks.robotis_sensing_brightness, '30'], + ], + value: '25', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + value: '', + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_if_greater, '0'], + [Lang.Blocks.robotis_if_smaller, '1'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [ + null, + { + type: 'number', + params: [0], + }, + null, + ], + type: 'robotis_koalabot_lite_distance_compare', + }, + paramsKeyMap: { + ADDR: 0, + COMPARE_VAL: 1, + COMPARE_OP: 2, + }, + class: 'robotis_koalabot_lite_value', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + let scope = script.executor.scope; + + let data_address = script.getNumberValue('ADDR'); + let compareValue = script.getNumberValue('COMPARE_VAL'); + let compareOP = script.getNumberValue('COMPARE_OP'); + + let result = 0; + + switch (data_address) { + case 25: + result = Entry.RobotisKoalabotLite.distanceDistance[0]; + break; + + case 24: + result = Entry.RobotisKoalabotLite.distanceButton[0]; + break; + + case 30: + result = Entry.RobotisKoalabotLite.distanceBrightness[0]; + break; + } + + if (typeof result == 'undefined') { + return false; + } + + if (data_address == 25) { + if (result > 1000) result = 1000; + } + + switch (compareOP) { + case 0: + return result > compareValue; + case 1: + return result < compareValue; + case 2: + return result == compareValue; + default: + return false; + } + }, + syntax: { + js: [], + py: ['Koalabot.distance_compare(%1)'], + }, + }, + robotis_koalabot_lite_dxl_value: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_left_wheel, '36'], + [Lang.Blocks.robotis_right_wheel, '35'], + ], + value: '36', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_dxl_value_angle, '1'], + [Lang.Blocks.robotis_dxl_value_velocity, '2'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [36, null], + type: 'robotis_koalabot_lite_dxl_value', + }, + paramsKeyMap: { + ID: 0, + TYPE: 1, + }, + class: 'robotis_koalabot_lite_value', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + let scope = script.executor.scope; + + let dxl_id = script.getNumberValue('ID'); + //var data_type = script.getNumberValue('TYPE'); + + let result = Entry.RobotisKoalabotLite.dxlPositions[dxl_id]; + + if (typeof result == 'undefined') { + return 0; + } + result = 180 - Math.round((result * 360) / 4096); + while (result < -180) { + result += 360; + } + while (result > 180) { + result -= 360; + } + + return result; + }, + syntax: { + js: [], + py: ['Koalabot.get_dxl_value(%1)'], + }, + }, + robotis_koalabot_lite_line_cross_compare: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_line_cross_type_5, '5'], + [Lang.Blocks.robotis_line_cross_type_6, '6'], + [Lang.Blocks.robotis_line_cross_type_7, '7'], + [Lang.Blocks.robotis_line_cross_type_8, '8'], + ], + value: '5', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'robotis_koalabot_lite_line_cross_compare', + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'robotis_koalabot_lite_value', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + let scope = script.executor.scope; + let data_address = 5201; + let compareValue = script.getNumberValue('VALUE'); + + let result = Entry.RobotisKoalabotLite.dataBuffer[data_address]; + + if (result == undefined) { + return false; + } + + return result == compareValue; + }, + syntax: { + js: [], + py: ['Koalabot.line_cross_compare(%1)'], + }, + }, + + robotis_koalabot_lite_screen: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_rla, '2'], + [Lang.Blocks.robotis_rgee, '0'], + [Lang.Blocks.robotis_kkokdu, '3'], + ], + value: '2', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_car_anim01, '2817'], + [Lang.Blocks.robotis_car_anim02, '2818'], + [Lang.Blocks.robotis_car_anim03, '2819'], + [Lang.Blocks.robotis_car_anim04, '2820'], + [Lang.Blocks.robotis_car_anim05, '2821'], + + [Lang.Blocks.robotis_car_anim06, '2822'], + //[Lang.Blocks.robotis_car_anim07, '2823'], + [Lang.Blocks.robotis_car_anim08, '2824'], + [Lang.Blocks.robotis_car_anim09, '2825'], + [Lang.Blocks.robotis_car_anim10, '2826'], + + [Lang.Blocks.robotis_car_anim11, '2827'], + [Lang.Blocks.robotis_car_anim12, '2828'], + //[Lang.Blocks.robotis_car_anim13, '2829'], + [Lang.Blocks.robotis_car_anim14, '2830'], + [Lang.Blocks.robotis_car_anim15, '2831'], + + [Lang.Blocks.robotis_car_anim16, '2832'], + [Lang.Blocks.robotis_car_anim17, '2833'], + [Lang.Blocks.robotis_car_anim18, '2834'], + [Lang.Blocks.robotis_car_anim19, '2835'], + ], + value: '2817', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'robotis_koalabot_lite_screen', + }, + paramsKeyMap: { + ROBOT_TYPE: 0, + BACKGROUND: 1, + }, + class: 'robotis_koalabot_lite_lcd', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let robotType = script.getNumberValue('ROBOT_TYPE', script); + let screenValue = script.getNumberValue('BACKGROUND', script); + + let data_instruction = INST_WRITE; + let data_address = 163; + let data_length = 2; + let data_value = screenValue + robotType * 256; + + if (robotType == 0) { + switch (screenValue) { + case 2817: + data_value = 2841; + break; + + case 2818: + data_value = 2842; + break; + + case 2819: + data_value = 2820; + break; + + case 2820: + data_value = 2817; + break; + + case 2821: + data_value = 2819; + break; + + case 2822: + data_value = 2818; + break; + + //case 2823: + // break; + + case 2824: + data_value = 2826; + break; + + case 2825: + data_value = 2836; + break; + + case 2826: + data_value = 2837; + break; + + case 2827: + data_value = 2843; + break; + + case 2828: + data_value = 2831; + break; + + //case 2829: + // break; + + case 2830: + data_value = 2833; + break; + + case 2831: + data_value = 2834; + break; + + case 2832: + data_value = 2828; + break; + + case 2833: + data_value = 2827; + break; + + case 2834: + data_value = 2829; + break; + + case 2835: + data_value = 2840; + break; + + default: + data_value = 2841; + break; + } + } + + let data_sendqueue = [ + [data_instruction, data_address, data_length, data_value], + [INST_WRITE, 162, 1, 1], + ]; + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + 200 + ); + }, + syntax: { js: [], py: ['Koalabot.screen(%1)'] }, + }, + + robotis_koalabot_lite_anim_screen: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_rla, '0'], + [Lang.Blocks.robotis_rgee, '-1'], + [Lang.Blocks.robotis_kkokdu, '1'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_car_anim01, '30978'], + [Lang.Blocks.robotis_car_anim02, '30981'], + //[Lang.Blocks.robotis_car_anim03, '30982'], + [Lang.Blocks.robotis_car_anim04, '30983'], + [Lang.Blocks.robotis_car_anim05, '30984'], + + [Lang.Blocks.robotis_car_anim06, '30985'], + [Lang.Blocks.robotis_car_anim07, '30986'], + [Lang.Blocks.robotis_car_anim08, '30987'], + [Lang.Blocks.robotis_car_anim09, '30988'], + [Lang.Blocks.robotis_car_anim10, '30989'], + + [Lang.Blocks.robotis_car_anim11, '30990'], + [Lang.Blocks.robotis_car_anim12, '30991'], + //[Lang.Blocks.robotis_car_anim13, '30992'], + [Lang.Blocks.robotis_car_anim14, '30993'], + [Lang.Blocks.robotis_car_anim15, '30994'], + + [Lang.Blocks.robotis_car_anim16, '30995'], + [Lang.Blocks.robotis_car_anim17, '30996'], + [Lang.Blocks.robotis_car_anim18, '30997'], + [Lang.Blocks.robotis_car_anim19, '30998'], + ], + value: '30978', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'robotis_koalabot_lite_anim_screen', + }, + paramsKeyMap: { + ROBOT_TYPE: 0, + BACKGROUND: 1, + }, + class: 'robotis_koalabot_lite_lcd', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let robotType = script.getNumberValue('ROBOT_TYPE', script); + let screenValue = script.getNumberValue('BACKGROUND', script); + + let data_instruction = INST_WRITE; + let data_address = 163; + let data_length = 2; + let data_value = screenValue; + + if (robotType >= 0) { + data_value += 256 * robotType; + } else { + switch (screenValue) { + case 30978: + data_value = 30724; + break; + + case 30981: + data_value = 30761; + break; + + //case 30982: + // break; + + case 30983: + data_value = 30748; + break; + + case 30984: + data_value = 30750; + break; + + case 30985: + data_value = 30749; + break; + + //case 30986: + // break; + + case 30987: + data_value = 30739; + break; + + case 30988: + data_value = 30751; + break; + + case 30989: + data_value = 30752; + break; + + case 30990: + data_value = 30762; + break; + + case 30991: + data_value = 30736; + break; + + //case 30992: + // break; + + case 30993: + data_value = 30742; + break; + + case 30994: + data_value = 30743; + break; + + case 30995: + data_value = 30734; + break; + + case 30996: + data_value = 30733; + break; + + case 30997: + data_value = 30732; + break; + + case 30998: + data_value = 30760; + break; + + default: + data_value = 30724; + break; + } + } + + let data_sendqueue = [ + [data_instruction, data_address, data_length, data_value], + [INST_WRITE, 162, 1, 1], + ]; + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY //+ 1000 + ); + }, + syntax: { js: [], py: ['Koalabot.animation_screen(%1)'] }, + }, + robotis_koalabot_lite_icon_screen_food_plant: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_icon_food_plant_1, '10496'], + [Lang.Blocks.robotis_icon_food_plant_2, '10497'], + [Lang.Blocks.robotis_icon_food_plant_3, '10498'], + [Lang.Blocks.robotis_icon_food_plant_4, '10499'], + [Lang.Blocks.robotis_icon_food_plant_5, '10500'], + [Lang.Blocks.robotis_icon_food_plant_6, '10501'], + [Lang.Blocks.robotis_icon_food_plant_7, '10502'], + [Lang.Blocks.robotis_icon_food_plant_8, '10503'], + [Lang.Blocks.robotis_icon_food_plant_9, '10504'], + [Lang.Blocks.robotis_icon_food_plant_10, '10505'], + [Lang.Blocks.robotis_icon_food_plant_11, '10506'], + [Lang.Blocks.robotis_icon_food_plant_12, '10507'], + [Lang.Blocks.robotis_icon_food_plant_13, '10508'], + [Lang.Blocks.robotis_icon_food_plant_14, '10509'], + [Lang.Blocks.robotis_icon_food_plant_15, '10510'], + [Lang.Blocks.robotis_icon_food_plant_16, '10511'], + [Lang.Blocks.robotis_icon_food_plant_17, '10512'], + [Lang.Blocks.robotis_icon_food_plant_18, '10513'], + [Lang.Blocks.robotis_icon_food_plant_19, '10514'], + [Lang.Blocks.robotis_icon_food_plant_20, '10515'], + [Lang.Blocks.robotis_icon_food_plant_21, '10516'], + [Lang.Blocks.robotis_icon_food_plant_22, '10517'], + [Lang.Blocks.robotis_icon_food_plant_23, '10518'], + [Lang.Blocks.robotis_icon_food_plant_24, '10519'], + ], + value: '10496', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + { + type: 'number', + params: ['0'], + }, + { + type: 'number', + params: ['0'], + }, + 50, + null, + ], + type: 'robotis_koalabot_lite_icon_screen_food_plant', + }, + paramsKeyMap: { + ICON: 0, + X: 1, + Y: 2, + SIZE: 3, + }, + class: 'robotis_koalabot_lite_lcd', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let iconNum = script.getField('ICON', script); + let x = script.getNumberValue('X', script); + let y = script.getNumberValue('Y', script); + let size = script.getNumberValue('SIZE', script) * 2; + + let data_instruction = INST_WRITE; + let data_address = 166; + let data_length = 2; + let data_value = 10496; + + if (x < -160) { + x = -160; + } else if (x > 160) { + x = 160; + } + + if (y < -120) { + y = -120; + } else if (y > 120) { + y = 120; + } + + if (size < 0) { + size = 0; + } else if (size > 400) { + size = 400; + } + + data_value = iconNum; + + let data_sendqueue = [ + [INST_WRITE, 130, 2, x], + [INST_WRITE, 132, 2, y], + [INST_WRITE, 149, 2, size], + [data_instruction, data_address, data_length, data_value], + [INST_WRITE, 162, 1, 1], + ]; + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + 200 + ); + }, + syntax: { + js: [], + py: ['Koalabot.icon_screen_food_and_plant(%1,%2,%3,%4)'], + }, + }, + robotis_koalabot_lite_icon_screen_animal_human: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_icon_animal_human_1, '10752'], + [Lang.Blocks.robotis_icon_animal_human_2, '10753'], + [Lang.Blocks.robotis_icon_animal_human_3, '10754'], + [Lang.Blocks.robotis_icon_animal_human_4, '10755'], + [Lang.Blocks.robotis_icon_animal_human_5, '10756'], + [Lang.Blocks.robotis_icon_animal_human_6, '10757'], + [Lang.Blocks.robotis_icon_animal_human_7, '10758'], + [Lang.Blocks.robotis_icon_animal_human_8, '10759'], + [Lang.Blocks.robotis_icon_animal_human_9, '10760'], + [Lang.Blocks.robotis_icon_animal_human_10, '11787'], + [Lang.Blocks.robotis_icon_animal_human_11, '11788'], + [Lang.Blocks.robotis_icon_animal_human_12, '11789'], + [Lang.Blocks.robotis_icon_animal_human_13, '11790'], + [Lang.Blocks.robotis_icon_animal_human_14, '11805'], + [Lang.Blocks.robotis_icon_animal_human_15, '11806'], + [Lang.Blocks.robotis_icon_animal_human_16, '11807'], + [Lang.Blocks.robotis_icon_animal_human_17, '11808'], + [Lang.Blocks.robotis_icon_animal_human_18, '10761'], + [Lang.Blocks.robotis_icon_animal_human_19, '10762'], + [Lang.Blocks.robotis_icon_animal_human_20, '10763'], + [Lang.Blocks.robotis_icon_animal_human_21, '10764'], + [Lang.Blocks.robotis_icon_animal_human_22, '10765'], + [Lang.Blocks.robotis_icon_animal_human_23, '10766'], + [Lang.Blocks.robotis_icon_animal_human_24, '10767'], + [Lang.Blocks.robotis_icon_animal_human_25, '10768'], + [Lang.Blocks.robotis_icon_animal_human_26, '10769'], + [Lang.Blocks.robotis_icon_animal_human_27, '10770'], + [Lang.Blocks.robotis_icon_animal_human_28, '10771'], + [Lang.Blocks.robotis_icon_animal_human_29, '10772'], + [Lang.Blocks.robotis_icon_animal_human_30, '10773'], + [Lang.Blocks.robotis_icon_animal_human_31, '10774'], + [Lang.Blocks.robotis_icon_animal_human_32, '10775'], + [Lang.Blocks.robotis_icon_animal_human_33, '10776'], + [Lang.Blocks.robotis_icon_animal_human_34, '10777'], + ], + value: '10752', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + { + type: 'number', + params: ['0'], + }, + { + type: 'number', + params: ['0'], + }, + 50, + null, + ], + type: 'robotis_koalabot_lite_icon_screen_animal_human', + }, + paramsKeyMap: { + ICON: 0, + X: 1, + Y: 2, + SIZE: 3, + }, + class: 'robotis_koalabot_lite_lcd', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let iconNum = script.getField('ICON', script); + let x = script.getNumberValue('X', script); + let y = script.getNumberValue('Y', script); + let size = script.getNumberValue('SIZE', script) * 2; + + let data_instruction = INST_WRITE; + let data_address = 166; + let data_length = 2; + let data_value = 10496; + + if (x < -160) { + x = -160; + } else if (x > 160) { + x = 160; + } + + if (y < -120) { + y = -120; + } else if (y > 120) { + y = 120; + } + + if (size < 0) { + size = 0; + } else if (size > 400) { + size = 400; + } + + data_value = iconNum; + + let data_sendqueue = [ + [INST_WRITE, 130, 2, x], + [INST_WRITE, 132, 2, y], + [INST_WRITE, 149, 2, size], + [data_instruction, data_address, data_length, data_value], + [INST_WRITE, 162, 1, 1], + ]; + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + 200 + ); + }, + syntax: { + js: [], + py: ['Koalabot.icon_screen_animal_and_human(%1,%2,%3,%4)'], + }, + }, + robotis_koalabot_lite_icon_screen_object_tool: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_icon_object_tool_1, '11008'], + [Lang.Blocks.robotis_icon_object_tool_2, '11009'], + [Lang.Blocks.robotis_icon_object_tool_3, '11010'], + [Lang.Blocks.robotis_icon_object_tool_4, '11011'], + [Lang.Blocks.robotis_icon_object_tool_5, '11012'], + [Lang.Blocks.robotis_icon_object_tool_6, '11013'], + [Lang.Blocks.robotis_icon_object_tool_7, '11014'], + [Lang.Blocks.robotis_icon_object_tool_8, '11015'], + [Lang.Blocks.robotis_icon_object_tool_9, '11016'], + [Lang.Blocks.robotis_icon_object_tool_10, '11017'], + [Lang.Blocks.robotis_icon_object_tool_11, '11018'], + [Lang.Blocks.robotis_icon_object_tool_12, '11019'], + [Lang.Blocks.robotis_icon_object_tool_13, '11020'], + [Lang.Blocks.robotis_icon_object_tool_14, '11021'], + [Lang.Blocks.robotis_icon_object_tool_15, '11022'], + [Lang.Blocks.robotis_icon_object_tool_16, '11023'], + [Lang.Blocks.robotis_icon_object_tool_17, '11024'], + [Lang.Blocks.robotis_icon_object_tool_18, '11025'], + [Lang.Blocks.robotis_icon_object_tool_19, '11026'], + [Lang.Blocks.robotis_icon_object_tool_20, '11027'], + [Lang.Blocks.robotis_icon_object_tool_21, '11028'], + [Lang.Blocks.robotis_icon_object_tool_22, '11029'], + [Lang.Blocks.robotis_icon_object_tool_23, '11030'], + [Lang.Blocks.robotis_icon_object_tool_24, '11031'], + [Lang.Blocks.robotis_icon_object_tool_25, '11032'], + [Lang.Blocks.robotis_icon_object_tool_26, '11033'], + [Lang.Blocks.robotis_icon_object_tool_27, '11034'], + [Lang.Blocks.robotis_icon_object_tool_28, '11035'], + [Lang.Blocks.robotis_icon_object_tool_29, '11036'], + [Lang.Blocks.robotis_icon_object_tool_30, '11037'], + [Lang.Blocks.robotis_icon_object_tool_31, '11038'], + [Lang.Blocks.robotis_icon_object_tool_32, '11039'], + [Lang.Blocks.robotis_icon_object_tool_33, '11040'], + [Lang.Blocks.robotis_icon_object_tool_34, '11801'], + [Lang.Blocks.robotis_icon_object_tool_35, '11802'], + [Lang.Blocks.robotis_icon_object_tool_36, '11809'], + ], + value: '11008', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + { + type: 'number', + params: ['0'], + }, + { + type: 'number', + params: ['0'], + }, + 50, + null, + ], + type: 'robotis_koalabot_lite_icon_screen_object_tool', + }, + paramsKeyMap: { + ICON: 0, + X: 1, + Y: 2, + SIZE: 3, + }, + class: 'robotis_koalabot_lite_lcd', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let iconNum = script.getField('ICON', script); + let x = script.getNumberValue('X', script); + let y = script.getNumberValue('Y', script); + let size = script.getNumberValue('SIZE', script) * 2; + + let data_instruction = INST_WRITE; + let data_address = 166; + let data_length = 2; + let data_value = 10496; + + if (x < -160) { + x = -160; + } else if (x > 160) { + x = 160; + } + + if (y < -120) { + y = -120; + } else if (y > 120) { + y = 120; + } + + if (size < 0) { + size = 0; + } else if (size > 400) { + size = 400; + } + + data_value = iconNum; + + let data_sendqueue = [ + [INST_WRITE, 130, 2, x], + [INST_WRITE, 132, 2, y], + [INST_WRITE, 149, 2, size], + [data_instruction, data_address, data_length, data_value], + [INST_WRITE, 162, 1, 1], + ]; + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + 200 + ); + }, + syntax: { + js: [], + py: ['Koalabot.icon_screen_object_and_tool(%1,%2,%3,%4)'], + }, + }, + robotis_koalabot_lite_icon_screen_vehicle_number: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_icon_vehicle_number_1, '11264'], + [Lang.Blocks.robotis_icon_vehicle_number_2, '11265'], + [Lang.Blocks.robotis_icon_vehicle_number_3, '11266'], + [Lang.Blocks.robotis_icon_vehicle_number_4, '11267'], + [Lang.Blocks.robotis_icon_vehicle_number_5, '11268'], + [Lang.Blocks.robotis_icon_vehicle_number_6, '11269'], + [Lang.Blocks.robotis_icon_vehicle_number_7, '11270'], + [Lang.Blocks.robotis_icon_vehicle_number_8, '11271'], + [Lang.Blocks.robotis_icon_vehicle_number_9, '11272'], + [Lang.Blocks.robotis_icon_vehicle_number_10, '11273'], + [Lang.Blocks.robotis_icon_vehicle_number_11, '11274'], + [Lang.Blocks.robotis_icon_vehicle_number_12, '11275'], + [Lang.Blocks.robotis_icon_vehicle_number_13, '11276'], + [Lang.Blocks.robotis_icon_vehicle_number_14, '11776'], + [Lang.Blocks.robotis_icon_vehicle_number_15, '11777'], + [Lang.Blocks.robotis_icon_vehicle_number_16, '11778'], + [Lang.Blocks.robotis_icon_vehicle_number_17, '11779'], + [Lang.Blocks.robotis_icon_vehicle_number_18, '11780'], + [Lang.Blocks.robotis_icon_vehicle_number_19, '11781'], + [Lang.Blocks.robotis_icon_vehicle_number_20, '11782'], + [Lang.Blocks.robotis_icon_vehicle_number_21, '11783'], + [Lang.Blocks.robotis_icon_vehicle_number_22, '11277'], + [Lang.Blocks.robotis_icon_vehicle_number_23, '11278'], + [Lang.Blocks.robotis_icon_vehicle_number_24, '11279'], + [Lang.Blocks.robotis_icon_vehicle_number_25, '11280'], + [Lang.Blocks.robotis_icon_vehicle_number_26, '11281'], + [Lang.Blocks.robotis_icon_vehicle_number_27, '11282'], + [Lang.Blocks.robotis_icon_vehicle_number_28, '11283'], + [Lang.Blocks.robotis_icon_vehicle_number_29, '11284'], + [Lang.Blocks.robotis_icon_vehicle_number_30, '11285'], + [Lang.Blocks.robotis_icon_vehicle_number_31, '11286'], + [Lang.Blocks.robotis_icon_vehicle_number_32, '11287'], + [Lang.Blocks.robotis_icon_vehicle_number_33, '11288'], + [Lang.Blocks.robotis_icon_vehicle_number_34, '11289'], + [Lang.Blocks.robotis_icon_vehicle_number_35, '11290'], + [Lang.Blocks.robotis_icon_vehicle_number_36, '11291'], + [Lang.Blocks.robotis_icon_vehicle_number_37, '11292'], + [Lang.Blocks.robotis_icon_vehicle_number_38, '11293'], + ], + value: '11264', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + { + type: 'number', + params: ['0'], + }, + { + type: 'number', + params: ['0'], + }, + 50, + null, + ], + type: 'robotis_koalabot_lite_icon_screen_vehicle_number', + }, + paramsKeyMap: { + ICON: 0, + X: 1, + Y: 2, + SIZE: 3, + }, + class: 'robotis_koalabot_lite_lcd', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let iconNum = script.getField('ICON', script); + let x = script.getNumberValue('X', script); + let y = script.getNumberValue('Y', script); + let size = script.getNumberValue('SIZE', script) * 2; + + let data_instruction = INST_WRITE; + let data_address = 166; + let data_length = 2; + let data_value = 10496; + + if (x < -160) { + x = -160; + } else if (x > 160) { + x = 160; + } + + if (y < -120) { + y = -120; + } else if (y > 120) { + y = 120; + } + + if (size < 0) { + size = 0; + } else if (size > 400) { + size = 400; + } + + data_value = iconNum; + + let data_sendqueue = [ + [INST_WRITE, 130, 2, x], + [INST_WRITE, 132, 2, y], + [INST_WRITE, 149, 2, size], + [data_instruction, data_address, data_length, data_value], + [INST_WRITE, 162, 1, 1], + ]; + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + 200 + ); + }, + syntax: { + js: [], + py: ['Koalabot.icon_screen_vehicle_and_number(%1,%2,%3,%4)'], + }, + }, + robotis_koalabot_lite_text_screen: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_screen_text_font_small, '0'], + [Lang.Blocks.robotis_screen_text_font_big, '1'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_red, '224'], + [Lang.Blocks.robotis_orange, '244'], + [Lang.Blocks.robotis_yellow, '252'], + [Lang.Blocks.robotis_green, '28'], + [Lang.Blocks.robotis_blue, '3'], + [Lang.Blocks.robotis_darkblue, '2'], + [Lang.Blocks.robotis_purple, '130'], + [Lang.Blocks.robotis_brown, '173'], + [Lang.Blocks.robotis_black, '0'], + [Lang.Blocks.robotis_white, '255'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + ' ', + { + type: 'number', + params: ['0'], + }, + { + type: 'number', + params: ['0'], + }, + null, + null, + ], + type: 'robotis_koalabot_lite_text_screen', + }, + paramsKeyMap: { + TEXT: 0, + X: 1, + Y: 2, + FONT: 3, + COLOR: 4, + }, + class: 'robotis_koalabot_lite_lcd', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let text = script.getStringValue('TEXT', script); + let x = script.getNumberValue('X', script); + let y = script.getNumberValue('Y', script); + let font = script.getNumberValue('FONT', script); + let color = script.getNumberValue('COLOR', script); + let data_buf = []; + let i = 0; + + let data_instruction = INST_WRITE; + let data_address = 900; + let data_length = 2; + + if (x < -160) { + x = -160; + } else if (x > 160) { + x = 160; + } + + if (y < -120) { + y = -120; + } else if (y > 120) { + y = 120; + } + + let encoder = new TextEncoder('utf-8'); + let byteArray = encoder.encode(text); + + data_buf.push(x % 256); + data_buf.push(Math.floor(x / 256)); + data_buf.push(y % 256); + data_buf.push(Math.floor(y / 256)); + data_buf.push(font); + data_buf.push(0); + data_buf.push(0); + data_buf.push(color); + data_buf.push(byteArray.length); + for (i = 0; i < byteArray.length; i++) { + data_buf.push(byteArray[i]); + } + + data_length = 9 + byteArray.length; + + let data_sendqueue = [ + [data_instruction, data_address, data_length, data_buf], + [INST_WRITE, 162, 1, 1], + ]; + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + 200 + ); + }, + syntax: { + js: [], + py: ['Koalabot.text_screen(%1,%2,%3,%4,%5)'], + }, + }, + robotis_koalabot_lite_pixel: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_red, '224'], + [Lang.Blocks.robotis_orange, '244'], + [Lang.Blocks.robotis_yellow, '252'], + [Lang.Blocks.robotis_green, '28'], + [Lang.Blocks.robotis_blue, '3'], + [Lang.Blocks.robotis_darkblue, '2'], + [Lang.Blocks.robotis_purple, '130'], + [Lang.Blocks.robotis_brown, '173'], + [Lang.Blocks.robotis_black, '0'], + [Lang.Blocks.robotis_white, '255'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + { + type: 'number', + params: ['0'], + }, + { + type: 'number', + params: ['0'], + }, + null, + ], + type: 'robotis_koalabot_lite_pixel', + }, + paramsKeyMap: { + X: 0, + Y: 1, + COLOR: 2, + }, + class: 'robotis_koalabot_lite_lcd', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let x = script.getNumberValue('X', script); + let y = script.getNumberValue('Y', script); + let color = script.getNumberValue('COLOR', script); + let data_buf = []; + + let data_instruction = INST_WRITE; + let data_address = 130; + let data_length = 11; + + if (x < -160) { + x = -160; + } else if (x > 160) { + x = 160; + } + + if (y < -120) { + y = -120; + } else if (y > 120) { + y = 120; + } + + data_buf.push(x % 256); + data_buf.push(Math.floor(x / 256)); + data_buf.push(y % 256); + data_buf.push(Math.floor(y / 256)); + data_buf.push(0); + data_buf.push(0); + data_buf.push(0); + data_buf.push(0); + data_buf.push(0); + data_buf.push(0); + data_buf.push(color); + + let data_sendqueue = [ + [data_instruction, data_address, data_length, data_buf], + [INST_WRITE, 161, 2, 1 * 256 + 8], + ]; + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + 100 + ); + }, + syntax: { + js: [], + py: ['Koalabot.pixel(%1,%2,%3)'], + }, + }, + robotis_koalabot_lite_text_screen_redraw: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_red, '224'], + [Lang.Blocks.robotis_orange, '244'], + [Lang.Blocks.robotis_yellow, '252'], + [Lang.Blocks.robotis_green, '28'], + [Lang.Blocks.robotis_blue, '3'], + [Lang.Blocks.robotis_darkblue, '2'], + [Lang.Blocks.robotis_purple, '130'], + [Lang.Blocks.robotis_brown, '173'], + [Lang.Blocks.robotis_black, '0'], + [Lang.Blocks.robotis_white, '255'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + ' ', + { + type: 'number', + params: ['0'], + }, + { + type: 'number', + params: ['0'], + }, + null, + ], + type: 'robotis_koalabot_lite_text_screen_redraw', + }, + paramsKeyMap: { + TEXT: 0, + X: 1, + Y: 2, + COLOR: 3, + }, + class: 'robotis_koalabot_lite_lcd', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let text = script.getStringValue('TEXT', script); + let x = script.getNumberValue('X', script); + let y = script.getNumberValue('Y', script); + let font = 0; + let color = script.getNumberValue('COLOR', script); + let data_buf = []; + let i = 0; + + if (x < -160) { + x = -160; + } else if (x > 160) { + x = 160; + } + + if (y < -120) { + y = -120; + } else if (y > 120) { + y = 120; + } + + let encoder = new TextEncoder('utf-8'); + let byteArray = encoder.encode(text); + + data_buf.push(x % 256); + data_buf.push(Math.floor(x / 256)); + data_buf.push(y % 256); + data_buf.push(Math.floor(y / 256)); + data_buf.push(font); + data_buf.push(1); + data_buf.push(bg_color); + data_buf.push(color); + data_buf.push(byteArray.length); + for (i = 0; i < byteArray.length; i++) { + data_buf.push(byteArray[i]); + } + + let data_instruction = INST_WRITE; + let data_address = 900; + let data_length = 9 + byteArray.length; + + let data_sendqueue = [ + [data_instruction, data_address, data_length, data_buf], + [INST_WRITE, 162, 1, 1], + ]; + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + 100 + ); + }, + syntax: { + js: [], + py: ['Koalabot.text_screen_redraw(%1,%2,%3,%4)'], + }, + }, + robotis_koalabot_lite_LCDBright: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [50], + type: 'robotis_koalabot_lite_LCDBright', + }, + paramsKeyMap: { + BRIGHT: 0, + }, + class: 'robotis_koalabot_lite_lcd', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let bright = script.getNumberValue('BRIGHT', script); + + let data_instruction = INST_WRITE; + let data_address = 180; + let data_length = 1; + let data_value = 0; + + bright = Math.min(Math.max(bright, 0), 100); + + data_value = bright; + + let data_sendqueue = [ + [data_instruction, data_address, data_length, data_value], + ]; + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + ); + }, + syntax: { + js: [], + py: ['Koalabot.LCDBright(%1)'], + }, + }, + robotis_koalabot_lite_LCDColor: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_red, '224'], + [Lang.Blocks.robotis_orange, '244'], + [Lang.Blocks.robotis_yellow, '252'], + [Lang.Blocks.robotis_green, '28'], + [Lang.Blocks.robotis_blue, '3'], + [Lang.Blocks.robotis_darkblue, '2'], + [Lang.Blocks.robotis_purple, '130'], + [Lang.Blocks.robotis_brown, '173'], + [Lang.Blocks.robotis_black, '0'], + [Lang.Blocks.robotis_white, '255'], + ], + value: '224', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'robotis_koalabot_lite_LCDColor', + }, + paramsKeyMap: { + COLOR: 0, + }, + class: 'robotis_koalabot_lite_lcd', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let color = script.getNumberValue('COLOR', script); + + let data_instruction = INST_WRITE; + let data_address = 163; + let data_length = 2; + let data_value = 0; + + data_value = color; + bg_color = color; + + let data_sendqueue = [ + [data_instruction, data_address, data_length, data_value], + [INST_WRITE, 162, 1, 1], + ]; + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + 100 + ); + }, + syntax: { + js: [], + py: ['Koalabot.LCDColor(%1)'], + }, + }, + + robotis_koalabot_lite_cm_led: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_left, '1'], + [Lang.Blocks.robotis_right, '2'], + [Lang.Blocks.robotis_both, '3'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_common_on, '1'], + [Lang.Blocks.robotis_common_off, '0'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null], + type: 'robotis_koalabot_lite_cm_led', + }, + paramsKeyMap: { + RB_LED: 0, + VALUE: 1, + }, + class: 'robotis_koalabot_lite_led', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let cmLed = script.getField('RB_LED', script); + let value = script.getField('VALUE', script); + + let data_instruction = INST_WRITE; + let data_address = 40; + let data_length = 1; + let data_value = 0; + + if (cmLed == 1) { + data_value = 200 * value; + } else if (cmLed == 2) { + data_address = 41; + data_value = 200 * value; + } else if (cmLed == 3) { + data_address = 40; + data_length = 2; + data_value = 200 * 257 * value; + } else { + data_value = value * cmLed; + } + + let data_sendqueue = [ + [data_instruction, data_address, data_length, data_value], + ]; + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + ); + }, + syntax: { js: [], py: ['Koalabot.led(%1, %2)'] }, + }, + robotis_koalabot_lite_cm_led_pattern: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_pattern1, '11'], + [Lang.Blocks.robotis_pattern2, '21'], + [Lang.Blocks.robotis_pattern3, '31'], + ], + value: '11', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_speed_fast, '0'], + [Lang.Blocks.robotis_speed_midium, '1'], + [Lang.Blocks.robotis_speed_slow, '2'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null], + type: 'robotis_koalabot_lite_cm_led_pattern', + }, + paramsKeyMap: { + PATTERN: 0, + SPEED: 1, + }, + class: 'robotis_koalabot_lite_led', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let pattern = script.getNumberValue('PATTERN', script); + let speed = script.getNumberValue('SPEED', script); + + let data_instruction = INST_WRITE; + let data_address = 40; + let data_length = 1; + let data_value = 0; + + data_value = pattern + speed; + + let data_sendqueue = [ + [data_instruction, data_address, data_length, data_value], + ]; + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + ); + }, + syntax: { js: [], py: ['Koalabot.led_pattern(%1, %2)'] }, + }, + + robotis_koalabot_lite_scale_simple: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['2', '2'], + ['3', '3'], + ['4', '4'], + ['5', '5'], + ['6', '6'], + ], + value: '4', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.General.note_c + '', '1'], + [Lang.General.note_c + '#', '2'], + [Lang.General.note_d + '', '3'], + [Lang.General.note_d + '#', '4'], + [Lang.General.note_e + '', '5'], + [Lang.General.note_f + '', '6'], + [Lang.General.note_f + '#', '7'], + [Lang.General.note_g + '', '8'], + [Lang.General.note_g + '#', '9'], + [Lang.General.note_a + '', '10'], + [Lang.General.note_a + '#', '11'], + [Lang.General.note_b + '', '12'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_beat_sound_8th_note, '3'], + [Lang.Blocks.robotis_beat_sound_dotted_8th_note, '4'], + [Lang.Blocks.robotis_beat_sound_quarter_note, '5'], + [Lang.Blocks.robotis_beat_sound_dotted_quarter_note, '6'], + [Lang.Blocks.robotis_beat_sound_half_note, '7'], + [Lang.Blocks.robotis_beat_sound_dotted_half_note, '8'], + [Lang.Blocks.robotis_beat_sound_whole_note, '9'], + [Lang.Blocks.robotis_beat_sound_dotted_note, '10'], + ], + value: '5', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null, null], + type: 'robotis_koalabot_lite_scale_simple', + }, + paramsKeyMap: { + CM_BUZZER_OCTAV: 0, + CM_BUZZER_INDEX: 1, + CM_BUZZER_NOTE: 2, + }, + class: 'robotis_koalabot_lite_sound', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let cmBuzzerIndex = script.getNumberValue('CM_BUZZER_INDEX', script); + let cmBuzzerOffset = script.getNumberValue('CM_BUZZER_OCTAV', script); + let cmBuzzerNote = script.getNumberValue('CM_BUZZER_NOTE', script); + let cmBuzzerTime = 0; + + let data_instruction = INST_WRITE; + let data_address = 0; + let data_value = 0; + let interval = 0; + let data_buf = []; + + switch (cmBuzzerNote) { + case 3: + cmBuzzerTime = Math.round((60 * 1000) / beat_per_minute / 2); + break; + + case 4: + cmBuzzerTime = Math.round( + ((60 * 1000) / beat_per_minute / 2) * 1.5 + ); + break; + + case 5: + cmBuzzerTime = Math.round((60 * 1000) / beat_per_minute); + break; + + case 6: + cmBuzzerTime = Math.round(((60 * 1000) / beat_per_minute) * 1.5); + break; + + case 7: + cmBuzzerTime = Math.round(((60 * 1000) / beat_per_minute) * 2); + break; + + case 8: + cmBuzzerTime = Math.round( + ((60 * 1000) / beat_per_minute) * 2 * 1.5 + ); + break; + + case 9: + cmBuzzerTime = Math.round(((60 * 1000) / beat_per_minute) * 4); + break; + + case 10: + cmBuzzerTime = Math.round( + ((60 * 1000) / beat_per_minute) * 4 * 1.5 + ); + break; + } + + data_address = 740; + // data_value_1 = cmBuzzerTime * 10; + // TODO 텍스트 입력으로 바꾸고 최대는 5초 : 0.5 초 하려면 5를 입력 - console.log(parseInt(0.59 * 10)); max 는 5초 + data_value = cmBuzzerTime; + if (data_value < 0) { + data_value = 0; + } + if (data_value > 50000) { + data_value = 50000; + } + + data_buf.push(data_value % 256); + data_buf.push(Math.floor(data_value / 256)); + + data_value = cmBuzzerIndex + (cmBuzzerOffset - 1) * 12; + data_buf.push(Math.floor(data_value)); + + // console.log("buzzer send"); + let data_sendqueue = [[data_instruction, data_address, 3, data_buf]]; + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + cmBuzzerTime + interval + ); + }, + syntax: { + js: [], + py: ['Koalabot.scale_simple(%1, %2, %3)'], + }, + }, + robotis_koalabot_lite_scale_advanced: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['2', '2'], + ['3', '3'], + ['4', '4'], + ['5', '5'], + ['6', '6'], + ], + value: '4', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.General.note_c + '', '1'], + [Lang.General.note_c + '#', '2'], + [Lang.General.note_d + '', '3'], + [Lang.General.note_d + '#', '4'], + [Lang.General.note_e + '', '5'], + [Lang.General.note_f + '', '6'], + [Lang.General.note_f + '#', '7'], + [Lang.General.note_g + '', '8'], + [Lang.General.note_g + '#', '9'], + [Lang.General.note_a + '', '10'], + [Lang.General.note_a + '#', '11'], + [Lang.General.note_b + '', '12'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, 1, null], + type: 'robotis_koalabot_lite_scale_advanced', + }, + paramsKeyMap: { + CM_BUZZER_OCTAV: 0, + CM_BUZZER_INDEX: 1, + CM_BUZZER_BEAT: 2, + }, + class: 'robotis_koalabot_lite_sound', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let cmBuzzerIndex = script.getNumberValue('CM_BUZZER_INDEX', script); + let cmBuzzerOffset = script.getNumberValue('CM_BUZZER_OCTAV', script); + let cmBuzzerBeat = script.getNumberValue('CM_BUZZER_BEAT', script); + let cmBuzzerTime = 0; + + cmBuzzerBeat = Math.min(Math.max(cmBuzzerBeat, 0), 100); + + let data_instruction = INST_WRITE; + let data_address_1 = 0; + let data_length_1 = 0; + let data_value_1 = 0; + let data_address_2 = 0; + let data_length_2 = 0; + let data_value_2 = 0; + let interval = 0; + + cmBuzzerTime = Math.round(((60 * 1000) / beat_per_minute) * cmBuzzerBeat); + + data_address_1 = 740; + data_length_1 = 2; + // data_value_1 = cmBuzzerTime * 10; + // TODO 텍스트 입력으로 바꾸고 최대는 5초 : 0.5 초 하려면 5를 입력 - console.log(parseInt(0.59 * 10)); max 는 5초 + data_value_1 = cmBuzzerTime; + if (data_value_1 < 0) { + data_value_1 = 0; + } + if (data_value_1 > 50000) { + data_value_1 = 50000; + } + + data_address_2 = 742; + data_length_2 = 1; + data_value_2 = cmBuzzerIndex + (cmBuzzerOffset - 1) * 12; + + // console.log("buzzer send"); + let data_sendqueue = [ + [data_instruction, data_address_1, data_length_1, data_value_1], + [data_instruction, data_address_2, data_length_2, data_value_2], + ]; + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + cmBuzzerTime + interval + ); + }, + syntax: { + js: [], + py: ['Koalabot.scale_advanced(%1, %2, %3)'], + }, + }, + robotis_koalabot_lite_rest_simple: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_beat_rest_8th_note, '3'], + [Lang.Blocks.robotis_beat_rest_quarter_note, '5'], + [Lang.Blocks.robotis_beat_rest_half_note, '7'], + [Lang.Blocks.robotis_beat_rest_whole_note, '9'], + ], + value: '5', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'robotis_koalabot_lite_rest_simple', + }, + paramsKeyMap: { + CM_BUZZER_NOTE: 0, + }, + class: 'robotis_koalabot_lite_sound', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let cmBuzzerNote = script.getNumberValue('CM_BUZZER_NOTE', script); + let cmBuzzerTime = 0; + + let interval = 0; + + switch (cmBuzzerNote) { + case 3: + cmBuzzerTime = Math.round((60 * 1000) / beat_per_minute / 2); + break; + + case 5: + cmBuzzerTime = Math.round((60 * 1000) / beat_per_minute); + break; + + case 7: + cmBuzzerTime = Math.round(((60 * 1000) / beat_per_minute) * 2); + break; + + case 9: + cmBuzzerTime = Math.round(((60 * 1000) / beat_per_minute) * 4); + break; + } + + let data_sendqueue = []; + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + cmBuzzerTime + interval + ); + }, + syntax: { + js: [], + py: ['Koalabot.rest_simple(%1)'], + }, + }, + robotis_koalabot_lite_rest_advanced: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [1, null], + type: 'robotis_koalabot_lite_rest_advanced', + }, + paramsKeyMap: { + CM_BUZZER_BEAT: 0, + }, + class: 'robotis_koalabot_lite_sound', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let cmBuzzerBeat = script.getNumberValue('CM_BUZZER_BEAT', script); + let cmBuzzerTime = 0; + + let interval = 0; + + cmBuzzerBeat = Math.min(Math.max(cmBuzzerBeat, 0), 100); + + cmBuzzerTime = Math.round(((60 * 1000) / beat_per_minute) * cmBuzzerBeat); + + let data_sendqueue = []; + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + cmBuzzerTime + interval + ); + }, + syntax: { + js: [], + py: ['Koalabot.rest_advanced(%1)'], + }, + }, + robotis_koalabot_lite_beat_per_minute: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [75, null], + type: 'robotis_koalabot_lite_beat_per_minute', + }, + paramsKeyMap: { + CM_BUZZER_BPM: 0, + }, + class: 'robotis_koalabot_lite_sound', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let cmBuzzerBpm = script.getNumberValue('CM_BUZZER_BPM', script); + + beat_per_minute = Math.min(Math.max(cmBuzzerBpm, 10), 600); + + // console.log("buzzer send"); + let data_sendqueue = []; + + return Entry.RobotisKoalabotLite.postCallReturn(script, data_sendqueue, 0); + }, + syntax: { + js: [], + py: ['Koalabot.set_bpm(%1)'], + }, + }, + + robotis_koalabot_lite_Hello: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_korean1, '0'], + [Lang.Blocks.robotis_korean2, '1'], + [Lang.Blocks.robotis_korean3, '2'], + [Lang.Blocks.robotis_korean4, '3'], + [Lang.Blocks.robotis_korean5, '4'], + [Lang.Blocks.robotis_korean6, '5'], + [Lang.Blocks.robotis_korean7, '6'], + [Lang.Blocks.robotis_korean8, '7'], + [Lang.Blocks.robotis_korean9, '8'], + [Lang.Blocks.robotis_korean10, '9'], + [Lang.Blocks.robotis_korean11, '10'], + [Lang.Blocks.robotis_korean12, '11'], + [Lang.Blocks.robotis_korean13, '12'], + [Lang.Blocks.robotis_korean14, '13'], + [Lang.Blocks.robotis_korean15, '14'], + [Lang.Blocks.robotis_korean16, '15'], + [Lang.Blocks.robotis_korean17, '16'], + [Lang.Blocks.robotis_korean18, '17'], + [Lang.Blocks.robotis_korean19, '18'], + [Lang.Blocks.robotis_korean20, '19'], + [Lang.Blocks.robotis_korean21, '20'], + [Lang.Blocks.robotis_korean22, '21'], + [Lang.Blocks.robotis_korean23, '22'], + [Lang.Blocks.robotis_korean24, '23'], + [Lang.Blocks.robotis_korean25, '24'], + [Lang.Blocks.robotis_korean26, '25'], + [Lang.Blocks.robotis_korean27, '26'], + [Lang.Blocks.robotis_korean28, '27'], + [Lang.Blocks.robotis_korean29, '28'], + [Lang.Blocks.robotis_korean30, '29'], + [Lang.Blocks.robotis_korean31, '30'], + [Lang.Blocks.robotis_korean32, '31'], + [Lang.Blocks.robotis_korean33, '32'], + [Lang.Blocks.robotis_korean34, '33'], + [Lang.Blocks.robotis_korean35, '34'], + [Lang.Blocks.robotis_korean36, '35'], + [Lang.Blocks.robotis_korean37, '36'], + [Lang.Blocks.robotis_korean38, '37'], + [Lang.Blocks.robotis_korean39, '38'], + [Lang.Blocks.robotis_korean40, '39'], + [Lang.Blocks.robotis_korean41, '40'], + [Lang.Blocks.robotis_korean42, '41'], + [Lang.Blocks.robotis_korean43, '42'], + [Lang.Blocks.robotis_korean44, '43'], + [Lang.Blocks.robotis_korean45, '44'], + [Lang.Blocks.robotis_korean46, '45'], + [Lang.Blocks.robotis_korean47, '46'], + [Lang.Blocks.robotis_korean48, '47'], + [Lang.Blocks.robotis_korean49, '48'], + [Lang.Blocks.robotis_korean50, '49'], + [Lang.Blocks.robotis_korean51, '50'], + [Lang.Blocks.robotis_korean52, '51'], + [Lang.Blocks.robotis_korean53, '52'], + [Lang.Blocks.robotis_korean54, '53'], + [Lang.Blocks.robotis_korean55, '54'], + [Lang.Blocks.robotis_korean56, '55'], + [Lang.Blocks.robotis_korean57, '56'], + [Lang.Blocks.robotis_korean58, '57'], + [Lang.Blocks.robotis_korean59, '58'], + [Lang.Blocks.robotis_korean60, '59'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'robotis_koalabot_lite_Hello', + }, + paramsKeyMap: { + HELLO: 0, + }, + class: 'robotis_koalabot_lite_sound', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let cmHello = script.getField('HELLO', script); + + let data_instruction = INST_WRITE; + let data_address = 110; + let data_length = 2; + let data_value = 0; + + data_value = 25601 + Number(cmHello); + + let data_sendqueue = [ + [data_instruction, data_address, data_length, data_value], + [data_instruction, 0, 2, 0], + ]; + + let extraTime = 0; + + if (cmHello == '38' || cmHello == '55') { + extraTime = 2000; + } + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + 2000 + extraTime + ); + }, + syntax: { + js: [], + py: ['Koalabot.speak(%1)'], + }, + }, + robotis_koalabot_lite_effectSound: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_dog, '0'], + [Lang.Blocks.robotis_frog, '1'], + [Lang.Blocks.robotis_cat, '2'], + [Lang.Blocks.robotis_chicken, '7'], + [Lang.Blocks.robotis_tiger, '19'], + [Lang.Blocks.robotis_mouse, '17'], + + [Lang.Blocks.robotis_ambul, '773'], + [Lang.Blocks.robotis_Horn, '781'], + [Lang.Blocks.robotis_siren, '774'], + [Lang.Blocks.robotis_whistle, '274'], + [Lang.Blocks.robotis_gun, '775'], + [Lang.Blocks.robotis_clap, '260'], + + [Lang.Blocks.robotis_melody1, '786'], + [Lang.Blocks.robotis_melody2, '787'], + [Lang.Blocks.robotis_melody3, '788'], + [Lang.Blocks.robotis_melody4, '789'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'robotis_koalabot_lite_effectSound', + }, + paramsKeyMap: { + HELLO: 0, + }, + class: 'robotis_koalabot_lite_sound', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let cmHello = script.getField('HELLO', script); + + let data_instruction = INST_WRITE; + let data_address = 110; + let data_length = 2; + let data_value = 0; + + data_value = Number(cmHello); + + let data_sendqueue = [ + [data_instruction, data_address, data_length, data_value], + [data_instruction, 0, 2, 0], + ]; + + let extraTime = 0; + if ( + cmHello == '272' || + cmHello == '786' || + cmHello == '787' || + cmHello == '788' || + cmHello == '789' + ) { + //오리 + extraTime = 0; + if (cmHello == '788' || cmHello == '789') { + extraTime += 500; + } + } + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + 3000 + extraTime + ); + }, + syntax: { + js: [], + py: ['Koalabot.effect_sound(%1)'], + }, + }, + robotis_koalabot_lite_record: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['1', '0'], + ['2', '1'], + ['3', '2'], + ['4', '3'], + ['5', '4'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'robotis_koalabot_lite_record', + }, + paramsKeyMap: { + ROOM: 0, + }, + class: 'robotis_koalabot_lite_sound', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let roomNum = script.getField('ROOM', script); + + let data_instruction = INST_WRITE; + let data_address = 115; + let data_length = 1; + let data_value = 0; + + data_value = roomNum; + + let data_sendqueue = [ + [data_instruction, data_address, data_length, data_value], + ]; + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + 6000 + ); + }, + syntax: { + js: [], + py: ['Koalabot.record(%1)'], + }, + }, + robotis_koalabot_lite_playRecord: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['1', '0'], + ['2', '1'], + ['3', '2'], + ['4', '3'], + ['5', '4'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'robotis_koalabot_lite_playRecord', + }, + paramsKeyMap: { + ROOM: 0, + }, + class: 'robotis_koalabot_lite_sound', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let roomNum = script.getField('ROOM', script); + + let data_instruction = INST_WRITE; + let data_address = 116; + let data_length = 1; + let data_value = 0; + + data_value = roomNum; + + let data_sendqueue = [ + [data_instruction, data_address, data_length, data_value], + ]; + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + 6000 + ); + }, + syntax: { + js: [], + py: ['Koalabot.playRecord(%1)'], + }, + }, + + robotis_koalabot_lite_ai_camera_block_value_closest_to_center: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_ai_camera_center_block_center_x, '0'], + [Lang.Blocks.robotis_ai_camera_center_block_center_y, '1'], + [Lang.Blocks.robotis_ai_camera_center_block_width, '2'], + [Lang.Blocks.robotis_ai_camera_center_block_height, '3'], + [Lang.Blocks.robotis_ai_camera_center_leared_id, '4'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'robotis_koalabot_lite_ai_camera_block_value_closest_to_center', + }, + paramsKeyMap: { + DATA_TYPE: 0, + }, + class: 'robotis_koalabot_lite_ai_camera_value', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + let scope = script.executor.scope; + let data_address = 4009; + let data_type = script.getNumberValue('DATA_TYPE'); + data_address += data_type * 2; + let result = Entry.RobotisKoalabotLite.dataBuffer[data_address]; + if (typeof result == 'undefined') { + return 0; + } + + return result; + }, + syntax: { + js: [], + py: ['Koalabot.ai_camera_block_value_closest_to_center(%1)'], + }, + }, + robotis_koalabot_lite_ai_camera_arrow_value_closest_to_center: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_ai_camera_center_arrow_origin_x, '0'], + [Lang.Blocks.robotis_ai_camera_center_arrow_origin_y, '1'], + [Lang.Blocks.robotis_ai_camera_center_arrow_target_x, '2'], + [Lang.Blocks.robotis_ai_camera_center_arrow_target_y, '3'], + [Lang.Blocks.robotis_ai_camera_center_leared_id, '4'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'robotis_koalabot_lite_ai_camera_arrow_value_closest_to_center', + }, + paramsKeyMap: { + DATA_TYPE: 0, + }, + class: 'robotis_koalabot_lite_ai_camera_value', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + let scope = script.executor.scope; + let data_address = 4019; + let data_type = script.getNumberValue('DATA_TYPE'); + data_address += data_type * 2; + let result = Entry.RobotisKoalabotLite.dataBuffer[data_address]; + + if (typeof result == 'undefined') { + return 0; + } + + return result; + }, + syntax: { + js: [], + py: ['Koalabot.ai_camera_arrow_value_closest_to_center(%1)'], + }, + }, + robotis_koalabot_lite_ai_camera_number_of_learned_id: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_string_field', + statements: [], + params: [], + events: {}, + def: { + params: [], + type: 'robotis_koalabot_lite_ai_camera_number_of_learned_id', + }, + paramsKeyMap: {}, + class: 'robotis_koalabot_lite_ai_camera_value', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + let scope = script.executor.scope; + let data_address = 4003; + let result = Entry.RobotisKoalabotLite.dataBuffer[data_address]; + if (typeof result == 'undefined') { + return 0; + } + + return result; + }, + syntax: { + js: [], + py: ['Koalabot.ai_camera_number_of_learned_id()'], + }, + }, + robotis_koalabot_lite_ai_camera_block_value_of_id: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['1', '1'], + ['2', '2'], + ['3', '3'], + ['4', '4'], + ['5', '5'], + ['6', '6'], + ['7', '7'], + ['8', '8'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_ai_camera_center_block_center_x, '0'], + [Lang.Blocks.robotis_ai_camera_center_block_center_y, '1'], + [Lang.Blocks.robotis_ai_camera_center_block_width, '2'], + [Lang.Blocks.robotis_ai_camera_center_block_height, '3'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'robotis_koalabot_lite_ai_camera_block_value_of_id', + }, + paramsKeyMap: { + ID: 0, + TYPE: 1, + }, + class: 'robotis_koalabot_lite_ai_camera_value', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + let scope = script.executor.scope; + + // instruction / address / length / value / default length + let data_instruction = INST_WRITE; + let data_address = 4029; // ID_FOR_USE + let data_length = 2; + let data_value = script.getNumberValue('ID'); + + if (data_value != camera_id_for_use) { + let data_sendqueue = [ + [data_instruction, data_address, data_length, data_value], + ]; + + Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + ); + camera_id_for_use = data_value; + } + + data_address = 4036; // BLOCK_RESULT_BY_ID_X_CENTER + + data_address += script.getNumberValue('TYPE') * 2; + + let result = Entry.RobotisKoalabotLite.dataBuffer[data_address]; + + if (typeof result == 'undefined') { + return 0; + } + + return result; + }, + syntax: { + js: [], + py: ['Koalabot.ai_camera_block_value_of_id(%1, %2)'], + }, + }, + robotis_koalabot_lite_ai_camera_arrow_value_of_id: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['1', '1'], + ['2', '2'], + ['3', '3'], + ['4', '4'], + ['5', '5'], + ['6', '6'], + ['7', '7'], + ['8', '8'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_ai_camera_center_arrow_origin_x, '0'], + [Lang.Blocks.robotis_ai_camera_center_arrow_origin_y, '1'], + [Lang.Blocks.robotis_ai_camera_center_arrow_target_x, '2'], + [Lang.Blocks.robotis_ai_camera_center_arrow_target_y, '3'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'robotis_koalabot_lite_ai_camera_arrow_value_of_id', + }, + paramsKeyMap: { + ID: 0, + TYPE: 1, + }, + class: 'robotis_koalabot_lite_ai_camera_value', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + let scope = script.executor.scope; + + // instruction / address / length / value / default length + let data_instruction = INST_WRITE; + let data_address = 4029; // ID_FOR_USE + let data_length = 2; + let data_value = script.getNumberValue('ID'); + + if (data_value != camera_id_for_use) { + let data_sendqueue = [ + [data_instruction, data_address, data_length, data_value], + ]; + + Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + ); + camera_id_for_use = data_value; + } + + data_address = 4044; // ARROW_RESULT_BY_ID_X_ORIGIN + + data_address += script.getNumberValue('TYPE') * 2; + let result = Entry.RobotisKoalabotLite.dataBuffer[data_address]; + + if (typeof result == 'undefined') { + return 0; + } + + return result; + }, + syntax: { + js: [], + py: ['Koalabot.ai_camera_arrow_value_of_id(%1, %2)'], + }, + }, + robotis_koalabot_lite_ai_camera_connection_status: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_connected, '1'], + [Lang.Blocks.robotis_disconnected, '0'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'robotis_koalabot_lite_ai_camera_connection_status', + }, + paramsKeyMap: { + STATUS: 0, + }, + class: 'robotis_koalabot_lite_ai_camera_value', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + let scope = script.executor.scope; + let data_address = 4000; + let compareValue = script.getNumberValue('STATUS'); + let result = Entry.RobotisKoalabotLite.dataBuffer[data_address]; + + if (result == undefined) { + return false; + } + + return result == compareValue; + }, + syntax: { + js: [], + py: ['Koalabot.ai_camera_connection_status(%1)'], + }, + }, + robotis_koalabot_lite_ai_camera_if_detected: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_ai_camera_block, '0'], + [Lang.Blocks.robotis_ai_camera_arrow, '1'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'robotis_koalabot_lite_ai_camera_if_detected', + }, + paramsKeyMap: { + DETECT_TYPE: 0, + }, + class: 'robotis_koalabot_lite_ai_camera_value', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + let scope = script.executor.scope; + let data_address = 4005; // block + let detect_type = script.getNumberValue('DETECT_TYPE'); + + if (detect_type == 1) { + data_address = 4006; + } // arrow + + let result = Entry.RobotisKoalabotLite.dataBuffer[data_address]; + + if (result == undefined) { + return false; + } + + return result == 1; + }, + syntax: { + js: [], + py: ['Koalabot.ai_camera_if_detected(%1)'], + }, + }, + robotis_koalabot_lite_ai_camera_set_mode: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.robotis_ai_camera_mode_face_recognition, '0'], + [Lang.Blocks.robotis_ai_camera_mode_object_tracking, '1'], + [Lang.Blocks.robotis_ai_camera_mode_object_recognition, '2'], + [Lang.Blocks.robotis_ai_camera_mode_line_tracking, '3'], + [Lang.Blocks.robotis_ai_camera_mode_color_recognition, '4'], + [Lang.Blocks.robotis_ai_camera_mode_tag_recognition, '5'], + [Lang.Blocks.robotis_ai_camera_mode_object_classification, '6'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'robotis_koalabot_lite_ai_camera_set_mode', + }, + paramsKeyMap: { + AI_CAMERA_MODE: 0, + }, + class: 'robotis_koalabot_lite_ai_camera_set', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let ai_camera_mode = script.getField('AI_CAMERA_MODE', script); + + let data_instruction = INST_WRITE; + let data_address = 4001; + let data_length = 1; + + let data_sendqueue = [ + [data_instruction, data_address, data_length, ai_camera_mode], + ]; + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + ); + }, + syntax: { + js: [], + py: ['Koalabot.set_ai_camera_mode(%1)'], + }, + }, + robotis_koalabot_lite_ai_camera_print_custom_text: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + { + type: 'number', + params: ['0'], + }, + { + type: 'number', + params: ['0'], + }, + 'Hello!', + ], + type: 'robotis_koalabot_lite_ai_camera_print_custom_text', + }, + paramsKeyMap: { + X: 0, + Y: 1, + TEXT: 2, + }, + class: 'robotis_koalabot_lite_ai_camera_set', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + let x = script.getNumberValue('X', script); + let y = script.getNumberValue('Y', script); + let text = script.getStringValue('TEXT', script); + let data_buf = []; + let i = 0; + + // Encode the text as UTF-8 + let encoder = new TextEncoder(); + let utf8Array = encoder.encode(text); + + // utf8Array is now a Uint8Array containing the UTF-8 bytes of the text + let text_len = utf8Array.length; + + if (text_len > 45) text_len = 45; + + if (x < -160) { + x = 160; + } else if (x > 160) { + x = 160; + } + + if (y < -120) { + y = 120; + } else if (y > 120) { + y = 120; + } + + if (x < 0) { + x = 65536 + x; + } + if (y < 0) { + y = 65536 + y; + } + + data_buf.push(x % 256); + data_buf.push(Math.floor(x / 256)); + data_buf.push(y % 256); + data_buf.push(Math.floor(y / 256)); + data_buf.push(0); + data_buf.push(0); + for (i = 0; i < text_len; i++) { + data_buf.push(utf8Array[i]); + } + + let data_instruction = INST_WRITE; + let data_address = 4200; + let data_length = 6 + text_len; + + let data_sendqueue = [ + [data_instruction, data_address, data_length, data_buf], + ]; + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + ); + }, + syntax: { + js: [], + py: ['Koalabot.ai_camera_print_custom_text(%1,%2,%3)'], + }, + }, + robotis_koalabot_lite_ai_camera_clear_custom_text: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [], + type: 'robotis_koalabot_lite_ai_camera_clear_custom_text', + }, + paramsKeyMap: {}, + class: 'robotis_koalabot_lite_ai_camera_set', + isNotFor: ['RobotisKoalabotLite'], + func(sprite, script) { + // instruction / address / length / value / default length + + let data_instruction = INST_WRITE; + let data_address = 4250; + let data_length = 1; + + let data_sendqueue = [[data_instruction, data_address, data_length, 1]]; + + return Entry.RobotisKoalabotLite.postCallReturn( + script, + data_sendqueue, + DEFAULT_DELAY + ); + }, + syntax: { + js: [], + py: ['Koalabot.ai_camera_clear_custom_text()'], + }, + }, + }; + } + + requestLocalData() { + let packet = null; + if (this.robotisBuffer.length > 0) { + const data = this.robotisBuffer.shift(); + const instruction = data[0]; + const address = data[1]; + const length = data[2]; + const value = data[3]; + const dataBuffer = data[4]; + let id = 0; + + switch (instruction) { + case INST_WRITE: + id = 200; + packet = this.writePacket(id, address, length, value); + break; + case INST_BYPASS_WRITE: + id = value; + packet = this.writePacket(id, address, length, dataBuffer); + break; + } + } + return packet; + } + + handleLocalData(data) { + let stuffLength = 0; + //console.log(`length: ${data.length}`); + for (let i = 0; i < data.length; i++) { + //this.receiveBuffer.push(data[i]); + const dataIn = data[i]; + + switch (this.packetReceiveState) { + case PACKET_STATE_IDLE: + if (this.headerCount >= 2) { + rxPacket.header[2] = dataIn; + + if ( + rxPacket.header[0] == 0xff && + rxPacket.header[1] == 0xff && + rxPacket.header[2] == 0xfd + ) { + this.headerCount = 0; + this.packetReceiveState = PACKET_STATE_RESERVED; + } else { + rxPacket.header[0] = rxPacket.header[1]; + rxPacket.header[1] = rxPacket.header[2]; + rxPacket.header[2] = 0; + } + } else { + rxPacket.header[this.headerCount] = dataIn; + this.headerCount++; + } + break; + + case PACKET_STATE_RESERVED: + if (dataIn == 0xfd) { + this.packetReceiveState = PACKET_STATE_IDLE; + } else { + rxPacket.reserved = dataIn; + this.packetReceiveState = PACKET_STATE_ID; + } + break; + + case PACKET_STATE_ID: + rxPacket.id = dataIn; + this.packetReceiveState = PACKET_STATE_LENGTH_L; + break; + + case PACKET_STATE_LENGTH_L: + rxPacket.packetLength = dataIn; + this.packetReceiveState = PACKET_STATE_LENGTH_H; + break; + + case PACKET_STATE_LENGTH_H: + rxPacket.packetLength |= dataIn << 8; + if (rxPacket.packetLength < 1000) { + this.packetReceiveState = PACKET_STATE_DATA; + } else { + this.packetReceiveState = PACKET_STATE_IDLE; + } + rxPacket.index = 0; + break; + + case PACKET_STATE_DATA: + rxPacket.data[rxPacket.index] = dataIn; + rxPacket.index++; + + if (rxPacket.index >= rxPacket.packetLength - 2) { + this.packetReceiveState = PACKET_STATE_CRC_L; + } + break; + + case PACKET_STATE_CRC_L: + rxPacket.crcReceived = dataIn; + this.packetReceiveState = PACKET_STATE_CRC_H; + break; + + case PACKET_STATE_CRC_H: + rxPacket.crcReceived |= dataIn << 8; + + stuffLength = this.removeStuffing(rxPacket.data, rxPacket.packetLength); + rxPacket.packetLength -= stuffLength; + + rxPacket.cmd = rxPacket.data[0]; + rxPacket.error = rxPacket.data[1]; + + if (rxPacket.cmd == INST_STATUS) { + //console.log(`rx length: ${rxPacket.packetLength}`); + if (rxPacket.packetLength >= 147) { + let tempValue = 0; + for (let i = 0; i < addrMap.length; i++) { + switch (addrMap[i][1]) { + case 1: + this.dataBuffer[addrMap[i][2]] = + rxPacket.data[2 + addrMap[i][0]]; + break; + + case 2: + tempValue = + rxPacket.data[2 + addrMap[i][0]] + + (rxPacket.data[2 + addrMap[i][0] + 1] << 8); + if (tempValue >= 32768) { + tempValue = tempValue - 65536; + } + this.dataBuffer[addrMap[i][2]] = tempValue; + break; + + case 4: + this.dataBuffer[addrMap[i][2]] = + rxPacket.data[2 + addrMap[i][0]] + + (rxPacket.data[2 + addrMap[i][0] + 1] << 8) + + (rxPacket.data[2 + addrMap[i][0] + 2] << 16) + + (rxPacket.data[2 + addrMap[i][0] + 3] << 24); + break; + } + } + + const dxlPositionStartAddr = + addrMap[addrMap.length - 1][0] + addrMap[addrMap.length - 1][1]; + + // DXL Position + for (let i = 0; i < 20; i++) { + const currentId = + rxPacket.data[2 + dxlPositionStartAddr + 3 * i]; + const currentPos = + rxPacket.data[2 + dxlPositionStartAddr + 3 * i + 1] + + (rxPacket.data[2 + dxlPositionStartAddr + 3 * i + 2] << 8); + if (currentId != 0xff && currentPos != 0xffff) { + this.dxlPositions[currentId] = currentPos; + } + } + + const lineCategoryStartAddr = dxlPositionStartAddr + 3 * 20; + // line category + this.dataBuffer[5201] = rxPacket.data[2 + lineCategoryStartAddr]; + + const sensorStartAddr = lineCategoryStartAddr + 1; + + // 온습도+조도+동작감지센서값 + this.pirPir[0] = rxPacket.data[2 + sensorStartAddr]; + this.pirTemperature[0] = rxPacket.data[2 + sensorStartAddr + 1]; + this.pirHumidity[0] = rxPacket.data[2 + sensorStartAddr + 2]; + this.pirBrightness[0] = rxPacket.data[2 + sensorStartAddr + 3]; + + // 거리+버튼+조도센서값 + this.distanceDistance[0] = + rxPacket.data[2 + sensorStartAddr + 4] + + (rxPacket.data[2 + sensorStartAddr + 5] << 8); + this.distanceButton[0] = rxPacket.data[2 + sensorStartAddr + 6]; + this.distanceBrightness[0] = rxPacket.data[2 + sensorStartAddr + 7]; + + for (let i = 0; i < addrMap2.length; i++) { + switch (addrMap2[i][1]) { + case 1: + this.dataBuffer[addrMap2[i][2]] = + rxPacket.data[2 + addrMap2[i][0]]; + break; + + case 2: + tempValue = + rxPacket.data[2 + addrMap2[i][0]] + + (rxPacket.data[2 + addrMap2[i][0] + 1] << 8); + if (tempValue >= 32768) { + tempValue = tempValue - 65536; + } + this.dataBuffer[addrMap2[i][2]] = tempValue; + break; + + case 4: + this.dataBuffer[addrMap2[i][2]] = + rxPacket.data[2 + addrMap2[i][0]] + + (rxPacket.data[2 + addrMap2[i][0] + 1] << 8) + + (rxPacket.data[2 + addrMap2[i][0] + 2] << 16) + + (rxPacket.data[2 + addrMap2[i][0] + 3] << 24); + break; + } + } + } + } + + this.packetReceiveState = PACKET_STATE_IDLE; + break; + + default: + // code block + } + } + } + + requestInitialData() { + this.robotisBuffer = []; + this.robotisBuffer.push([INST_WRITE, 21, 2, 20]); + this.robotisBuffer.push([INST_WRITE, 19, 1, 1]); // bypass 모드 켜기 + this.robotisBuffer.push([INST_WRITE, 20, 1, 0]); // bypass port를 BLE로 설정 + this.robotisBuffer.push([INST_WRITE, 23, 1, 1]); // auto report 기능 켜기 + this.robotisBuffer.push([INST_WRITE, 4250, 1, 1]); // ai_camera 텍스트 지우기 + this.robotisBuffer.push([INST_WRITE, 722, 1, 0]); // dxl 토크 끄기 + //this.robotisBuffer.push([INST_WRITE, 63, 1, 1]); // 부저음 시간 설정 + //this.robotisBuffer.push([INST_WRITE, 60, 1, 70]); // 부저음 발생 + this.robotisBuffer.push([INST_WRITE, 113, 2, 1040]); // "띵" 효과음 발생 + /* + //const ping = [0xff, 0xff, 0xfd, 0x00, 0xc8, 0x03, 0x00, 0x01, 0x3b, 0xfa]; + // run entry mode + const packet = [ + 0xff, 0xff, 0xfd, 0x00, 0xc8, 0x07, 0x00, 0x03, 0x15, 0x00, 0x14, 0x00, 0xc1, 0xb3, + ]; + return packet; + */ + } + + async initialHandshake() { + const status = true; + let sendBuffer = null; + this.requestInitialData(); + while (this.robotisBuffer.length) { + const data = this.robotisBuffer.shift(); + const instruction = data[0]; + const address = data[1]; + const length = data[2]; + const value = data[3]; + const dataBuffer = data[4]; + let id = 0; + + switch (instruction) { + case INST_WRITE: + id = 200; + sendBuffer = this.writePacket(id, address, length, value); + break; + case INST_BYPASS_WRITE: + id = value; + sendBuffer = this.writePacket(id, address, length, dataBuffer); + break; + } + Entry.hwLite.serial.sendAsciiAsBuffer(sendBuffer); + if (instruction == INST_WRITE && address == 2100 && length == 1 && value == 1) { + this.robotisBuffer = []; + } + } + return status; + } + })(); +})(); + +module.exports = Entry.RobotisKoalabotLite; diff --git a/src/playground/blocks/hardwareLite/metadata_robotis_koalabot_lite.json b/src/playground/blocks/hardwareLite/metadata_robotis_koalabot_lite.json new file mode 100644 index 0000000000..0f883869df --- /dev/null +++ b/src/playground/blocks/hardwareLite/metadata_robotis_koalabot_lite.json @@ -0,0 +1,9 @@ +{ + "name": "RobotisKoalabotLite", + "version": "1.0.0", + "type": "hardware", + "title": "코알라봇", + "description": "로보티즈", + "imageName": "robotis_koalabot_lite", + "moduleId": "070C01" +} From 9a0559845edd51d03078c1281b3dfe9380085359 Mon Sep 17 00:00:00 2001 From: Jason Kim Date: Sun, 13 Oct 2024 17:04:40 +0900 Subject: [PATCH 5/9] =?UTF-8?q?=EC=BD=94=EC=95=8C=EB=9D=BC=EB=B4=87=20?= =?UTF-8?q?=EC=95=A0=EB=8B=88=EB=A9=94=EC=9D=B4=EC=85=98=20=EA=B8=B0?= =?UTF-8?q?=EB=B3=B8=EB=A1=9C=EB=B4=87=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blocks/hardwareLite/block_robotis_koalabot_lite.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/playground/blocks/hardwareLite/block_robotis_koalabot_lite.js b/src/playground/blocks/hardwareLite/block_robotis_koalabot_lite.js index 1399b83cc9..82312165de 100644 --- a/src/playground/blocks/hardwareLite/block_robotis_koalabot_lite.js +++ b/src/playground/blocks/hardwareLite/block_robotis_koalabot_lite.js @@ -3391,7 +3391,7 @@ let camera_id_for_use = 0; [Lang.Blocks.robotis_rgee, '-1'], [Lang.Blocks.robotis_kkokdu, '1'], ], - value: '1', + value: '0', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, From f64b1f81ad5038f5e40d0b84aa47b27b9b39ee1d Mon Sep 17 00:00:00 2001 From: Jason Kim Date: Wed, 16 Oct 2024 10:49:48 +0900 Subject: [PATCH 6/9] =?UTF-8?q?=EB=B8=94=EB=A1=9D=20=EB=AC=B8=EA=B5=AC=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../block_robotisRBPracticalAssembly.js | 95 +++++++++++-------- .../block_robotis_robotai_lite.js | 80 ++++++++-------- 2 files changed, 97 insertions(+), 78 deletions(-) diff --git a/src/playground/blocks/hardware/block_robotisRBPracticalAssembly.js b/src/playground/blocks/hardware/block_robotisRBPracticalAssembly.js index 5be3e25c0c..0f28164d65 100644 --- a/src/playground/blocks/hardware/block_robotisRBPracticalAssembly.js +++ b/src/playground/blocks/hardware/block_robotisRBPracticalAssembly.js @@ -138,7 +138,7 @@ Entry.Robotis_rb_P_Assembly.blockMenuBlocks = [ 'robotis_Practice_dxl_set_rotate', 'robotis_Practice_dxl_set_multiturn_round', - // AI 카메라 값 블록 + // 인공지능 카메라 값 블록 'robotis_Practice_huskylens_connection_status', 'robotis_Practice_huskylens_if_detected', @@ -182,12 +182,12 @@ Entry.Robotis_rb_P_Assembly.setLanguage = function () { robotis_Practice_turn_at_line: "교차로에서 %1 하고 멈추기 %2", robotis_Practice_drive_stop: "정지하기 %1", - robotis_Practice_securitybot_init: "보안로봇 초기화 %1", - robotis_Practice_securitybot_hi: "보안로봇 위아래로 흔들기 %1", - robotis_Practice_securitybot_alert: "보안로봇 좌우로 흔들기 %1", + robotis_Practice_securitybot_init: "보안 로봇 초기화 %1", + robotis_Practice_securitybot_hi: "보안 로봇 위아래로 흔들기 %1", + robotis_Practice_securitybot_alert: "보안 로봇 좌우로 흔들기 %1", - robotis_Practice_petbot_happy: "반려로봇 웃음 %1", - robotis_Practice_petbot_sad: "반려로봇 화남 %1", + robotis_Practice_petbot_happy: "반려 로봇 웃음 %1", + robotis_Practice_petbot_sad: "반려 로봇 화남 %1", robotis_Practice_farmbot_init: "스마트팜 로봇 초기화 %1", robotis_Practice_farmbot_seek: "농작물 찾기 %1", @@ -255,24 +255,24 @@ Entry.Robotis_rb_P_Assembly.setLanguage = function () { - // Huskylens 값 블록 - robotis_Practice_huskylens_connection_status: "AI 카메라: %1이면", - robotis_Practice_huskylens_if_detected: "AI 카메라: %1 이/가 표시되면", - - robotis_Practice_huskylens_block_value_closest_to_center: "AI 카메라: 화면 중앙과 가까운 %1의 %2", - robotis_Practice_huskylens_arrow_value_closest_to_center: "AI 카메라: 화면 중앙과 가까운 화살표의 %1", - robotis_Practice_huskylens_number_of_learned_id: "AI 카메라: 학습한 ID의 갯수", - robotis_Practice_huskylens_block_value_of_id: "AI 카메라: 감지된 ID가 %1인 %2의 %3", - robotis_Practice_huskylens_arrow_value_of_id: "AI 카메라: 감지된 ID가 %1인 화살표의 %2", - - robotis_Practice_huskylens_if_learned_id: "AI 카메라: ID가 %1인 데이터를 학습하였으면", - robotis_Practice_huskylens_if_detected_id_type: "AI 카메라: ID가 %1인 %2데이터를 인식하였으면", + // 인공지능 카메라 값 블록 + robotis_Practice_huskylens_connection_status: "인공지능 카메라: %1이면", + robotis_Practice_huskylens_if_detected: "인공지능 카메라: %1 이/가 표시되면", + + robotis_Practice_huskylens_block_value_closest_to_center: "인공지능 카메라: 화면 중앙과 가까운 %1의 %2", + robotis_Practice_huskylens_arrow_value_closest_to_center: "인공지능 카메라: 화면 중앙과 가까운 화살표의 %1", + robotis_Practice_huskylens_number_of_learned_id: "인공지능 카메라: 학습한 번호의 갯수", + robotis_Practice_huskylens_block_value_of_id: "인공지능 카메라: 감지된 번호가 %1인 %2의 %3", + robotis_Practice_huskylens_arrow_value_of_id: "인공지능 카메라: 감지된 번호가 %1인 화살표의 %2", + + robotis_Practice_huskylens_if_learned_id: "인공지능 카메라: 번호가 %1인 데이터를 학습하였으면", + robotis_Practice_huskylens_if_detected_id_type: "인공지능 카메라: 번호가 %1인 %2데이터를 인식하였으면", - // AI 카메라 제어 - robotis_Practice_huskylens_set_mode: "AI 카메라: 모드를 %1(으)로 설정 %2", - robotis_Practice_huskylens_print_custom_text: "AI 카메라: 화면 위치 (%1,%2)에 %3를 보여주기%4", - robotis_Practice_huskylens_clear_custom_text: "AI 카메라: 화면의 글 지우기 %1", + // 인공지능 카메라 제어 + robotis_Practice_huskylens_set_mode: "인공지능 카메라: 모드를 %1(으)로 설정 %2", + robotis_Practice_huskylens_print_custom_text: "인공지능 카메라: 화면 위치 (%1,%2)에 %3를 보여주기%4", + robotis_Practice_huskylens_clear_custom_text: "인공지능 카메라: 화면의 글 지우기 %1", }, Helper: { // 주행 제어 @@ -287,6 +287,25 @@ Entry.Robotis_rb_P_Assembly.setLanguage = function () { robotis_Practice_turn_at_line: "교차로에서 지정한 회전을 하고 멈추기", robotis_Practice_drive_stop: "로봇아이 정지하기", + robotis_robotai_lite_securitybot_init: + '보안 로봇을 초기화합니다. 두 모터를 관절모드로 설정하고 카메라를 얼굴인식모드로 설정합니다.', + robotis_robotai_lite_securitybot_hi: + '보안 로봇이 "사용자를 확인하였습니다." 문구를 화면에 표시하고 팔을 위아래로 흔듭니다.', + robotis_robotai_lite_securitybot_alert: + '보안 로봇이 "사용자가 아닙니다." 문구를 화면에 표시하고 몸을 좌우로 흔듭니다.', + + robotis_robotai_lite_petbot_happy: + '반려 로봇이 웃는 표정을 하고 "즐거워요" 라고 말을 하면서 제자리에서 한바퀴 회전합니다.', + robotis_robotai_lite_petbot_sad: + '반려 로봇이 화난 표정을 하고 "무서워요" 라고 말을 하면서 뒤로 5cm 후진합니다.', + + robotis_robotai_lite_farmbot_init: + '스마트팜 로봇을 초기화 합니다. 1번 모터를 시작위치로 이동시키고 카메라를 색상인식모드로 설정합니다.', + robotis_robotai_lite_farmbot_seek: '농작물을 발견하면 가까이로 이동합니다.', + robotis_robotai_lite_farmbot_plant_type: '농작물의 유형을 판단합니다.', + robotis_robotai_lite_farmbot_harvest_or_not_and_go: + '농작물을 수확하거나 수확하지 않습니다. 그 이후 우측으로 회전합니다.', + // 값 블록 robotis_Practice_cm_ir_value: "지정한 번호의 IR 센서 값(범위: 0 ~ 200)", robotis_Practice_cm_ir_compare: "지정한 번호의 IR 센서 값과 지정한 값의 비교식이 맞으면 '참', 아니면 '거짓'으로 판단합니다.", @@ -343,22 +362,22 @@ Entry.Robotis_rb_P_Assembly.setLanguage = function () { robotis_Practice_dxl_set_multiturn_round: "지정한 ID의 모터가 지정한 속도와 방향으로 지정한 바퀴만큼 회전", // AI Camera 값 블록 - robotis_Practice_huskylens_connection_status: "AI 카메라가 연결된 상태이면 '참', 아니면 '거짓'으로 판단합니다.", - robotis_Practice_huskylens_if_detected: "AI 카메라의 LCD화면에 선택한 기호(사각형/화살표)가 표시되면 '참', 아니면 '거짓'으로 판단합니다.", + robotis_Practice_huskylens_connection_status: "인공지능 카메라가 연결된 상태이면 '참', 아니면 '거짓'으로 판단합니다.", + robotis_Practice_huskylens_if_detected: "인공지능 카메라의 LCD화면에 선택한 기호(사각형/화살표)가 표시되면 '참', 아니면 '거짓'으로 판단합니다.", - robotis_Practice_huskylens_block_value_closest_to_center: "AI 카메라 화면 중앙과 가장 가까운 사각형의 X좌표/Y좌표/너비/높이/학습ID", - robotis_Practice_huskylens_arrow_value_closest_to_center: "AI 카메라 화면 중앙과 가장 가까운 화살표의 시작점X좌표/시작점Y좌표/끝점X좌표/끝점Y좌표/학습ID", - robotis_Practice_huskylens_number_of_learned_id: "AI 카메라가 학습한 ID의 갯수", - robotis_Practice_huskylens_block_value_of_id: "AI 카메라가 감지한 사각형중 지정한 ID의 사각형의 X좌표/Y좌표/너비/높이", - robotis_Practice_huskylens_arrow_value_of_id: "AI 카메라가 감지한 화살표중 지정한 ID의 화살표의 시작점X좌표/시작점Y좌표/끝점X좌표/끝점Y좌표", + robotis_Practice_huskylens_block_value_closest_to_center: "인공지능 카메라 화면 중앙과 가장 가까운 사각형의 X좌표/Y좌표/너비/높이/학습번호", + robotis_Practice_huskylens_arrow_value_closest_to_center: "인공지능 카메라 화면 중앙과 가장 가까운 화살표의 시작점X좌표/시작점Y좌표/끝점X좌표/끝점Y좌표/학습번호", + robotis_Practice_huskylens_number_of_learned_id: "인공지능 카메라가 학습한 번호의 갯수", + robotis_Practice_huskylens_block_value_of_id: "인공지능 카메라가 감지한 사각형중 지정한 번호의 사각형의 X좌표/Y좌표/너비/높이", + robotis_Practice_huskylens_arrow_value_of_id: "인공지능 카메라가 감지한 화살표중 지정한 번호의 화살표의 시작점X좌표/시작점Y좌표/끝점X좌표/끝점Y좌표", - robotis_Practice_huskylens_if_learned_id: "AI 카메라가 지정한 ID인 데이터를 학습하였으면 '참', 아니면 '거짓'으로 판단합니다.", - robotis_Practice_huskylens_if_detected_id_type: "AI 카메라가 지정한 ID인 지정한 데이터(사각형/화살표)를 학습하였으면 '참', 아니면 '거짓'으로 판단합니다.", + robotis_Practice_huskylens_if_learned_id: "인공지능 카메라가 지정한 번호인 데이터를 학습하였으면 '참', 아니면 '거짓'으로 판단합니다.", + robotis_Practice_huskylens_if_detected_id_type: "인공지능 카메라가 지정한 번호인 지정한 데이터(사각형/화살표)를 학습하였으면 '참', 아니면 '거짓'으로 판단합니다.", - // AI 카메라 제어 - robotis_Practice_huskylens_set_mode: "AI 카메라의 모드를 설정", - robotis_Practice_huskylens_print_custom_text: "AI 카메라 화면의 지정한 위치에 지정한 문구 출력\nX좌표: -160 ~ 160\nY좌표: -120 ~ 120", - robotis_Practice_huskylens_clear_custom_text: "AI 카메라 화면에 표시한 모든 문구 지우기", + // 인공지능 카메라 제어 + robotis_Practice_huskylens_set_mode: "인공지능 카메라의 모드를 설정", + robotis_Practice_huskylens_print_custom_text: "인공지능 카메라 화면의 지정한 위치에 지정한 문구 출력\nX좌표: -160 ~ 160\nY좌표: -120 ~ 120", + robotis_Practice_huskylens_clear_custom_text: "인공지능 카메라 화면에 표시한 모든 문구 지우기", }, Blocks: { robotis_red: "빨강", @@ -752,7 +771,7 @@ Entry.Robotis_rb_P_Assembly.setLanguage = function () { robotis_huskylens_center_block_center_y: "중심 Y좌표", robotis_huskylens_center_block_width: "너비", robotis_huskylens_center_block_height: "높이", - robotis_huskylens_center_leared_id: "학습ID", + robotis_huskylens_center_leared_id: "학습번호", robotis_huskylens_center_arrow_origin_x: "시작점 X좌표", robotis_huskylens_center_arrow_origin_y: "시작점 Y좌표", robotis_huskylens_center_arrow_target_x: "끝점 X좌표", @@ -859,7 +878,7 @@ Entry.Robotis_rb_P_Assembly.setLanguage = function () { robotis_Practice_huskylens_if_learned_id: "AI Camera: If learned data with ID %1", robotis_Practice_huskylens_if_detected_id_type: "AI Camera: If learned %2 data with ID %1", - // AI 카메라 제어 + // 인공지능 카메라 제어 robotis_Practice_huskylens_set_mode: "AI Camera: Set mode to %1 %2", robotis_Practice_huskylens_print_custom_text: "AI Camera: Display %3 at screen position (%1, %2) %4", robotis_Practice_huskylens_clear_custom_text: "AI Camera: Clear screen text %1", @@ -943,7 +962,7 @@ Entry.Robotis_rb_P_Assembly.setLanguage = function () { robotis_Practice_huskylens_if_learned_id: "If the AI camera has learned the data of the specified ID, it is determined as 'true'; otherwise, 'false'.", robotis_Practice_huskylens_if_detected_id_type: "If the AI camera has learned the specified data (rectangle/arrow) of the specified ID, it is determined as 'true'; otherwise, 'false'.", - // AI 카메라 제어 + // 인공지능 카메라 제어 robotis_Practice_huskylens_set_mode: "Set the mode of the AI camera", robotis_Practice_huskylens_print_custom_text: "Print the specified text at the specified position on the AI camera screen\nX coordinate: -160 ~ 160\nY coordinate: -120 ~ 120", robotis_Practice_huskylens_clear_custom_text: "Clear all the text displayed on the AI camera screen", diff --git a/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js b/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js index b954cc6d8a..dad5790493 100644 --- a/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js +++ b/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js @@ -242,7 +242,7 @@ let camera_id_for_use = 0; 'robotis_robotai_lite_dxl_set_rotate', 'robotis_robotai_lite_dxl_set_multiturn_round', - // AI 카메라 값 블록 + // 인공지능 카메라 값 블록 'robotis_robotai_lite_ai_camera_connection_status', 'robotis_robotai_lite_ai_camera_if_detected', @@ -471,12 +471,12 @@ let camera_id_for_use = 0; robotis_robotai_lite_turn_at_line: '교차로에서 %1 하고 멈추기 %2', robotis_robotai_lite_drive_stop: '정지하기 %1', - robotis_robotai_lite_securitybot_init: '보안로봇 초기화 %1', - robotis_robotai_lite_securitybot_hi: '보안로봇 위아래로 흔들기 %1', - robotis_robotai_lite_securitybot_alert: '보안로봇 좌우로 흔들기 %1', + robotis_robotai_lite_securitybot_init: '보안 로봇 초기화 %1', + robotis_robotai_lite_securitybot_hi: '보안 로봇 위아래로 흔들기 %1', + robotis_robotai_lite_securitybot_alert: '보안 로봇 좌우로 흔들기 %1', - robotis_robotai_lite_petbot_happy: '반려로봇 웃음 %1', - robotis_robotai_lite_petbot_sad: '반려로봇 화남 %1', + robotis_robotai_lite_petbot_happy: '반려 로봇 웃음 %1', + robotis_robotai_lite_petbot_sad: '반려 로봇 화남 %1', robotis_robotai_lite_farmbot_init: '스마트팜 로봇 초기화 %1', robotis_robotai_lite_farmbot_seek: '농작물 찾기 %1', @@ -548,32 +548,32 @@ let camera_id_for_use = 0; '%1 모터 %2 속도로 %3 바퀴 %4으로 회전 %5', // ai_camera 값 블록 - robotis_robotai_lite_ai_camera_connection_status: 'AI 카메라: %1이면', - robotis_robotai_lite_ai_camera_if_detected: 'AI 카메라: %1 이/가 표시되면', + robotis_robotai_lite_ai_camera_connection_status: '인공지능 카메라: %1이면', + robotis_robotai_lite_ai_camera_if_detected: '인공지능 카메라: %1 이/가 표시되면', robotis_robotai_lite_ai_camera_block_value_closest_to_center: - 'AI 카메라: 화면 중앙과 가까운 %1의 %2', + '인공지능 카메라: 화면 중앙과 가까운 %1의 %2', robotis_robotai_lite_ai_camera_arrow_value_closest_to_center: - 'AI 카메라: 화면 중앙과 가까운 화살표의 %1', + '인공지능 카메라: 화면 중앙과 가까운 화살표의 %1', robotis_robotai_lite_ai_camera_number_of_learned_id: - 'AI 카메라: 학습한 ID의 갯수', + '인공지능 카메라: 학습한 번호의 갯수', robotis_robotai_lite_ai_camera_block_value_of_id: - 'AI 카메라: 감지된 ID가 %1인 %2의 %3', + '인공지능 카메라: 감지된 번호가 %1인 %2의 %3', robotis_robotai_lite_ai_camera_arrow_value_of_id: - 'AI 카메라: 감지된 ID가 %1인 화살표의 %2', + '인공지능 카메라: 감지된 번호가 %1인 화살표의 %2', robotis_robotai_lite_ai_camera_if_learned_id: - 'AI 카메라: ID가 %1인 데이터를 학습하였으면', + '인공지능 카메라: 번호가 %1인 데이터를 학습하였으면', robotis_robotai_lite_ai_camera_if_detected_id_type: - 'AI 카메라: ID가 %1인 %2데이터를 인식하였으면', + '인공지능 카메라: 번호가 %1인 %2데이터를 인식하였으면', - // AI 카메라 제어 + // 인공지능 카메라 제어 robotis_robotai_lite_ai_camera_set_mode: - 'AI 카메라: 모드를 %1(으)로 설정 %2', + '인공지능 카메라: 모드를 %1(으)로 설정 %2', robotis_robotai_lite_ai_camera_print_custom_text: - 'AI 카메라: 화면 위치 (%1,%2)에 %3를 보여주기%4', + '인공지능 카메라: 화면 위치 (%1,%2)에 %3를 보여주기%4', robotis_robotai_lite_ai_camera_clear_custom_text: - 'AI 카메라: 화면의 글 지우기 %1', + '인공지능 카메라: 화면의 글 지우기 %1', }, Helper: { // 주행 제어 @@ -595,16 +595,16 @@ let camera_id_for_use = 0; robotis_robotai_lite_drive_stop: '로봇아이 정지하기', robotis_robotai_lite_securitybot_init: - '보안로봇을 초기화합니다. 두 모터를 관절모드로 설정하고 카메라를 얼굴인식모드로 설정합니다.', + '보안 로봇을 초기화합니다. 두 모터를 관절모드로 설정하고 카메라를 얼굴인식모드로 설정합니다.', robotis_robotai_lite_securitybot_hi: - '보안로봇이 "사용자를 확인하였습니다." 문구를 화면에 표시하고 팔을 위아래로 흔듭니다.', + '보안 로봇이 "사용자를 확인하였습니다." 문구를 화면에 표시하고 팔을 위아래로 흔듭니다.', robotis_robotai_lite_securitybot_alert: - '보안로봇 "사용자가 아닙니다." 문구를 화면에 표시하고 몸을 좌우로 흔듭니다.', + '보안 로봇이 "사용자가 아닙니다." 문구를 화면에 표시하고 몸을 좌우로 흔듭니다.', robotis_robotai_lite_petbot_happy: - '반려로봇이 웃는 표정을 하고 "즐거워요" 라고 말을 하면서 제자리에서 한바퀴 회전합니다.', + '반려 로봇이 웃는 표정을 하고 "즐거워요" 라고 말을 하면서 제자리에서 한바퀴 회전합니다.', robotis_robotai_lite_petbot_sad: - '반려로봇이 화난 표정을 하고 "무서워요" 라고 말을 하면서 뒤로 5cm 후진합니다.', + '반려 로봇이 화난 표정을 하고 "무서워요" 라고 말을 하면서 뒤로 5cm 후진합니다.', robotis_robotai_lite_farmbot_init: '스마트팜 로봇을 초기화 합니다. 1번 모터를 시작위치로 이동시키고 카메라를 색상인식모드로 설정합니다.', @@ -691,32 +691,32 @@ let camera_id_for_use = 0; // AI Camera 값 블록 robotis_robotai_lite_ai_camera_connection_status: - "AI 카메라가 연결된 상태이면 '참', 아니면 '거짓'으로 판단합니다.", + "인공지능 카메라가 연결된 상태이면 '참', 아니면 '거짓'으로 판단합니다.", robotis_robotai_lite_ai_camera_if_detected: - "AI 카메라의 LCD화면에 선택한 기호(사각형/화살표)가 표시되면 '참', 아니면 '거짓'으로 판단합니다.", + "인공지능 카메라의 LCD화면에 선택한 기호(사각형/화살표)가 표시되면 '참', 아니면 '거짓'으로 판단합니다.", robotis_robotai_lite_ai_camera_block_value_closest_to_center: - 'AI 카메라 화면 중앙과 가장 가까운 사각형의 X좌표/Y좌표/너비/높이/학습ID', + '인공지능 카메라 화면 중앙과 가장 가까운 사각형의 X좌표/Y좌표/너비/높이/학습번호', robotis_robotai_lite_ai_camera_arrow_value_closest_to_center: - 'AI 카메라 화면 중앙과 가장 가까운 화살표의 시작점X좌표/시작점Y좌표/끝점X좌표/끝점Y좌표/학습ID', + '인공지능 카메라 화면 중앙과 가장 가까운 화살표의 시작점X좌표/시작점Y좌표/끝점X좌표/끝점Y좌표/학습번호', robotis_robotai_lite_ai_camera_number_of_learned_id: - 'AI 카메라가 학습한 ID의 갯수', + '인공지능 카메라가 학습한 번호의 갯수', robotis_robotai_lite_ai_camera_block_value_of_id: - 'AI 카메라가 감지한 사각형중 지정한 ID의 사각형의 X좌표/Y좌표/너비/높이', + '인공지능 카메라가 감지한 사각형중 지정한 번호의 사각형의 X좌표/Y좌표/너비/높이', robotis_robotai_lite_ai_camera_arrow_value_of_id: - 'AI 카메라가 감지한 화살표중 지정한 ID의 화살표의 시작점X좌표/시작점Y좌표/끝점X좌표/끝점Y좌표', + '인공지능 카메라가 감지한 화살표중 지정한 번호의 화살표의 시작점X좌표/시작점Y좌표/끝점X좌표/끝점Y좌표', robotis_robotai_lite_ai_camera_if_learned_id: - "AI 카메라가 지정한 ID인 데이터를 학습하였으면 '참', 아니면 '거짓'으로 판단합니다.", + "인공지능 카메라가 지정한 번호인 데이터를 학습하였으면 '참', 아니면 '거짓'으로 판단합니다.", robotis_robotai_lite_ai_camera_if_detected_id_type: - "AI 카메라가 지정한 ID인 지정한 데이터(사각형/화살표)를 학습하였으면 '참', 아니면 '거짓'으로 판단합니다.", + "인공지능 카메라가 지정한 번호인 지정한 데이터(사각형/화살표)를 학습하였으면 '참', 아니면 '거짓'으로 판단합니다.", - // AI 카메라 제어 - robotis_robotai_lite_ai_camera_set_mode: 'AI 카메라의 모드를 설정', + // 인공지능 카메라 제어 + robotis_robotai_lite_ai_camera_set_mode: '인공지능 카메라의 모드를 설정', robotis_robotai_lite_ai_camera_print_custom_text: - 'AI 카메라 화면의 지정한 위치에 지정한 문구 출력\nX좌표: -160 ~ 160\nY좌표: -120 ~ 120', + '인공지능 카메라 화면의 지정한 위치에 지정한 문구 출력\nX좌표: -160 ~ 160\nY좌표: -120 ~ 120', robotis_robotai_lite_ai_camera_clear_custom_text: - 'AI 카메라 화면에 표시한 모든 문구 지우기', + '인공지능 카메라 화면에 표시한 모든 문구 지우기', }, Blocks: { robotis_red: '빨강', @@ -1113,7 +1113,7 @@ let camera_id_for_use = 0; robotis_ai_camera_center_block_center_y: '중심 Y좌표', robotis_ai_camera_center_block_width: '너비', robotis_ai_camera_center_block_height: '높이', - robotis_ai_camera_center_leared_id: '학습ID', + robotis_ai_camera_center_leared_id: '학습번호', robotis_ai_camera_center_arrow_origin_x: '시작점 X좌표', robotis_ai_camera_center_arrow_origin_y: '시작점 Y좌표', robotis_ai_camera_center_arrow_target_x: '끝점 X좌표', @@ -1240,7 +1240,7 @@ let camera_id_for_use = 0; robotis_robotai_lite_ai_camera_if_detected_id_type: 'AI Camera: If learned %2 data with ID %1', - // AI 카메라 제어 + // 인공지능 카메라 제어 robotis_robotai_lite_ai_camera_set_mode: 'AI Camera: Set mode to %1 %2', robotis_robotai_lite_ai_camera_print_custom_text: 'AI Camera: Display %3 at screen position (%1, %2) %4', @@ -1397,7 +1397,7 @@ let camera_id_for_use = 0; robotis_robotai_lite_ai_camera_if_detected_id_type: "If the AI camera has learned the specified data (rectangle/arrow) of the specified ID, it is determined as 'true'; otherwise, 'false'.", - // AI 카메라 제어 + // 인공지능 카메라 제어 robotis_robotai_lite_ai_camera_set_mode: 'Set the mode of the AI camera', robotis_robotai_lite_ai_camera_print_custom_text: 'Print the specified text at the specified position on the AI camera screen\nX coordinate: -160 ~ 160\nY coordinate: -120 ~ 120', From 236b22c6c1dfd13c1d8f59929345e6b2724125e2 Mon Sep 17 00:00:00 2001 From: Jason Kim Date: Wed, 16 Oct 2024 11:04:29 +0900 Subject: [PATCH 7/9] =?UTF-8?q?=EC=BD=94=EC=95=8C=EB=9D=BC=EB=B4=87=20?= =?UTF-8?q?=EC=B9=B4=EB=A9=94=EB=9D=BC=20=ED=85=8D=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=ED=91=9C=EC=8B=9C=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blocks/hardware/block_robotisRBKoala.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/playground/blocks/hardware/block_robotisRBKoala.js b/src/playground/blocks/hardware/block_robotisRBKoala.js index cba0085fbb..9b71c7acc5 100644 --- a/src/playground/blocks/hardware/block_robotisRBKoala.js +++ b/src/playground/blocks/hardware/block_robotisRBKoala.js @@ -5985,10 +5985,17 @@ Entry.Robotis_rb_koala.getBlocks = function() { var x = script.getNumberValue('X', script); var y = script.getNumberValue('Y', script); var text = script.getStringValue('TEXT', script); - var text_len = text.length; var data_buf = []; var i = 0; + // Encode the text as UTF-8 + let encoder = new TextEncoder(); + let utf8Array = encoder.encode(text); + + // utf8Array is now a Uint8Array containing the UTF-8 bytes of the text + let text_len = utf8Array.length; + + if (text_len > 45) text_len = 45; if (x < -160) x = 160; else if (x > 160) x = 160; @@ -6006,7 +6013,7 @@ Entry.Robotis_rb_koala.getBlocks = function() { data_buf.push(0); data_buf.push(0); for (i = 0; i < text_len; i++) { - data_buf.push(text[i]); + data_buf.push(utf8Array[i]); } var data_instruction = Entry.Robotis_rb.INSTRUCTION.WRITE; From db932f4ce31adfa7748a1c0e22ccbb79b6372104 Mon Sep 17 00:00:00 2001 From: Jason Kim Date: Wed, 23 Oct 2024 14:18:24 +0900 Subject: [PATCH 8/9] =?UTF-8?q?=EB=A1=9C=EB=B4=87=EC=95=84=EC=9D=B4,=20?= =?UTF-8?q?=EC=BD=94=EC=95=8C=EB=9D=BC=EB=B4=87=20=EB=B8=94=EB=A1=9D=20?= =?UTF-8?q?=EB=AC=B8=EA=B5=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blocks/hardware/block_robotisRB.js | 2 +- .../block_robotisRBPracticalAssembly.js | 57 ++++++++--------- .../block_robotis_robotai_lite.js | 61 +++++++++---------- 3 files changed, 58 insertions(+), 62 deletions(-) diff --git a/src/playground/blocks/hardware/block_robotisRB.js b/src/playground/blocks/hardware/block_robotisRB.js index 4367c8c5a7..31ada80e29 100644 --- a/src/playground/blocks/hardware/block_robotisRB.js +++ b/src/playground/blocks/hardware/block_robotisRB.js @@ -318,7 +318,7 @@ Entry.Robotis_rb.setLanguage = function() { robotis_face22: "목욕", robotis_face23: "햐트뿅뿅", - robotis_car_anim01: "기본표정", + robotis_car_anim01: "기본 표정", robotis_car_anim02: "감동", robotis_car_anim03: "미소", robotis_car_anim04: "웃음", diff --git a/src/playground/blocks/hardware/block_robotisRBPracticalAssembly.js b/src/playground/blocks/hardware/block_robotisRBPracticalAssembly.js index 0f28164d65..6d0cf52a30 100644 --- a/src/playground/blocks/hardware/block_robotisRBPracticalAssembly.js +++ b/src/playground/blocks/hardware/block_robotisRBPracticalAssembly.js @@ -183,11 +183,11 @@ Entry.Robotis_rb_P_Assembly.setLanguage = function () { robotis_Practice_drive_stop: "정지하기 %1", robotis_Practice_securitybot_init: "보안 로봇 초기화 %1", - robotis_Practice_securitybot_hi: "보안 로봇 위아래로 흔들기 %1", - robotis_Practice_securitybot_alert: "보안 로봇 좌우로 흔들기 %1", + robotis_Practice_securitybot_hi: "보안 로봇 긍정적 행동하기 %1", + robotis_Practice_securitybot_alert: "보안 로봇 부정적 행동하기 %1", - robotis_Practice_petbot_happy: "반려 로봇 웃음 %1", - robotis_Practice_petbot_sad: "반려 로봇 화남 %1", + robotis_Practice_petbot_happy: "반려 로봇 행복한 행동하기 %1", + robotis_Practice_petbot_sad: "반려 로봇 화난 행동하기 %1", robotis_Practice_farmbot_init: "스마트팜 로봇 초기화 %1", robotis_Practice_farmbot_seek: "농작물 찾기 %1", @@ -256,23 +256,23 @@ Entry.Robotis_rb_P_Assembly.setLanguage = function () { // 인공지능 카메라 값 블록 - robotis_Practice_huskylens_connection_status: "인공지능 카메라: %1이면", - robotis_Practice_huskylens_if_detected: "인공지능 카메라: %1 이/가 표시되면", + robotis_Practice_huskylens_connection_status: "인공지능 카메라가 %1이면", + robotis_Practice_huskylens_if_detected: "인공지능 카메라에 %1 이/가 표시되면", - robotis_Practice_huskylens_block_value_closest_to_center: "인공지능 카메라: 화면 중앙과 가까운 %1의 %2", - robotis_Practice_huskylens_arrow_value_closest_to_center: "인공지능 카메라: 화면 중앙과 가까운 화살표의 %1", - robotis_Practice_huskylens_number_of_learned_id: "인공지능 카메라: 학습한 번호의 갯수", - robotis_Practice_huskylens_block_value_of_id: "인공지능 카메라: 감지된 번호가 %1인 %2의 %3", - robotis_Practice_huskylens_arrow_value_of_id: "인공지능 카메라: 감지된 번호가 %1인 화살표의 %2", + robotis_Practice_huskylens_block_value_closest_to_center: "인공지능 카메라가 인식한 %1의 %2", + robotis_Practice_huskylens_arrow_value_closest_to_center: "인공지능 카메라가 인식한 화살표의 %1", + robotis_Practice_huskylens_number_of_learned_id: "인공지능 카메라가 학습한 클래스의 갯수", + robotis_Practice_huskylens_block_value_of_id: "인공지능 카메라가 감지한 클래스가 %1인 %2의 %3", + robotis_Practice_huskylens_arrow_value_of_id: "인공지능 카메라가 감지한 클래스가 %1인 화살표의 %2", - robotis_Practice_huskylens_if_learned_id: "인공지능 카메라: 번호가 %1인 데이터를 학습하였으면", - robotis_Practice_huskylens_if_detected_id_type: "인공지능 카메라: 번호가 %1인 %2데이터를 인식하였으면", + robotis_Practice_huskylens_if_learned_id: "인공지능 카메라가 클래스가 %1인 데이터를 학습하였으면", + robotis_Practice_huskylens_if_detected_id_type: "인공지능 카메라가 클래스가 %1인 %2데이터를 인식하였으면", // 인공지능 카메라 제어 - robotis_Practice_huskylens_set_mode: "인공지능 카메라: 모드를 %1(으)로 설정 %2", - robotis_Practice_huskylens_print_custom_text: "인공지능 카메라: 화면 위치 (%1,%2)에 %3를 보여주기%4", - robotis_Practice_huskylens_clear_custom_text: "인공지능 카메라: 화면의 글 지우기 %1", + robotis_Practice_huskylens_set_mode: "인공지능 카메라의 작동방식을 %1(으)로 설정 %2", + robotis_Practice_huskylens_print_custom_text: "인공지능 카메라의 화면 위치 (%1,%2)에 %3를 보여주기%4", + robotis_Practice_huskylens_clear_custom_text: "인공지능 카메라의 화면의 글 지우기 %1", }, Helper: { // 주행 제어 @@ -365,8 +365,8 @@ Entry.Robotis_rb_P_Assembly.setLanguage = function () { robotis_Practice_huskylens_connection_status: "인공지능 카메라가 연결된 상태이면 '참', 아니면 '거짓'으로 판단합니다.", robotis_Practice_huskylens_if_detected: "인공지능 카메라의 LCD화면에 선택한 기호(사각형/화살표)가 표시되면 '참', 아니면 '거짓'으로 판단합니다.", - robotis_Practice_huskylens_block_value_closest_to_center: "인공지능 카메라 화면 중앙과 가장 가까운 사각형의 X좌표/Y좌표/너비/높이/학습번호", - robotis_Practice_huskylens_arrow_value_closest_to_center: "인공지능 카메라 화면 중앙과 가장 가까운 화살표의 시작점X좌표/시작점Y좌표/끝점X좌표/끝점Y좌표/학습번호", + robotis_Practice_huskylens_block_value_closest_to_center: "인공지능 카메라 화면 중앙과 가장 가까운 사각형의 X좌표/Y좌표/너비/높이/클래스", + robotis_Practice_huskylens_arrow_value_closest_to_center: "인공지능 카메라 화면 중앙과 가장 가까운 화살표의 시작점X좌표/시작점Y좌표/끝점X좌표/끝점Y좌표/클래스", robotis_Practice_huskylens_number_of_learned_id: "인공지능 카메라가 학습한 번호의 갯수", robotis_Practice_huskylens_block_value_of_id: "인공지능 카메라가 감지한 사각형중 지정한 번호의 사각형의 X좌표/Y좌표/너비/높이", robotis_Practice_huskylens_arrow_value_of_id: "인공지능 카메라가 감지한 화살표중 지정한 번호의 화살표의 시작점X좌표/시작점Y좌표/끝점X좌표/끝점Y좌표", @@ -753,13 +753,12 @@ Entry.Robotis_rb_P_Assembly.setLanguage = function () { robotis_connected: "연결", robotis_disconnected: "없음", - robotis_huskylens_mode_face_recognition: "얼굴인식", - robotis_huskylens_mode_object_tracking: "물체추적", - robotis_huskylens_mode_object_recognition: "물체인식", - robotis_huskylens_mode_line_tracking: "라인인식", - robotis_huskylens_mode_color_recognition: "색상인식", - robotis_huskylens_mode_tag_recognition: "태그인식", - robotis_huskylens_mode_object_classification: "물체분류", + robotis_huskylens_mode_face_recognition: "얼굴 인식", + robotis_huskylens_mode_line_tracking: "라인 인식", + robotis_huskylens_mode_color_recognition: "색상 인식", + robotis_huskylens_mode_tag_recognition: "태그 인식", + robotis_huskylens_mode_object_classification: "사물 분류", + robotis_huskylens_mode_expression_recognition: '표정 인식', robotis_huskylens_target_face: "얼굴", robotis_huskylens_target_object: "사물", robotis_huskylens_target_color: "색상", @@ -771,7 +770,7 @@ Entry.Robotis_rb_P_Assembly.setLanguage = function () { robotis_huskylens_center_block_center_y: "중심 Y좌표", robotis_huskylens_center_block_width: "너비", robotis_huskylens_center_block_height: "높이", - robotis_huskylens_center_leared_id: "학습번호", + robotis_huskylens_center_leared_id: "클래스", robotis_huskylens_center_arrow_origin_x: "시작점 X좌표", robotis_huskylens_center_arrow_origin_y: "시작점 Y좌표", robotis_huskylens_center_arrow_target_x: "끝점 X좌표", @@ -1150,12 +1149,11 @@ Entry.Robotis_rb_P_Assembly.setLanguage = function () { robotis_connected: "connected", robotis_disconnected: "NOT connected", robotis_huskylens_mode_face_recognition: "Face recognition", - robotis_huskylens_mode_object_tracking: "Object tracking", - robotis_huskylens_mode_object_recognition: "Object recognition", robotis_huskylens_mode_line_recognition: "Line tracking", robotis_huskylens_mode_color_recognition: "Color recognition", robotis_huskylens_mode_tag_recognition: "Tag recognition", robotis_huskylens_mode_object_classification: "Object classification", + robotis_huskylens_mode_expression_recognition: 'Expression recognition', robotis_huskylens_target_block: "Rectangle", robotis_huskylens_target_arrow: "Arrow", robotis_huskylens_center_block_center_x: "Center X", @@ -7327,12 +7325,11 @@ Entry.Robotis_rb_P_Assembly.getBlocks = function () { type: 'Dropdown', options: [ [Lang.Blocks.robotis_huskylens_mode_face_recognition, '0'], - [Lang.Blocks.robotis_huskylens_mode_object_tracking, '1'], - [Lang.Blocks.robotis_huskylens_mode_object_recognition, '2'], [Lang.Blocks.robotis_huskylens_mode_line_tracking, '3'], [Lang.Blocks.robotis_huskylens_mode_color_recognition, '4'], [Lang.Blocks.robotis_huskylens_mode_tag_recognition, '5'], [Lang.Blocks.robotis_huskylens_mode_object_classification, '6'], + [Lang.Blocks.robotis_huskylens_mode_expression_recognition, '9'], ], value: '0', fontSize: 11, diff --git a/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js b/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js index dad5790493..870d80dfe3 100644 --- a/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js +++ b/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js @@ -472,11 +472,11 @@ let camera_id_for_use = 0; robotis_robotai_lite_drive_stop: '정지하기 %1', robotis_robotai_lite_securitybot_init: '보안 로봇 초기화 %1', - robotis_robotai_lite_securitybot_hi: '보안 로봇 위아래로 흔들기 %1', - robotis_robotai_lite_securitybot_alert: '보안 로봇 좌우로 흔들기 %1', + robotis_robotai_lite_securitybot_hi: '보안 로봇 긍정적 행동하기 %1', + robotis_robotai_lite_securitybot_alert: '보안 로봇 부정적 행동하기 %1', - robotis_robotai_lite_petbot_happy: '반려 로봇 웃음 %1', - robotis_robotai_lite_petbot_sad: '반려 로봇 화남 %1', + robotis_robotai_lite_petbot_happy: '반려 로봇 행복한 행동하기 %1', + robotis_robotai_lite_petbot_sad: '반려 로봇 화난 행동하기 %1', robotis_robotai_lite_farmbot_init: '스마트팜 로봇 초기화 %1', robotis_robotai_lite_farmbot_seek: '농작물 찾기 %1', @@ -512,7 +512,7 @@ let camera_id_for_use = 0; robotis_robotai_lite_playRecord: '소리 %1번을 재생하기 %2', // LCD 제어 - robotis_robotai_lite_screen: '화면 표정을 %1 %2 (으)로 정하기 %3', + robotis_robotai_lite_screen: '화면을 %1 %2 (으)로 정하기 %3', robotis_robotai_lite_anim_screen: '화면 애니메이션을 %1 %2 (으)로 정하기 %3', robotis_robotai_lite_icon_screen_food_plant: @@ -548,32 +548,32 @@ let camera_id_for_use = 0; '%1 모터 %2 속도로 %3 바퀴 %4으로 회전 %5', // ai_camera 값 블록 - robotis_robotai_lite_ai_camera_connection_status: '인공지능 카메라: %1이면', - robotis_robotai_lite_ai_camera_if_detected: '인공지능 카메라: %1 이/가 표시되면', + robotis_robotai_lite_ai_camera_connection_status: '인공지능 카메라가 %1이면', + robotis_robotai_lite_ai_camera_if_detected: '인공지능 카메라에 %1 이/가 표시되면', robotis_robotai_lite_ai_camera_block_value_closest_to_center: - '인공지능 카메라: 화면 중앙과 가까운 %1의 %2', + '인공지능 카메라가 인식한 %1의 %2', robotis_robotai_lite_ai_camera_arrow_value_closest_to_center: - '인공지능 카메라: 화면 중앙과 가까운 화살표의 %1', + '인공지능 카메라가 인식한 화살표의 %1', robotis_robotai_lite_ai_camera_number_of_learned_id: - '인공지능 카메라: 학습한 번호의 갯수', + '인공지능 카메라가 학습한 클래스의 갯수', robotis_robotai_lite_ai_camera_block_value_of_id: - '인공지능 카메라: 감지된 번호가 %1인 %2의 %3', + '인공지능 카메라가 감지한 클래스가 %1인 %2의 %3', robotis_robotai_lite_ai_camera_arrow_value_of_id: - '인공지능 카메라: 감지된 번호가 %1인 화살표의 %2', + '인공지능 카메라가 감지한 클래스가 %1인 화살표의 %2', robotis_robotai_lite_ai_camera_if_learned_id: - '인공지능 카메라: 번호가 %1인 데이터를 학습하였으면', + '인공지능 카메라가 클래스가 %1인 데이터를 학습하였으면', robotis_robotai_lite_ai_camera_if_detected_id_type: - '인공지능 카메라: 번호가 %1인 %2데이터를 인식하였으면', + '인공지능 카메라가 클래스가 %1인 %2데이터를 인식하였으면', // 인공지능 카메라 제어 robotis_robotai_lite_ai_camera_set_mode: - '인공지능 카메라: 모드를 %1(으)로 설정 %2', + '인공지능 카메라의 작동 방식을 %1(으)로 설정 %2', robotis_robotai_lite_ai_camera_print_custom_text: - '인공지능 카메라: 화면 위치 (%1,%2)에 %3를 보여주기%4', + '인공지능 카메라의 화면 위치 (%1,%2)에 %3를 보여주기%4', robotis_robotai_lite_ai_camera_clear_custom_text: - '인공지능 카메라: 화면의 글 지우기 %1', + '인공지능 카메라의 화면의 글 지우기 %1', }, Helper: { // 주행 제어 @@ -595,7 +595,7 @@ let camera_id_for_use = 0; robotis_robotai_lite_drive_stop: '로봇아이 정지하기', robotis_robotai_lite_securitybot_init: - '보안 로봇을 초기화합니다. 두 모터를 관절모드로 설정하고 카메라를 얼굴인식모드로 설정합니다.', + '보안 로봇을 초기화합니다. 두 모터를 관절모드로 설정하고 카메라를 얼굴 인식모드로 설정합니다.', robotis_robotai_lite_securitybot_hi: '보안 로봇이 "사용자를 확인하였습니다." 문구를 화면에 표시하고 팔을 위아래로 흔듭니다.', robotis_robotai_lite_securitybot_alert: @@ -696,9 +696,9 @@ let camera_id_for_use = 0; "인공지능 카메라의 LCD화면에 선택한 기호(사각형/화살표)가 표시되면 '참', 아니면 '거짓'으로 판단합니다.", robotis_robotai_lite_ai_camera_block_value_closest_to_center: - '인공지능 카메라 화면 중앙과 가장 가까운 사각형의 X좌표/Y좌표/너비/높이/학습번호', + '인공지능 카메라 화면 중앙과 가장 가까운 사각형의 X좌표/Y좌표/너비/높이/클래스', robotis_robotai_lite_ai_camera_arrow_value_closest_to_center: - '인공지능 카메라 화면 중앙과 가장 가까운 화살표의 시작점X좌표/시작점Y좌표/끝점X좌표/끝점Y좌표/학습번호', + '인공지능 카메라 화면 중앙과 가장 가까운 화살표의 시작점X좌표/시작점Y좌표/끝점X좌표/끝점Y좌표/클래스', robotis_robotai_lite_ai_camera_number_of_learned_id: '인공지능 카메라가 학습한 번호의 갯수', robotis_robotai_lite_ai_camera_block_value_of_id: @@ -873,7 +873,7 @@ let camera_id_for_use = 0; robotis_pitch: '앞뒤 회전각 (pitch)', robotis_direction_forward: '전진방향', robotis_direction_backward: '후진방향', - robotis_stMotion1: '기본자세', + robotis_stMotion1: '기본 자세', robotis_stMotion2: '전진', robotis_stMotion3: '우전진', robotis_stMotion4: '좌전진', @@ -1095,13 +1095,12 @@ let camera_id_for_use = 0; robotis_connected: '연결', robotis_disconnected: '없음', - robotis_ai_camera_mode_face_recognition: '얼굴인식', - robotis_ai_camera_mode_object_tracking: '물체추적', - robotis_ai_camera_mode_object_recognition: '물체인식', - robotis_ai_camera_mode_line_tracking: '라인인식', - robotis_ai_camera_mode_color_recognition: '색상인식', - robotis_ai_camera_mode_tag_recognition: '태그인식', - robotis_ai_camera_mode_object_classification: '물체분류', + robotis_ai_camera_mode_face_recognition: '얼굴 인식', + robotis_ai_camera_mode_line_tracking: '라인 인식', + robotis_ai_camera_mode_color_recognition: '색상 인식', + robotis_ai_camera_mode_tag_recognition: '태그 인식', + robotis_ai_camera_mode_object_classification: '사물 분류', + robotis_ai_camera_mode_expression_recognition: '표정 인식', robotis_ai_camera_target_face: '얼굴', robotis_ai_camera_target_object: '사물', robotis_ai_camera_target_color: '색상', @@ -1113,7 +1112,7 @@ let camera_id_for_use = 0; robotis_ai_camera_center_block_center_y: '중심 Y좌표', robotis_ai_camera_center_block_width: '너비', robotis_ai_camera_center_block_height: '높이', - robotis_ai_camera_center_leared_id: '학습번호', + robotis_ai_camera_center_leared_id: '클래스', robotis_ai_camera_center_arrow_origin_x: '시작점 X좌표', robotis_ai_camera_center_arrow_origin_y: '시작점 Y좌표', robotis_ai_camera_center_arrow_target_x: '끝점 X좌표', @@ -1785,6 +1784,7 @@ let camera_id_for_use = 0; robotis_ai_camera_mode_color_recognition: 'Color recognition', robotis_ai_camera_mode_tag_recognition: 'Tag recognition', robotis_ai_camera_mode_object_classification: 'Object classification', + robotis_ai_camera_mode_expression_recognition: 'Expression recognition', robotis_ai_camera_target_block: 'Rectangle', robotis_ai_camera_target_arrow: 'Arrow', robotis_ai_camera_center_block_center_x: 'Center X', @@ -7235,12 +7235,11 @@ let camera_id_for_use = 0; type: 'Dropdown', options: [ [Lang.Blocks.robotis_ai_camera_mode_face_recognition, '0'], - [Lang.Blocks.robotis_ai_camera_mode_object_tracking, '1'], - [Lang.Blocks.robotis_ai_camera_mode_object_recognition, '2'], [Lang.Blocks.robotis_ai_camera_mode_line_tracking, '3'], [Lang.Blocks.robotis_ai_camera_mode_color_recognition, '4'], [Lang.Blocks.robotis_ai_camera_mode_tag_recognition, '5'], [Lang.Blocks.robotis_ai_camera_mode_object_classification, '6'], + [Lang.Blocks.robotis_ai_camera_mode_expression_recognition, '9'], ], value: '0', fontSize: 11, From fb2bae5609ca941e4aec818c4b8936ec8c31dd9e Mon Sep 17 00:00:00 2001 From: Jason Kim Date: Wed, 23 Oct 2024 15:46:30 +0900 Subject: [PATCH 9/9] =?UTF-8?q?es-lint=20=EB=AC=B8=EC=A0=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hardwareLite/block_robotis_robotai_lite.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js b/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js index 870d80dfe3..60d7bc0c01 100644 --- a/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js +++ b/src/playground/blocks/hardwareLite/block_robotis_robotai_lite.js @@ -476,7 +476,7 @@ let camera_id_for_use = 0; robotis_robotai_lite_securitybot_alert: '보안 로봇 부정적 행동하기 %1', robotis_robotai_lite_petbot_happy: '반려 로봇 행복한 행동하기 %1', - robotis_robotai_lite_petbot_sad: '반려 로봇 화난 행동하기 %1', + robotis_robotai_lite_petbot_sad: '반려 로봇 화난 행동하기 %1', robotis_robotai_lite_farmbot_init: '스마트팜 로봇 초기화 %1', robotis_robotai_lite_farmbot_seek: '농작물 찾기 %1', @@ -486,7 +486,7 @@ let camera_id_for_use = 0; // 값 블록 robotis_robotai_lite_cm_ir_value: '%1 적외선센서 값', robotis_robotai_lite_cm_ir_compare: '%1 적외선센서 값이 %2 보다 %3', - robotis_robotai_lite_detectFrontObj: '적외선센서의 %1에 물체가 있으면', // 거리센서를 사용하지 않을 경우 + robotis_robotai_lite_detectFrontObj: '적외선센서의 %1에 물체가 있으면', robotis_robotai_lite_cm_btn_value: '제어기의 %1 버튼을 클릭했을때', robotis_robotai_lite_cm_joystick_value: '제어기의 노랑 조이스틱 위치가 %1 이면', @@ -548,8 +548,10 @@ let camera_id_for_use = 0; '%1 모터 %2 속도로 %3 바퀴 %4으로 회전 %5', // ai_camera 값 블록 - robotis_robotai_lite_ai_camera_connection_status: '인공지능 카메라가 %1이면', - robotis_robotai_lite_ai_camera_if_detected: '인공지능 카메라에 %1 이/가 표시되면', + robotis_robotai_lite_ai_camera_connection_status: + '인공지능 카메라가 %1이면', + robotis_robotai_lite_ai_camera_if_detected: + '인공지능 카메라에 %1 이/가 표시되면', robotis_robotai_lite_ai_camera_block_value_closest_to_center: '인공지능 카메라가 인식한 %1의 %2', @@ -7342,7 +7344,7 @@ let camera_id_for_use = 0; // Encode the text as UTF-8 let encoder = new TextEncoder(); let utf8Array = encoder.encode(text); - + // utf8Array is now a Uint8Array containing the UTF-8 bytes of the text let text_len = utf8Array.length;