Files
lms-be/scripts/reseed-base-nav2-curriculum.sql
T

254 lines
18 KiB
PL/PgSQL

-- Rebuild the shared base course as a two-week NAV2 curriculum.
-- Target: courses.slug = 'futuredrive-autonomy-basic'
BEGIN;
CREATE TEMP TABLE target_course AS
SELECT id
FROM courses
WHERE slug = 'futuredrive-autonomy-basic';
DO $$
BEGIN
IF (SELECT count(*) FROM target_course) <> 1 THEN
RAISE EXCEPTION 'Expected exactly one futuredrive-autonomy-basic course';
END IF;
END $$;
-- Existing module IDs are replaced, so their student repository/score rows cascade.
DELETE FROM course_student_week_progress
WHERE course_id IN (SELECT id FROM target_course);
DELETE FROM instructor_curriculum_week_overrides
WHERE course_id IN (SELECT id FROM target_course);
DELETE FROM course_environment_profiles
WHERE course_id IN (SELECT id FROM target_course);
DELETE FROM course_week_visualization_platforms
WHERE course_id IN (SELECT id FROM target_course);
DELETE FROM course_week_maps
WHERE course_id IN (SELECT id FROM target_course);
DELETE FROM course_week_modules
WHERE week_id IN (SELECT id FROM course_weeks WHERE course_id IN (SELECT id FROM target_course));
DELETE FROM course_week_topics
WHERE week_id IN (SELECT id FROM course_weeks WHERE course_id IN (SELECT id FROM target_course));
DELETE FROM course_week_practices
WHERE week_id IN (SELECT id FROM course_weeks WHERE course_id IN (SELECT id FROM target_course));
DELETE FROM course_week_references
WHERE week_id IN (SELECT id FROM course_weeks WHERE course_id IN (SELECT id FROM target_course));
DELETE FROM course_weeks
WHERE course_id IN (SELECT id FROM target_course)
AND week > 2;
UPDATE courses
SET
title = 'NAV2 기반 자율주행 교육 과정',
subtitle = 'ROS2, 시뮬레이션, SLAM부터 경로 계획과 제어까지',
description = 'ROS2와 NAV2 기반 시뮬레이션 및 플랫폼 실습을 통해 자율주행 시스템의 핵심 흐름을 학습하고 팀 프로젝트로 검증합니다.'
WHERE id IN (SELECT id FROM target_course);
UPDATE course_weeks
SET
title = 'ROS2 & Simulation',
tags = ARRAY['MK-mini', '진행중'],
progress = 0,
state = 'current',
duration = '1주',
github = 'https://github.com/ros-navigation/navigation2',
overview = 'ROS2 통신 구조와 Gazebo 시뮬레이션 환경을 구성하고, LiDAR SLAM·위치추정·경로 계획·제어까지 NAV2 자율주행 파이프라인을 실습합니다.',
deliverable = 'NAV2 모듈 소스 변경 내역, SLAM 결과 맵, 목표 지점 주행 검증 화면 및 실행 로그를 제출합니다.',
requires_source_submission = true
WHERE course_id IN (SELECT id FROM target_course) AND week = 1;
UPDATE course_weeks
SET
title = 'Autonomy Studio 팀 프로젝트',
tags = ARRAY['MK-mini', '진행예정'],
progress = 0,
state = 'locked',
duration = '1주',
github = 'https://github.com/ros-navigation/navigation2',
overview = '3~4인 팀으로 자율주행 알고리즘이 필요한 문제 상황을 정의하고, 센서 구성과 NAV2 모듈을 조합해 시뮬레이션과 플랫폼에서 검증합니다.',
deliverable = '팀 프로젝트 소스, 시스템 구성도, 시뮬레이션 및 플랫폼 주행 검증 결과, 발표 자료를 제출합니다.',
requires_source_submission = true
WHERE course_id IN (SELECT id FROM target_course) AND week = 2;
INSERT INTO course_weeks (course_id, week, title, tags, progress, state, duration, github, overview, deliverable, requires_source_submission)
SELECT id, 1, 'ROS2 & Simulation', ARRAY['MK-mini', '진행중'], 0, 'current', '1주',
'https://github.com/ros-navigation/navigation2',
'ROS2 통신 구조와 Gazebo 시뮬레이션 환경을 구성하고, LiDAR SLAM·위치추정·경로 계획·제어까지 NAV2 자율주행 파이프라인을 실습합니다.',
'NAV2 모듈 소스 변경 내역, SLAM 결과 맵, 목표 지점 주행 검증 화면 및 실행 로그를 제출합니다.', true
FROM target_course
WHERE NOT EXISTS (SELECT 1 FROM course_weeks WHERE course_id = target_course.id AND week = 1);
INSERT INTO course_weeks (course_id, week, title, tags, progress, state, duration, github, overview, deliverable, requires_source_submission)
SELECT id, 2, 'Autonomy Studio 팀 프로젝트', ARRAY['MK-mini', '진행예정'], 0, 'locked', '1주',
'https://github.com/ros-navigation/navigation2',
'3~4인 팀으로 자율주행 알고리즘이 필요한 문제 상황을 정의하고, 센서 구성과 NAV2 모듈을 조합해 시뮬레이션과 플랫폼에서 검증합니다.',
'팀 프로젝트 소스, 시스템 구성도, 시뮬레이션 및 플랫폼 주행 검증 결과, 발표 자료를 제출합니다.', true
FROM target_course
WHERE NOT EXISTS (SELECT 1 FROM course_weeks WHERE course_id = target_course.id AND week = 2);
INSERT INTO course_week_topics (week_id, title, detail, sort_order)
SELECT w.id, topic.title, topic.detail, topic.sort_order
FROM course_weeks w
CROSS JOIN (
VALUES
(1, 'ROS2 기초', 'ROS Topic, Service, Action 통신과 TF 정의, ROS2 패키지 및 tree 구조를 실습합니다.'),
(2, 'Sensor Processing', 'LiDAR와 카메라 등 센서 데이터 처리 흐름과 Calibration 기초를 확인합니다.'),
(3, 'Simulation 환경 구축 Part 1', 'Gazebo 월드, 로봇 모델, 센서 토픽을 구성해 시뮬레이션 실습 환경을 만듭니다.'),
(4, 'Simulation 환경 구축 Part 2', '시뮬레이션에서 활용할 수 있는 모빌리티 플랫폼과 실행 모듈 구성을 점검합니다.'),
(5, 'LiDAR SLAM', '센서 데이터와 SLAM 알고리즘을 활용해 자율주행용 2D Map을 구축합니다.'),
(6, 'LiDAR Localization', '구축한 Map과 실시간 LiDAR 데이터를 이용해 현재 위치를 추정합니다.'),
(7, 'Parameter Tuning', '모듈 파라미터를 변경하고 결과를 비교해 알고리즘을 튜닝합니다.'),
(8, '[심화] Camera based SLAM', '카메라 기반 Map 구축과 위치인식의 입력·출력 구조를 분석합니다.'),
(9, 'Occupancy Map', '장애물 인식을 위한 Occupancy Map과 costmap 반영 과정을 실습합니다.'),
(10, 'Planning', '장애물 충돌 없이 목표 지점으로 이동하기 위한 전역·지역 경로 계획을 실습합니다.'),
(11, 'Control', '생성한 경로를 추종하도록 속도 명령을 만들고 주행 결과를 검증합니다.'),
(12, '[심화] 딥러닝 기반 객체 인식', '딥러닝 기반 객체 인식 결과를 자율주행 데이터 흐름에 반영하는 방법을 학습합니다.')
) AS topic(sort_order, title, detail)
WHERE w.course_id IN (SELECT id FROM target_course) AND w.week = 1;
INSERT INTO course_week_topics (week_id, title, detail, sort_order)
SELECT w.id, topic.title, topic.detail, topic.sort_order
FROM course_weeks w
CROSS JOIN (
VALUES
(1, '프로젝트 주제와 역할 분담', '팀별 자율주행 문제 상황과 목표, 역할, 검증 기준을 정의합니다.'),
(2, '센서·모듈 구성 설계', '센서 입력과 NAV2 모듈 조합, ROS 토픽 및 실행 순서를 설계합니다.'),
(3, '알고리즘 구현과 튜닝', 'SLAM, Localization, Planning, Control 파라미터를 수정하고 성능을 비교합니다.'),
(4, '시뮬레이션·플랫폼 검증', 'Gazebo 시뮬레이션과 실제 플랫폼에서 주행 시나리오를 검증합니다.'),
(5, '결과 제출과 발표', '소스, 실행 로그, 검증 결과를 정리해 팀 프로젝트 결과를 제출하고 발표합니다.')
) AS topic(sort_order, title, detail)
WHERE w.course_id IN (SELECT id FROM target_course) AND w.week = 2;
INSERT INTO course_week_practices (week_id, title, description, sort_order)
SELECT w.id, practice.title, practice.description, practice.sort_order
FROM course_weeks w
CROSS JOIN (
VALUES
(1, 'ROS2와 Gazebo 실행 환경', 'Topic, Service, Action, TF를 확인하고 TurtleBot3 Gazebo 환경을 실행합니다.'),
(2, 'LiDAR SLAM과 Localization', '맵을 생성·저장하고 저장된 맵에서 AMCL 기반 위치추정을 검증합니다.'),
(3, '경로 계획과 제어', '목표 지점을 설정하고 장애물 회피, 경로 계획, 제어 명령을 비교합니다.')
) AS practice(sort_order, title, description)
WHERE w.course_id IN (SELECT id FROM target_course) AND w.week = 1;
INSERT INTO course_week_practices (week_id, title, description, sort_order)
SELECT w.id, practice.title, practice.description, practice.sort_order
FROM course_weeks w
CROSS JOIN (
VALUES
(1, '팀 자율주행 시나리오 구현', '팀별 시나리오에 맞춰 NAV2 모듈을 구성하고 소스를 수정합니다.'),
(2, '통합 주행 검증', '시뮬레이션과 플랫폼에서 재현 가능한 주행 결과를 확보합니다.')
) AS practice(sort_order, title, description)
WHERE w.course_id IN (SELECT id FROM target_course) AND w.week = 2;
WITH module_definitions(category, name, folder_name, template_repository_url, prebuilt_artifacts, default_parameters, docker_image) AS (
VALUES
('Simulator', 'NAV2-Gazebo', '[lms-nav2-gazebo-simulator]nav2-simulator_v1.0.0_ws', 'http://localhost:3000/templates/lms-nav2-gazebo-simulator.git',
jsonb_build_array(jsonb_build_object('url', 'https://pub-ca72c40797144462bdb7d200c215d361.r2.dev/studio-artifacts/modules/lms-nav2-gazebo-simulator/1.0.0/prebuilt/latest/lms-nav2-gazebo-simulator-build-install.tar.zst', 'type', 'build-install', 'fileName', 'lms-nav2-gazebo-simulator-build-install.tar.zst', 'required', false, 'extractPath', '.')), jsonb_build_array('gui:=false'), 'future-nav2-gazebo:humble'),
('Vehicle', 'NAV2-TurtleBot3Burger', '[lms-nav2-gazebo-vehicle]nav2-vehicle_v1.0.0_ws', 'http://localhost:3000/templates/lms-nav2-gazebo-vehicle.git',
jsonb_build_array(jsonb_build_object('url', 'https://pub-ca72c40797144462bdb7d200c215d361.r2.dev/studio-artifacts/modules/lms-nav2-gazebo-vehicle/1.0.0/prebuilt/latest/lms-nav2-gazebo-vehicle-build-install.tar.zst', 'type', 'build-install', 'fileName', 'lms-nav2-gazebo-vehicle-build-install.tar.zst', 'required', false, 'extractPath', '.')), jsonb_build_array('sim_mode:=true', 'platform:=turtlebot3', 'level:=2d'), 'future-nav2-gazebo:humble'),
('Map', 'NAV2-Map', '[lms-nav2-gazebo-map]nav2-map_v1.0.0_ws', 'http://localhost:3000/templates/lms-nav2-gazebo-map.git',
jsonb_build_array(jsonb_build_object('url', 'https://pub-ca72c40797144462bdb7d200c215d361.r2.dev/studio-artifacts/modules/lms-nav2-gazebo-map/1.0.0/prebuilt/latest/lms-nav2-gazebo-map-build-install.tar.zst', 'type', 'build-install', 'fileName', 'lms-nav2-gazebo-map-build-install.tar.zst', 'required', false, 'extractPath', '.')), '[]'::jsonb, 'future-nav2-gazebo:humble'),
('Localization', 'NAV2-SLAM', '[lms-nav2-gazebo-slam]nav2-slam_v1.0.0_ws', 'http://localhost:3000/templates/lms-nav2-gazebo-slam.git',
jsonb_build_array(jsonb_build_object('url', 'https://pub-ca72c40797144462bdb7d200c215d361.r2.dev/studio-artifacts/modules/lms-nav2-gazebo-slam/1.0.0/prebuilt/latest/lms-nav2-gazebo-slam-build-install.tar.zst', 'type', 'build-install', 'fileName', 'lms-nav2-gazebo-slam-build-install.tar.zst', 'required', false, 'extractPath', '.')), '[]'::jsonb, 'future-nav2-gazebo:humble'),
('Localization', 'NAV2-Localization', '[lms-nav2-gazebo-localization]nav2-localization_v1.0.0_ws', 'http://localhost:3000/templates/lms-nav2-gazebo-localization.git',
jsonb_build_array(jsonb_build_object('url', 'https://pub-ca72c40797144462bdb7d200c215d361.r2.dev/studio-artifacts/modules/lms-nav2-gazebo-localization/1.0.0/prebuilt/latest/lms-nav2-gazebo-localization-build-install.tar.zst', 'type', 'build-install', 'fileName', 'lms-nav2-gazebo-localization-build-install.tar.zst', 'required', false, 'extractPath', '.')), jsonb_build_array('localization_mode:=slam'), 'future-nav2-gazebo:humble'),
('Perception', 'NAV2-Perception', '[lms-nav2-gazebo-perception]nav2-perception_v1.0.0_ws', 'http://localhost:3000/templates/lms-nav2-gazebo-perception.git',
jsonb_build_array(jsonb_build_object('url', 'https://pub-ca72c40797144462bdb7d200c215d361.r2.dev/studio-artifacts/modules/lms-nav2-gazebo-perception/1.0.0/prebuilt/latest/lms-nav2-gazebo-perception-build-install.tar.zst', 'type', 'build-install', 'fileName', 'lms-nav2-gazebo-perception-build-install.tar.zst', 'required', false, 'extractPath', '.')), jsonb_build_array('sim_mode:=true'), 'future-nav2-gazebo:humble'),
('Planning', 'NAV2-Planning', '[lms-nav2-gazebo-planning]nav2-planning_v1.0.0_ws', 'http://localhost:3000/templates/lms-nav2-gazebo-planning.git',
jsonb_build_array(jsonb_build_object('url', 'https://pub-ca72c40797144462bdb7d200c215d361.r2.dev/studio-artifacts/modules/lms-nav2-gazebo-planning/1.0.0/prebuilt/latest/lms-nav2-gazebo-planning-build-install.tar.zst', 'type', 'build-install', 'fileName', 'lms-nav2-gazebo-planning-build-install.tar.zst', 'required', false, 'extractPath', '.')), '[]'::jsonb, 'future-nav2-gazebo:humble'),
('Control', 'NAV2-Control', '[lms-nav2-gazebo-control]nav2-control_v1.0.0_ws', 'http://localhost:3000/templates/lms-nav2-gazebo-control.git',
jsonb_build_array(jsonb_build_object('url', 'https://pub-ca72c40797144462bdb7d200c215d361.r2.dev/studio-artifacts/modules/lms-nav2-gazebo-control/1.0.0/prebuilt/latest/lms-nav2-gazebo-control-build-install.tar.zst', 'type', 'build-install', 'fileName', 'lms-nav2-gazebo-control-build-install.tar.zst', 'required', false, 'extractPath', '.')), jsonb_build_array('sim_mode:=true', 'robot:=turtlebot3', 'level:=2d'), 'future-nav2-gazebo:humble'),
('Vehicle', 'NAV2-MKMini', '[lms-nav2-mkmini]nav2-mkmini_v1.0.0_ws', 'http://localhost:3000/templates/lms-nav2-mkmini.git',
jsonb_build_array(jsonb_build_object('url', 'https://pub-ca72c40797144462bdb7d200c215d361.r2.dev/studio-artifacts/modules/lms-nav2-mkmini/1.0.0/prebuilt/amd64/lms-nav2-mkmini-build-install-amd64.tar.zst', 'type', 'build-install', 'fileName', 'lms-nav2-mkmini-build-install-amd64.tar.zst', 'checksumSha256', '8b36d3fda6a81a49da140529d9874e99b734d05e01e12a49e719e2b26f8803d9', 'architecture', 'amd64', 'required', false, 'extractPath', '.')), jsonb_build_array('sim_mode:=false', 'platform:=mkmini', 'robot:=mkmini', 'level:=2d'), 'future-nav2:humble-jetson_orin')
)
INSERT INTO course_week_modules (week_id, sort_order, category, name, folder_name, template_repository_url, source_type, prebuilt_artifacts, default_parameters, docker_image)
SELECT w.id, row_number() OVER (PARTITION BY w.id ORDER BY module_definitions.folder_name), category, name, folder_name, template_repository_url, 'GIT', prebuilt_artifacts, default_parameters, docker_image
FROM course_weeks w
CROSS JOIN module_definitions
WHERE w.course_id IN (SELECT id FROM target_course) AND w.week IN (1, 2);
INSERT INTO course_week_visualization_platforms (course_id, week, platform_key, enabled, created_at, updated_at)
SELECT target_course.id, weeks.week, platform.platform_key, true, now(), now()
FROM target_course
CROSS JOIN (VALUES (1), (2)) AS weeks(week)
JOIN visualization_platforms platform ON platform.platform_key IN ('NAV2', 'REAL_SLAM', 'REAL_NAVIGATION');
INSERT INTO course_environment_profiles (course_id, week, platform_key, profile_type, name, config, enabled, created_at, updated_at)
SELECT target_course.id, weeks.week, platform.platform_key, platform.type,
CASE WHEN platform.platform_key = 'NAV2' THEN '로컬' ELSE platform.display_name END,
platform.default_config, true, now(), now()
FROM target_course
CROSS JOIN (VALUES (1), (2)) AS weeks(week)
JOIN visualization_platforms platform ON platform.platform_key IN ('NAV2', 'REAL_SLAM', 'REAL_NAVIGATION');
-- Local simulation gets all Gazebo modules. Platform profiles only receive modules applicable to their workflow.
UPDATE course_environment_profiles profile
SET config = profile.config::jsonb || jsonb_build_object('moduleSet', jsonb_build_object(
'target', CASE WHEN profile.platform_key = 'NAV2' THEN 'local' ELSE 'platform' END,
'includeUnlisted', false,
'modules', COALESCE((
SELECT jsonb_agg(jsonb_build_object('id', module.id) ORDER BY module.sort_order)
FROM course_weeks week
JOIN course_week_modules module ON module.week_id = week.id
WHERE week.course_id = profile.course_id
AND week.week = profile.week
AND (
(profile.platform_key = 'NAV2' AND module.folder_name LIKE '[lms-nav2-gazebo-%')
OR (profile.platform_key IN ('REAL_SLAM', 'REAL_NAVIGATION') AND module.folder_name IN (
'[lms-nav2-mkmini]nav2-mkmini_v1.0.0_ws',
'[lms-nav2-gazebo-map]nav2-map_v1.0.0_ws',
'[lms-nav2-gazebo-perception]nav2-perception_v1.0.0_ws',
'[lms-nav2-gazebo-localization]nav2-localization_v1.0.0_ws',
'[lms-nav2-gazebo-planning]nav2-planning_v1.0.0_ws',
'[lms-nav2-gazebo-control]nav2-control_v1.0.0_ws'
))
)
), '[]'::jsonb)
))
WHERE profile.course_id IN (SELECT id FROM target_course)
AND profile.platform_key IN ('NAV2', 'REAL_SLAM', 'REAL_NAVIGATION');
-- Control runs with TurtleBot3/Gazebo defaults locally, but uses MK-mini and the ARM64 image on a platform.
UPDATE course_environment_profiles profile
SET config = jsonb_set(profile.config::jsonb, '{moduleSet,modules}', (
SELECT jsonb_agg(
CASE WHEN item->>'id' = control_module.id::text THEN item || jsonb_build_object(
'defaultParameters', jsonb_build_array('sim_mode:=false', 'robot:=mkmini', 'level:=2d'),
'dockerImage', 'future-nav2:humble-jetson_orin'
) ELSE item END
)
FROM jsonb_array_elements(profile.config->'moduleSet'->'modules') AS item
CROSS JOIN LATERAL (
SELECT module.id
FROM course_weeks week
JOIN course_week_modules module ON module.week_id = week.id
WHERE week.course_id = profile.course_id
AND week.week = profile.week
AND module.name = 'NAV2-Control'
) AS control_module
), true)
WHERE profile.course_id IN (SELECT id FROM target_course)
AND profile.platform_key IN ('REAL_SLAM', 'REAL_NAVIGATION');
INSERT INTO course_week_maps (id, course_id, week, map_key, sort_order, created_at, updated_at)
SELECT gen_random_uuid(), target_course.id, weeks.week, map.map_key, map.sort_order, now(), now()
FROM target_course
CROSS JOIN (VALUES (1), (2)) AS weeks(week)
CROSS JOIN (VALUES ('nav2-turtlebot3-world', 1), ('nav2-turtlebot3-house', 2)) AS map(map_key, sort_order);
UPDATE instructor_curriculum_settings
SET active_week = 1, active_learning_step = 'ROS2 기초'
WHERE course_id IN (SELECT id FROM target_course);
COMMIT;