- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 1. ロボティクスの基礎
- 2. ROS2 (Robot Operating System 2)
- 3. センサー処理
- 4. SLAM (Simultaneous Localization and Mapping)
- 5. モーションプランニング
- 6. ロボット向けコンピュータビジョン
- 7. 強化学習ベースのロボット制御
- 8. 自律走行
- 9. 2026年のヒューマノイドロボット
- 10. クイズ: ロボティクス&AI 基礎確認
- 参考資料
1. ロボティクスの基礎
自由度 (DOF: Degrees of Freedom)
ロボットの自由度とは、ロボットが独立して動ける軸の数のことです。6自由度ロボットアームは、3次元空間における任意の位置と姿勢を表現するために必要な最小限の自由度を持ちます。指を含む全身ヒューマノイドロボットは50自由度以上を持つことがあります。
| 自由度 | 表現可能な運動 | 例 |
|---|---|---|
| 1-DOF | 単軸回転/並進 | コンベヤーベルト |
| 3-DOF | 3次元位置のみ | デルタロボット |
| 6-DOF | 位置+姿勢の完全制御 | 産業用ロボットアーム |
| 7-DOF | 冗長自由度あり | KUKA iiwa、Franka Panda |
座標変換: 同次変換行列
3D空間における剛体の位置と姿勢を表現するために、ロボティクスでは**同次変換行列(Homogeneous Transformation Matrix)**を使用します。4x4行列で回転(R)と平行移動(t)を同時に表現します。
複数の座標系間の変換は行列積として連鎖的に適用できます。
順運動学 (Forward Kinematics)
順運動学は、各関節の角度(関節角度)が与えられたときにエンドエフェクターの位置と姿勢を計算する問題です。各関節に対応する変換行列を掛け合わせて求めます。
import numpy as np
def dh_transform(a, d, alpha, theta):
"""Denavit-Hartenberg変換行列を計算"""
ct, st = np.cos(theta), np.sin(theta)
ca, sa = np.cos(alpha), np.sin(alpha)
return np.array([
[ct, -st*ca, st*sa, a*ct],
[st, ct*ca, -ct*sa, a*st],
[0, sa, ca, d ],
[0, 0, 0, 1 ]
])
def forward_kinematics(joint_angles, dh_params):
"""
順運動学: 関節角度 -> エンドエフェクターの位置/姿勢
dh_params: [(a, d, alpha, theta_offset), ...]
"""
T = np.eye(4)
for i, theta in enumerate(joint_angles):
a, d, alpha, theta_off = dh_params[i]
T = T @ dh_transform(a, d, alpha, theta + theta_off)
return T
# 2自由度平面アームの例 (リンク長各1.0m)
dh_params_2dof = [
(1.0, 0, 0, 0),
(1.0, 0, 0, 0),
]
joint_angles = [np.pi/4, np.pi/4]
T_end = forward_kinematics(joint_angles, dh_params_2dof)
print("エンドエフェクター位置:", T_end[:3, 3])
逆運動学 (Inverse Kinematics)
逆運動学は、望ましいエンドエフェクターの位置/姿勢から必要な関節角度を計算する問題です。解析的手法(Analytical IK)と数値的手法(ヤコビアンベースの反復IK)があります。
数値的逆運動学の核心は、ヤコビアン行列 を用いた反復計算です。
ここで はヤコビアンの擬似逆行列です。特異点(singularity)の近傍ではヤコビアンがランク不足となり、数値的不安定性が生じます。
DH パラメータ (Denavit-Hartenberg)
DH規則は、ロボットの各リンクに座標系を体系的に割り当てる手法です。各関節はリンク長 、リンクのねじれ 、リンクオフセット 、関節角 の4つのパラメータで記述されます。
2. ROS2 (Robot Operating System 2)
ROS1 vs ROS2: 主な違い
ROS2はROS1の欠点を克服するために、**DDS(Data Distribution Service)**ベースの通信で再設計されました。
| 項目 | ROS1 | ROS2 |
|---|---|---|
| 通信ミドルウェア | 独自TCP/UDP | DDS (OMG標準) |
| リアルタイム対応 | 不十分 | 対応 (rclcpp rt) |
| Pythonバージョン | Python 2/3 | Python 3専用 |
| セキュリティ | なし | SROS2 (TLS/DDS) |
| マルチロボット | 困難 | 名前空間で容易 |
| ライフサイクルノード | なし | LifecycleNode対応 |
基本概念: ノード、トピック、サービス、アクション
- ノード(Node): 独立した実行単位。1つのプロセスまたは複数のノードを含む
- トピック(Topic): 発行(publish)/購読(subscribe)の非同期メッセージ通信
- サービス(Service): 要求/応答(request/response)の同期通信
- アクション(Action): 長時間実行タスク向けの非同期通信(フィードバック付き)
ROS2 Python パブリッシャー/サブスクライバーの例
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class TalkerNode(Node):
def __init__(self):
super().__init__('talker')
self.publisher = self.create_publisher(String, 'chatter', 10)
self.timer = self.create_timer(0.5, self.publish_msg)
self.count = 0
def publish_msg(self):
msg = String()
msg.data = f'Hello ROS2: {self.count}'
self.publisher.publish(msg)
self.get_logger().info(f'Published: {msg.data}')
self.count += 1
class ListenerNode(Node):
def __init__(self):
super().__init__('listener')
self.subscription = self.create_subscription(
String, 'chatter', self.callback, 10
)
def callback(self, msg):
self.get_logger().info(f'Received: {msg.data}')
def main():
rclpy.init()
node = TalkerNode()
rclpy.spin(node)
rclpy.shutdown()
ランチファイルの例
# launch/my_robot.launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='my_robot',
executable='talker',
name='talker_node',
output='screen',
parameters=[{'use_sim_time': False}],
),
Node(
package='my_robot',
executable='listener',
name='listener_node',
output='screen',
),
])
実行コマンド: ros2 launch my_robot my_robot.launch.py
3. センサー処理
LiDAR: 点群処理
LiDAR(Light Detection And Ranging)はレーザーを使用して3D点群を生成します。自律走行および3Dマッピングに不可欠です。
import open3d as o3d
import numpy as np
def process_pointcloud(pcd_path):
# 点群の読み込み
pcd = o3d.io.read_point_cloud(pcd_path)
# 統計的外れ値除去
pcd_clean, _ = pcd.remove_statistical_outlier(
nb_neighbors=20, std_ratio=2.0
)
# ボクセルダウンサンプリング (解像度削減)
pcd_down = pcd_clean.voxel_down_sample(voxel_size=0.05)
# 法線推定
pcd_down.estimate_normals(
search_param=o3d.geometry.KDTreeSearchParamHybrid(
radius=0.1, max_nn=30
)
)
# RANSAC平面分割 (地面除去)
plane_model, inliers = pcd_down.segment_plane(
distance_threshold=0.01,
ransac_n=3,
num_iterations=1000
)
[a, b, c, d] = plane_model
print(f"地面平面方程式: {a:.2f}x + {b:.2f}y + {c:.2f}z + {d:.2f} = 0")
# 地面以外のオブジェクトを抽出
objects_pcd = pcd_down.select_by_index(inliers, invert=True)
return objects_pcd
IMUとカルマンフィルター
IMU(慣性計測装置)は加速度計とジャイロスコープを含み、ロボットの姿勢と速度を推定します。カルマンフィルターを使用してノイズを低減し、正確な状態推定を行います。
カルマンフィルターの2つのステップ:
- 予測(Predict): 運動モデルを使用して現在の状態を予測
- 更新(Update): センサー測定値で予測値を補正
ここで はカルマンゲイン、 は測定値です。非線形システムには拡張カルマンフィルター(EKF)を使用します。
4. SLAM (Simultaneous Localization and Mapping)
SLAMとは?
SLAMは、ロボットが未知の環境を探索しながら同時に地図を作成し、自身の位置を推定する技術です。ロボットナビゲーションと自律走行の根本的な問題です。
SLAMの主要な課題:
- データアソシエーション: 現在の観測がどのランドマークに対応するかのマッチング
- ループクロージャ: 以前に訪問した場所を認識して累積誤差を補正
- 地図表現: 特徴点マップ、占有格子マップ、位相的マップなど
EKF-SLAM
**拡張カルマンフィルター(EKF)**を用いたSLAM。非線形のロボット運動/観測モデルを1次テイラー展開で線形化します。
状態ベクトル: ロボットポーズ + 全ランドマーク位置
ランドマーク数 に対して計算複雑度が となるため、大規模環境では限界があります。
グラフベースSLAM
現代的なSLAMシステムはグラフベースの定式化を使用します。ポーズがグラフのノードとなり、センサー制約がエッジとなります。ループクロージャが検出されると、非線形最小二乗法(g2o、GTSAMなど)によってグラフ全体が最適化されます。
実際のSLAMライブラリ
| ライブラリ | 手法 | センサー | 特徴 |
|---|---|---|---|
| Cartographer | グラフSLAM | LiDAR、IMU | Google開発、ROS2対応 |
| ORB-SLAM3 | 特徴ベース | カメラ、IMU | リアルタイム単眼/ステレオ |
| LIO-SAM | 密結合 | LiDAR + IMU | 屋外大規模環境 |
| RTAB-Map | グラフSLAM | RGB-D、LiDAR | リアルタイム3Dマッピング |
# ROS2 HumbleにCartographerをインストール
sudo apt install ros-humble-cartographer-ros
# TurtleBot3でCartographerを起動
ros2 launch turtlebot3_cartographer cartographer.launch.py
5. モーションプランニング
経路計画アルゴリズムの概要
モーションプランニングは、障害物を避けながら開始構成から目標構成まで衝突のない経路を見つける問題です。
- グリッドベース: A*、Dijkstra — 離散グリッドで最適経路を探索
- サンプリングベース: RRT、PRM — 高次元構成空間で効率的
- 最適化ベース: CHOMP、STOMP — コスト関数を最適化
RRT* の実装
**RRT*(Rapidly-exploring Random Tree Star)**は漸近的最適性を保証するサンプリングベースのアルゴリズムです。
import numpy as np
def rrt_star(start, goal, obstacles, max_iter=1000, step=0.5, goal_radius=0.5):
"""
シンプルな2D RRT* 実装
start, goal: np.array([x, y])
obstacles: [(cx, cy, radius), ...]
"""
nodes = [start]
parents = [-1]
costs = [0.0]
def is_collision(p1, p2):
"""線分 p1-p2 が障害物と衝突するか検査"""
for (cx, cy, r) in obstacles:
center = np.array([cx, cy])
d = p2 - p1
t = np.clip(np.dot(center - p1, d) / (np.dot(d, d) + 1e-9), 0, 1)
closest = p1 + t * d
if np.linalg.norm(closest - center) < r:
return True
return False
for _ in range(max_iter):
rand = goal if np.random.random() < 0.05 else np.random.uniform(-10, 10, 2)
dists = [np.linalg.norm(np.array(n) - rand) for n in nodes]
nearest_idx = int(np.argmin(dists))
nearest = np.array(nodes[nearest_idx])
direction = rand - nearest
norm = np.linalg.norm(direction)
if norm < 1e-9:
continue
new_node = nearest + step * direction / norm
if is_collision(nearest, new_node):
continue
nodes.append(new_node)
parents.append(nearest_idx)
costs.append(costs[nearest_idx] + step)
if np.linalg.norm(new_node - goal) < goal_radius:
print(f"目標到達! 総ノード数: {len(nodes)}")
return nodes, parents
return nodes, parents
# 実行例
start = np.array([0.0, 0.0])
goal = np.array([9.0, 9.0])
obstacles = [(5.0, 5.0, 1.5), (3.0, 7.0, 1.0)]
nodes, parents = rrt_star(start, goal, obstacles)
MoveIt2とロボットアームのモーションプランニング
MoveIt2はROS2においてロボットアームのモーションプランニングのための標準フレームワークです。OMPL、STOMP、CHOMPなど複数のプランニングライブラリを統一APIでラップします。
# MoveIt2 Python API の例
import rclpy
from moveit.planning import MoveItPy
rclpy.init()
moveit = MoveItPy(node_name='moveit_py_planning')
panda_arm = moveit.get_planning_component('panda_arm')
# 目標ポーズの設定
from geometry_msgs.msg import PoseStamped
goal_pose = PoseStamped()
goal_pose.header.frame_id = 'panda_link0'
goal_pose.pose.position.x = 0.5
goal_pose.pose.position.y = 0.0
goal_pose.pose.position.z = 0.5
goal_pose.pose.orientation.w = 1.0
panda_arm.set_goal_state(pose_stamped_msg=goal_pose, pose_link='panda_hand')
# 計画と実行
plan_result = panda_arm.plan()
if plan_result:
moveit.execute(plan_result.trajectory)
6. ロボット向けコンピュータビジョン
物体検出
ロボットが動的な環境を認識するために、**YOLO(You Only Look Once)**系のモデルがリアルタイム物体検出に広く使用されています。
from ultralytics import YOLO
import cv2
# YOLOv11ナノモデルのロード
model = YOLO('yolo11n.pt')
def detect_objects(frame):
"""カメラフレームから物体を検出"""
results = model(frame, conf=0.5)
annotated = results[0].plot()
for box in results[0].boxes:
cls_id = int(box.cls[0])
label = model.names[cls_id]
conf = float(box.conf[0])
x1, y1, x2, y2 = map(int, box.xyxy[0])
print(f"{label}: {conf:.2f} at ({x1},{y1})-({x2},{y2})")
return annotated
# Webカメラでリアルタイム検出
cap = cv2.VideoCapture(0)
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
annotated_frame = detect_objects(frame)
cv2.imshow('Robot Vision', annotated_frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
6Dポーズ推定
ロボットが物体を把持するためには、物体の6Dポーズ(3D位置 + 3D方向)を推定する必要があります。**PnP(Perspective-n-Point)**アルゴリズムを使用します。
import cv2
import numpy as np
def estimate_pose(object_points, image_points, camera_matrix, dist_coeffs):
"""
PnPアルゴリズムによる6Dポーズ推定
object_points: 物体座標系での3D点
image_points: 対応する2D画像座標
"""
success, rvec, tvec = cv2.solvePnP(
object_points, image_points,
camera_matrix, dist_coeffs,
flags=cv2.SOLVEPNP_ITERATIVE
)
if success:
R, _ = cv2.Rodrigues(rvec)
print(f"位置: {tvec.flatten()}")
print(f"回転行列:\n{R}")
return R, tvec
return None, None
7. 強化学習ベースのロボット制御
ロボット学習のシミュレーション環境
| シミュレーター | 開発元 | 特徴 | 用途 |
|---|---|---|---|
| MuJoCo | Google DeepMind | 高精度物理、高速 | 連続制御研究 |
| PyBullet | Erwin Coumans | オープンソース | プロトタイピング |
| Isaac Gym | NVIDIA | GPU並列シミュレーション | 大規模RL学習 |
| CARLA | Intel/UPV | 自動運転特化 | AD研究 |
SACによる連続制御学習
**SAC(Soft Actor-Critic)**はエントロピー正則化を取り入れたオフポリシー強化学習アルゴリズムで、探索と活用のバランスを自動的に調整します。
import gymnasium as gym
from stable_baselines3 import SAC
from stable_baselines3.common.callbacks import EvalCallback
# MuJoCo Ant環境でSACを学習
env = gym.make('Ant-v4', render_mode=None)
eval_env = gym.make('Ant-v4', render_mode=None)
eval_callback = EvalCallback(
eval_env,
best_model_save_path='./logs/best_model',
log_path='./logs/',
eval_freq=10000,
deterministic=True,
render=False
)
# SACモデルの作成
model = SAC(
'MlpPolicy',
env,
verbose=1,
learning_rate=3e-4,
buffer_size=1_000_000,
batch_size=256,
ent_coef='auto',
gamma=0.99,
tau=0.005,
tensorboard_log='./tb_logs/'
)
# 学習
model.learn(total_timesteps=1_000_000, callback=eval_callback)
model.save('ant_sac_final')
# 推論 (デプロイ)
obs, _ = env.reset()
total_reward = 0.0
for _ in range(1000):
action, _ = model.predict(obs, deterministic=True)
obs, reward, done, truncated, info = env.step(action)
total_reward += reward
if done or truncated:
print(f"エピソード終了。総報酬: {total_reward:.2f}")
obs, _ = env.reset()
total_reward = 0.0
Sim-to-Real転移
シミュレーションで学習した方策を実際のロボットに適用する際のReality Gap問題を解決する手法:
- ドメインランダム化(Domain Randomization): シミュレーション中に物理パラメーター(摩擦、質量、関節剛性)をランダムに変化させ、実環境の変動性に頑健な方策を学習
- ドメイン適応(Domain Adaptation): 少量の実世界データで方策をファインチューニング
- システム同定(System Identification): 実際のロボットの物理パラメーターを正確に測定してシミュレーターに反映
- ランダム化レンダリング: ビジョンベースの方策では、テクスチャ、照明、カメラ特性をランダム化
8. 自律走行
SAE自律走行レベル
| レベル | 名称 | 説明 | 例 |
|---|---|---|---|
| L0 | 非自動化 | ドライバーが完全制御 | 一般車両 |
| L1 | 運転支援 | 単一機能の補助 | ACC、LKAS |
| L2 | 部分自動化 | 複合機能の自動化 | Tesla Autopilot |
| L3 | 条件付き自動化 | 特定条件での自律 | Mercedes Drive Pilot |
| L4 | 高度自動化 | 指定区域での完全自律 | Waymo One |
| L5 | 完全自動化 | 全条件での自律 | (未実現) |
認識-予測-計画-制御パイプライン
class AutonomousDrivingSystem:
"""自律走行システムの基本パイプライン"""
def __init__(self, perception, prediction, planning, control):
self.perception = perception # 認識モジュール
self.prediction = prediction # 予測モジュール
self.planning = planning # 計画モジュール
self.control = control # 制御モジュール
self.goal = None
def run_step(self, sensor_data):
# 1. 認識: センサーデータから物体検出・追跡、自己位置推定
detected_objects = self.perception.detect(sensor_data)
ego_state = self.perception.localize(sensor_data)
# 2. 予測: 周囲の車両・歩行者の将来軌跡を予測
predicted_trajectories = self.prediction.predict(
detected_objects, horizon=3.0 # 3秒予測
)
# 3. 計画: 目標まで安全な経路を計画
trajectory = self.planning.plan(
ego_state, predicted_trajectories, goal=self.goal
)
# 4. 制御: 計画された経路を追従
steering, throttle, brake = self.control.compute(
ego_state, trajectory
)
return steering, throttle, brake
9. 2026年のヒューマノイドロボット
2026年、ヒューマノイドロボット市場は急激に成長しています。主要プレイヤーの最新状況を見ていきます。
主要ヒューマノイドロボット比較
| ロボット | 企業 | 身長/重量 | 主な特徴 |
|---|---|---|---|
| Atlas (電動) | Boston Dynamics | 1.5m / 89kg | 電動アクチュエーター、高度な移動性 |
| Optimus Gen 3 | Tesla | 1.73m / 57kg | 手に22自由度、FSD AIスタック搭載 |
| Figure 02 | Figure AI | 1.7m / 60kg | OpenAI連携、音声理解 |
| Unitree H1/G1 | Unitree Robotics | 1.8m/1.3m | コスト効率、オープンソース対応 |
| 1X NEO Beta | 1X Technologies | 1.65m / 30kg | 軽量化、ソフトアクチュエーター |
ロボット向けファウンデーションモデル
**RT-2(Robotics Transformer 2)**はGoogle DeepMindが開発したビジョン-言語-行動(VLA)モデルで、Webスケールのデータから学習した知識をロボット制御に直接活用します。自然言語コマンドを理解し、新しい物体にも汎化できます。
OpenVLAはオープンソースのVLAモデルで、研究者が自身のロボットデータでファインチューニングして使用できます。
# OpenVLA推論の例 (概念コード)
from transformers import AutoModelForVision2Seq, AutoProcessor
import torch
model_name = "openvla/openvla-7b"
processor = AutoProcessor.from_pretrained(model_name, trust_remote_code=True)
model = AutoModelForVision2Seq.from_pretrained(
model_name,
torch_dtype=torch.bfloat16,
device_map='auto',
trust_remote_code=True
)
# ビジョン+言語命令からロボット行動を生成
image = get_camera_image() # ロボットのリストカメラ画像
instruction = "pick up the red block and place it in the box"
inputs = processor(instruction, image).to('cuda:0', dtype=torch.bfloat16)
action = model.predict_action(**inputs, unnorm_key='bridge_orig', do_sample=False)
# action: [dx, dy, dz, droll, dpitch, dyaw, gripper]
robot.execute_action(action)
組み込みAIとオンデバイス推論
ヒューマノイドロボットの頭脳はクラウドに依存せず、リアルタイムで動作する必要があります。NVIDIA Jetson AGX Orin (275 TOPS)やQualcomm Robotics RB5などのエッジAIチップが鍵となります。
効率的なオンデバイス推論のための主要技術:
- 量子化(Quantization): INT8/FP16でモデルサイズと推論速度を最適化
- プルーニング(Pruning): 冗長な重みを削除して計算量を削減
- TensorRT / ONNX Runtime: ハードウェア最適化推論エンジン
- 知識蒸留(Distillation): 大きなモデルから小さなモデルへの知識転移
10. クイズ: ロボティクス&AI 基礎確認
Q1. SLAMにおいてループクロージャが重要な理由は何ですか?
正解: ロボットが以前に訪問した場所を認識し、累積された位置推定誤差を補正するためです。
解説: 長時間の探索中、小さなセンサーおよびオドメトリーの誤差が累積し、推定された軌跡が実際の軌跡から大きくずれていきます。ループクロージャが検出されると(特徴マッチングや場所認識などによって)、グラフ最適化ステップ(g2oやGTSAMなど)が過去のすべてのポーズに累積誤差を分散させ、地図の一貫性を大幅に向上させます。
Q2. ROS2がDDSを採用することの主な利点は何ですか?
正解: 標準化されたミドルウェア、リアルタイムサポート、マルチロボット環境でのネットワーク柔軟性、単一障害点の排除(roscoreが不要)、セキュリティ(SROS2)のサポートです。
解説: ROS1は単一のroscoreプロセスに依存していたため、単一障害点が存在しました。ROS2のDDSベースのアーキテクチャは完全に分散型で、ノードはブローカーなしに自動的に互いを発見します。QoS(Quality of Service)ポリシーにより、通信の信頼性、レイテンシ、履歴を細かく制御できます。SROS2はTLSベースの暗号化と認証を追加します。
Q3. SACアルゴリズムにおけるエントロピー項の役割は何ですか?
正解: エントロピーを報酬信号の一部に含めることで方策の確率的性質(探索レベル)を維持し、過度に決定論的な行動への早期収束を防ぎます。
解説: SACの目標は期待報酬と方策エントロピーの和を最大化することです。エントロピー係数(alpha)が大きいほど探索が強調されます。'auto'に設定するとSACはalphaを動的に調整して目標エントロピーレベルを維持します。このメカニズムは局所最適解から抜け出し、未知の状況によりよく汎化するより頑健な方策を生み出します。
Q4. 逆運動学が順運動学より根本的に難しい理由は何ですか?
正解: 逆運動学は解が存在しない場合、唯一の解がある場合、または無限に多くの解がある場合がある非線形方程式系であるのに対し、順運動学は常に唯一の結果を生成するからです。
解説: 順運動学は変換行列の単純な合成で、関節角度が与えられれば正確に1つのエンドエフェクターポーズが得られます。逆運動学はこのマッピングを逆算します。7自由度の冗長マニピュレーターでは、同じエンドエフェクターポーズに達する関節構成が無限に存在します(運動学的冗長性)。ワークスペース境界では解が存在しないことがあります。特異点付近ではヤコビアンがランク不足となり、反復ソルバーで数値的不安定性が生じます。
Q5. Sim-to-Real転移においてドメインランダム化が効果的な理由は?
正解: 広範なシミュレーション物理パラメーターの分布で学習することで、方策が実世界に存在する変動性に対して頑健になるからです。
解説: 固定されたシミュレーションパラメーターで学習した方策は、それらの特定の条件に過適合し、実際の物理特性が異なる場合(異なる摩擦、アクチュエーター遅延、センサーノイズ)に失敗します。ドメインランダム化は実世界をトレーニング分布のサンプルの1つとして扱います。OpenAIの器用な手の研究やNVIDIAの四足歩行研究は、大規模にランダム化されたシミュレーションのみで驚くべき実世界性能を達成したこのアプローチのランドマークデモンストレーションです。