diff --git a/images/hardware/cuboai.png b/images/hardware/cuboai.png new file mode 100644 index 0000000000..0a6fcbf50f Binary files /dev/null and b/images/hardware/cuboai.png differ diff --git a/images/hw/cuboai.png b/images/hw/cuboai.png new file mode 100644 index 0000000000..0a6fcbf50f Binary files /dev/null and b/images/hw/cuboai.png differ diff --git a/src/playground/blocks/hardware/block_aidrone.js b/src/playground/blocks/hardware/block_aidrone.js new file mode 100644 index 0000000000..a240429caf --- /dev/null +++ b/src/playground/blocks/hardware/block_aidrone.js @@ -0,0 +1,2001 @@ +'use strict'; + +Entry.AIDrone = { + Cmd: { + CMD_LED: 1, + CMD_TUNE: 2, + CMD_TUNEDUR: 3, + CMD_ROLL_LOW: 4, + CMD_ROLL_HIGH: 5, + CMD_PITCH_LOW: 6, + CMD_PITCH_HIGH: 7, + CMD_OPTION_LOW: 8, + CMD_MOTOR0: 9, + CMD_MOTOR1: 10, + CMD_MOTOR2: 11, + CMD_MOTOR3: 12, + CMD_EXTPIN1: 13, + CMD_EXTPIN2: 14, + CMD_EXTPIN3: 15, + CMD_PWM: 16, + CMD_SERVOPORT: 17, + CMD_SERVODGREE: 18, + CMD_OPTION_HIGH: 19, + CMD_YAW_LOW: 20, + CMD_YAW_HIGH: 21, + CMD_THROTTLE_LOW: 22, + CMD_THROTTLE_HIGH: 23, + CMD_POSVEL_LOW: 24, + CMD_POSVEL_HIGH: 25, + CMD_YAWVEL_LOW: 26, + CMD_YAWVEL_HIGH: 27, + CMD_ULTRASONIC: 28, + }, + Sensor: { + SENSOR_JOYSTICK_LLR: 1, + SENSOR_JOYSTICK_LTB: 2, + SENSOR_JOYSTICK_RLR: 3, + SENSOR_JOYSTICK_RTB: 4, + SENSOR_BUTTON: 5, + SENSOR_DRONECONNECT: 6, + SENSOR_DRONEALT: 7, + SENSOR_GYRO_X: 8, + SENSOR_GYRO_Y: 9, + SENSOR_DRONEREADY: 10, + SENSOR_EXTPIN1: 11, + SENSOR_EXTPIN2: 12, + SENSOR_ANALOG4: 13, + SENSOR_ANALOG5: 14, + SENSOR_JDKITMAX: 15, + SENSOR_BATTERY: 15, + SENSOR_POSX_L: 16, + SENSOR_POSX_H: 17, + SENSOR_POSY_L: 18, + SENSOR_POSY_H: 19, + SENSOR_ULTRASONIC: 20, + }, + setZero: function() { + Entry.hw.sendQueue.CMD = [ + 0xf0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + Entry.hw.update(); + }, + id: '6B.1', + name: 'AIDrone', + url: 'http://www.aidrone.store', + imageName: 'aidrone.png', + title: { + 'en': 'AIDrone', + 'ko': 'AI드론', + }, + monitorTemplate: { + imgPath: 'hw/jdrc.png', + width: 600, + height: 355, + listPorts: { + 'A6': { + name: '드론연결상태', + type: 'input', + pos: { + x: 0, + y: 0, + }, + }, + 'A10': { + name: '드론준비상태', + type: 'input', + pos: { + x: 0, + y: 0, + }, + }, + 'A15': { + name: '배터리(%)', + type: 'input', + pos: { + x: 0, + y: 0, + }, + }, + 'A8': { + name: '드론좌우기울기', + type: 'input', + pos: { + x: 0, + y: 0, + }, + }, + 'A9': { + name: '드론앞뒤기울기', + type: 'input', + pos: { + x: 0, + y: 0, + }, + }, + 'A7': { + name: '드론높이', + type: 'input', + pos: { + x: 0, + y: 0, + }, + }, + 'A16': { + name: '드론좌우이동', + type: 'input', + pos: { + x: 0, + y: 0, + }, + }, + 'A18': { + name: '드론앞뒤이동', + type: 'input', + pos: { + x: 0, + y: 0, + }, + }, + }, + ports: { + 'A1': { + name: '왼쪽 조이스틱 좌우', + type: 'input', + pos: { + x: 140, + y: 140, + }, + }, + + 'A2': { + name: '왼쪽 조이스틱 상하', + type: 'input', + pos: { + x: 140, + y: 140, + }, + }, + 'A3': { + name: '오른쪽 조이스틱 좌우', + type: 'input', + pos: { + x: 450, + y: 140, + }, + }, + + 'A4': { + name: '오른쪽 조이스틱 상하', + type: 'input', + pos: { + x: 450, + y: 140, + }, + }, + 'A5': { + name: '버튼', + type: 'input', + pos: { + x: 430, + y: 250, + }, + }, + + + }, + mode: 'both', + }, +}; + + +Entry.AIDrone.setLanguage = function() { + return { + ko: { + template: { + 'aidrone_takeoff': '드론 이륙하기 %1', + 'aidrone_landing': '드론 착륙하기 %1', + 'aidrone_altitude': '%1cm 높이로 비행%2', + 'aidrone_throttle': '프로펠러를 %1 % 세기로 돌리기 %2', + 'aidrone_velocity': '%1(으)로 %2속도(cm/s)로 비행%3', + 'aidrone_distance': '%1(으)로 %2cm 거리를 %3속도(cm/s)로 비행%4', + 'aidrone_degree': '%1으로 %2도를 %3각속도(deg/s)로 회전 %4', + 'aidrone_motor': '%1 모터를 %2 세기로 돌리기 %3', + 'aidrone_emergency': '드론 즉시멈추기 %1', + 'aidrone_connect': '드론 연결상태', + 'aidrone_ready': '드론 준비상태', + 'aidrone_battery': '배터리(%)', + 'aidrone_dronealt': '드론 높이', + 'aidrone_gyrox': '드론 좌우 기울기', + 'aidrone_gyroy': '드론 앞뒤 기울기', + 'aidrone_posx': '드론 좌우 이동', + 'aidrone_posy': '드론 앞뒤 이동', + 'aidrone_led': '%1 LED %2 %3', + 'aidrone_tune': '%1 음을 %2 초동안 소리내기 %3', + 'aidrone_joystick': '조이스틱 %1 읽기', + 'aidrone_button': '%1번 버튼 값 읽어오기', + 'aidrone_dir_front': '앞', + 'aidrone_dir_back': '뒤', + 'aidrone_dir_right': '오른쪽', + 'aidrone_dir_left': '왼쪽', + 'aidrone_alt': '드론 높이', + 'aidrone_tiltx': '드론좌우기울기', + 'aidrone_tilty': '드론앞뒤기울기', + 'aidrone_battery': '배터리', + 'aidrone_detect_marker': '화면에서 마커 찾기 %1', + 'aidrone_get_marker_data': '인식된 마커의 %1 값', + 'aidrone_color_track_start': '%1 색상 추적 시작 %2', + 'aidrone_color_track_stop': '색상 추적 중지 %1', + 'aidrone_color_detected': '색상이 감지됨?', + 'aidrone_get_color_x': '감지된 색상 X좌표', + 'aidrone_get_color_y': '감지된 색상 Y좌표', + 'aidrone_get_color_size': '감지된 색상 크기', + 'aidrone_get_color_data': '색상 추적 %1', + 'aidrone_face_detect': '얼굴 인식하기 %1', + 'aidrone_face_detected': '얼굴이 감지됨?', + 'aidrone_get_face_x': '얼굴 X좌표', + 'aidrone_get_face_y': '얼굴 Y좌표', + 'aidrone_get_face_size': '얼굴 크기', + 'aidrone_get_face_data': '얼굴 %1', + 'aidrone_get_landmark': '얼굴 랜드마크 %1번 %2 좌표', + 'aidrone_marker_detected': '마커가 감지됨?', + }, + }, + en: { + template: { + 'aidrone_takeoff': '드론 이륙하기 %1', + 'aidrone_landing': '드론 착륙하기 %1', + 'aidrone_altitude': '%1cm 높이로 비행%2', + 'aidrone_throttle': '프로펠러를 %1 % 세기로 돌리기 %2', + 'aidrone_velocity': '%1(으)로 %2속도(cm/s)로 비행%3', + 'aidrone_distance': '%1(으)로 %2cm 거리를 %3속도(cm/s)로 비행%4', + 'aidrone_degree': '%1으로 %2도를 %3각속도(deg/s)로 회전 %4', + 'aidrone_motor': '%1 모터를 %2 세기로 돌리기 %3', + 'aidrone_emergency': '드론 즉시멈추기 %1', + 'aidrone_connect': '드론 연결상태', + 'aidrone_ready': '드론 준비상태', + 'aidrone_battery': '배터리(%)', + 'aidrone_dronealt': '드론 높이', + 'aidrone_gyrox': '드론 좌우 기울기', + 'aidrone_gyroy': '드론 앞뒤 기울기', + 'aidrone_posx': '드론 좌우 이동', + 'aidrone_posy': '드론 앞뒤 이동', + 'aidrone_led': '%1 LED %2 %3', + 'aidrone_tune': '%1 음을 %2 초동안 소리내기 %3', + 'aidrone_joystick': '조이스틱 %1 읽기', + 'aidrone_button': '%1번 버튼 값 읽어오기', + 'aidrone_dir_front': '앞', + 'aidrone_dir_back': '뒤', + 'aidrone_dir_right': '오른쪽', + 'aidrone_dir_left': '왼쪽', + 'aidrone_alt': '드론 높이', + 'aidrone_tiltx': '드론좌우기울기', + 'aidrone_tilty': '드론앞뒤기울기', + 'aidrone_battery': '배터리', + 'aidrone_detect_marker': '화면에서 마커 찾기 %1', + 'aidrone_get_marker_data': '인식된 마커의 %1 값', + 'aidrone_color_track_start': '%1 color track start %2', + 'aidrone_color_track_stop': 'color track stop %1', + 'aidrone_color_detected': 'color detected?', + 'aidrone_get_color_x': 'color X', + 'aidrone_get_color_y': 'color Y', + 'aidrone_get_color_size': 'color size', + 'aidrone_get_color_data': 'color track %1', + 'aidrone_face_detect': 'detect face %1', + 'aidrone_face_detected': 'face detected?', + 'aidrone_get_face_x': 'face X', + 'aidrone_get_face_y': 'face Y', + 'aidrone_get_face_size': 'face size', + 'aidrone_get_face_data': 'face %1', + 'aidrone_get_landmark': 'landmark %1 %2', + 'aidrone_marker_detected': 'marker detected?', + }, + }, + }; +}; + + +Entry.AIDrone.blockMenuBlocks = [ + 'aidrone_takeoff', + 'aidrone_landing', + 'aidrone_altitude', + 'aidrone_throttle', + 'aidrone_velocity', + 'aidrone_distance', + 'aidrone_degree', + 'aidrone_emergency', + 'aidrone_connect', + 'aidrone_ready', + 'aidrone_battery', + 'aidrone_dronealt', + 'aidrone_gyrox', + 'aidrone_gyroy', + 'aidrone_posx', + 'aidrone_posy', + 'aidrone_led', + 'aidrone_tune', + 'aidrone_motor', + 'aidrone_joystick', + 'aidrone_button', + 'aidrone_detect_marker', + 'aidrone_get_marker_data', + // tracking.js 기반 비전 블록 ─ 색상 추적 + 'aidrone_color_track_start', + 'aidrone_color_track_stop', + 'aidrone_color_detected', + 'aidrone_get_color_x', + 'aidrone_get_color_y', + 'aidrone_get_color_size', + 'aidrone_get_color_data', + // tracking.js 기반 비전 블록 ─ 얼굴 인식 + 'aidrone_face_detect', + 'aidrone_face_detected', + 'aidrone_get_face_x', + 'aidrone_get_face_y', + 'aidrone_get_face_size', + 'aidrone_get_face_data', + // tracking.js 기반 비전 블록 ─ 랜드마크 + 'aidrone_get_landmark', + // AR 마커 조건 블록 + 'aidrone_marker_detected', +]; + +// --- [여기부터] 1단계 코드: 마커 데이터 저장 변수 --- +Entry.AIDrone.visionData = { + id: -1, // 마커 ID (없으면 -1) + x: 0, // 화면 X좌표 (-240 ~ 240) + y: 0, // 화면 Y좌표 (-135 ~ 135) + dist: 0, // 거리 (cm 추정치) + width: 0 // 마커의 크기(픽셀) +}; +// --- [여기까지] 1단계 코드 --- + +// ------------------------------------------------------- +// tracking.js 전용 데이터 저장 변수 +// ------------------------------------------------------- + +// 색상 추적 데이터 +Entry.AIDrone.colorTrackData = { + detected: false, // 감지 여부 + x: 0, // 감지된 색상 영역 중심 X (엔트리 좌표계) + y: 0, // 감지된 색상 영역 중심 Y (엔트리 좌표계) + width: 0, // 영역 가로 크기(pixel) + height: 0 // 영역 세로 크기(pixel) +}; +Entry.AIDrone._colorTrackerTask = null; +Entry.AIDrone._colorTrackerRunning = false; +Entry.AIDrone._colorTrackerStop = null; +Entry.AIDrone._arDetector = null; // AR.Detector 재사용 + +// ---------------------------------------------------------------- +// _getVisionCanvas(): 비전 분석에 사용할 canvas 반환 +// +// 동작 우선순위: +// 1순위: Entry.cam.canvas +// → 엔트리 [비디오 화면 보이기] + [MJPEG Camera로 바꾸기] 블록 +// 실행 후 생성되는 공식 비디오 캔버스 +// (매 프레임 Entry.cam.video → Entry.cam.canvas에 그려짐) +// +// 2순위: Entry.cam.video → 오프스크린 canvas +// → Entry.cam.canvas가 없을 때 video를 직접 그려서 분석 +// +// 3순위: document의 재생 중인