お遊びネタ!AI搭載ドローン防衛シミュレーションを自作

プログラミングで体験!AI搭載ドローン防衛シミュレーションを自作

1. なぜAI搭載ドローンが話題?

ドローンにAI(人工知能)が搭載されることで、「画像解析」「経路最適化」「自動監視・防衛」など、従来人間が行っていた複雑な判断や操作が自動化できるようになりました。防衛・災害対応・インフラ点検・農業など多様な分野で活用が進み、今や国や企業だけでなく、趣味の分野でも“AIドローン”は注目の的です。
  • 敵や障害物を自動で検知し、回避する
  • 人間の指示がなくても目的地に到達する
  • 画像・映像から危険や異常を素早く発見する

こうした最先端のテクノロジーが身近に感じられる方法として、「シミュレーションの自作」をおすすめします!

2. 最新AIニュースと社会背景

■ AIと防衛:日本の最新動向

2025年6月、防衛省は「AI搭載装備品のガイドライン」を策定し、安全性や倫理性を確保しながら防衛AI技術の開発を加速する方針を発表しました。これは世界的なAI軍拡競争に対応しつつ、透明性説明責任を担保する試みです。

背景解説:
  • AI活用が進む中、ドローンなど「無人化防衛システム」の研究が活発化
  • 社会全体でAIのリスクとベネフィットの議論が進む(軍事、災害、産業…)
  • 著作権や倫理問題にも配慮した政策づくりが求められている

■ 英語圏のAIニュースから

Getty ImagesがStability AIを著作権侵害で提訴(2025年6月)。AIによる画像生成や解析における「データ利用の倫理」もホットな話題。AI業界の成長に法整備や社会的ルールが不可欠になっています。

3. Pythonで作る!AI防衛シミュレーション

■ シナリオ概要

目標:AI搭載ドローン(青い点)が敵(赤い点)を自動検知し、回避しながら基地(緑四角)を目指すシンプルなシミュレーションです。Pythonと「pygame」ライブラリで実装します。

準備:
  1. Python 3.xをインストール
  2. ターミナル/コマンドプロンプトで pip install pygame を実行
  3. 下記コードを貼り付けて実行!

■ サンプルコード


import pygame
import heapq
import random
import math
import os

WIDTH, HEIGHT = 600, 400
GRID = 20
ROWS, COLS = HEIGHT // GRID, WIDTH // GRID

BLUE = (0, 150, 255)
RED = (255, 50, 50)
GREEN = (50, 200, 50)
WHITE = (255, 255, 255)
GRAY = (170, 170, 170)
BLACK = (30, 30, 30)

ENEMY_NUM = 10
OBSTACLE_NUM = 10
ENEMY_MOVE_INTERVAL = 6
OBSTACLE_MOVE_INTERVAL = 18
MAX_EPISODES = 10
CATCH_RANGE = 1

def heuristic(a, b):
    return abs(a[0] - b[0]) + abs(a[1] - b[1])

def get_neighbors(pos):
    neighbors = []
    x, y = pos
    for dx, dy in [(-1,0), (1,0), (0,-1), (0,1)]:
        nx, ny = x+dx, y+dy
        if 0 <= nx < COLS and 0 <= ny < ROWS:
            neighbors.append((nx, ny))
    return neighbors

def astar(start, goal, grid_map):
    heap = []
    heapq.heappush(heap, (0, start))
    came_from = {}
    cost_so_far = {start: 0}
    while heap:
        _, current = heapq.heappop(heap)
        if current == goal:
            break
        for neighbor in get_neighbors(current):
            if grid_map[neighbor[1]][neighbor[0]] == 1:
                continue
            new_cost = cost_so_far[current] + 1
            if neighbor not in cost_so_far or new_cost < cost_so_far[neighbor]:
                cost_so_far[neighbor] = new_cost
                priority = new_cost + heuristic(goal, neighbor)
                heapq.heappush(heap, (priority, neighbor))
                came_from[neighbor] = current
    if goal not in came_from:
        return None
    # 経路復元
    path = [goal]
    while path[-1] != start:
        path.append(came_from[path[-1]])
    path.reverse()
    return path

def random_move(pos, grid_map):
    candidates = []
    for n in get_neighbors(pos):
        if grid_map[n[1]][n[0]] == 0:
            candidates.append(n)
    return random.choice(candidates) if candidates else pos

def random_move_wall(pos, grid_map, start, goal, avoid=[]):
    candidates = []
    for n in get_neighbors(pos):
        if (grid_map[n[1]][n[0]] == 0 and n != start and n != goal and n not in avoid):
            candidates.append(n)
    return random.choice(candidates) if candidates else pos

# --- 日本語フォント自動検出 ---
def get_jp_font(size=30):
    font_paths = [
        "C:/Windows/Fonts/msgothic.ttc",
        "C:/Windows/Fonts/meiryo.ttc",
        "/usr/share/fonts/truetype/fonts-japanese-gothic.ttf",
        "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
        "/System/Library/Fonts/ヒラギノ角ゴシック W3.ttc",
        "/usr/share/fonts/opentype/ipaexfont-gothic/ipaexg.ttf",
    ]
    for path in font_paths:
        if os.path.exists(path):
            return pygame.font.Font(path, size)
    return pygame.font.SysFont(None, size)

def main():
    pygame.init()
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    pygame.display.set_caption("動的A*ドローン防衛シミュレーション(兵士10人・突破可能)")
    font = get_jp_font(28)
    font_small = get_jp_font(20)
    clock = pygame.time.Clock()

    start = (2, 2)
    goal = (COLS-3, ROWS-3)
    episode = 0
    results = []

    while episode < MAX_EPISODES:
        # 障害物
        fixed_obstacles = []
        while len(fixed_obstacles) < OBSTACLE_NUM:
            x = random.randint(4, COLS-4)
            y = random.randint(2, ROWS-2)
            p = (x, y)
            if p != start and p != goal and p not in fixed_obstacles:
                fixed_obstacles.append(p)
        # 敵(兵士): ゴール周囲3マスは空ける
        enemies = []
        while len(enemies) < ENEMY_NUM:
            if len(enemies) < ENEMY_NUM // 2:
                x = random.randint(COLS-7, COLS-4)
                y = random.randint(ROWS-7, ROWS-4)
            else:
                x = random.randint(6, COLS-7)
                y = random.randint(3, ROWS-4)
            p = (x, y)
            # ゴールとその周囲3マスは空ける
            if (abs(x-goal[0]) <= 3 and abs(y-goal[1]) <= 3):
                continue
            if p != start and p != goal and p not in fixed_obstacles and p not in enemies:
                enemies.append(p)

        drone_pos = start
        drone_path = [drone_pos]
        frame_count = 0
        running = True
        arrived = False
        msg = "詰み"

        while running:
            grid_map = [[0]*COLS for _ in range(ROWS)]
            for x, y in fixed_obstacles:
                grid_map[y][x] = 1
            for ex, ey in enemies:
                for dx in range(-2,3):
                    for dy in range(-2,3):
                        nx, ny = ex+dx, ey+dy
                        if 0<=nx 1:
                drone_pos = path[1]
                drone_path.append(drone_pos)

            # 敵(兵士)移動
            if running and frame_count % ENEMY_MOVE_INTERVAL == 0:
                new_enemies = []
                for e in enemies:
                    avoid = fixed_obstacles + enemies
                    ne = random_move(e, grid_map)
                    # ゴール周囲3マスは入れない
                    if (abs(ne[0]-goal[0]) <= 3 and abs(ne[1]-goal[1]) <= 3):
                        new_enemies.append(e)
                    elif ne != start and ne != goal:
                        new_enemies.append(ne)
                    else:
                        new_enemies.append(e)
                enemies = new_enemies

            # 障害物移動
            if running and frame_count % OBSTACLE_MOVE_INTERVAL == 0:
                new_fixed_obstacles = []
                for i, o in enumerate(fixed_obstacles):
                    avoid = [start, goal] + enemies + new_fixed_obstacles + fixed_obstacles[i+1:]
                    no = random_move_wall(o, grid_map, start, goal, avoid=avoid)
                    new_fixed_obstacles.append(no)
                fixed_obstacles = new_fixed_obstacles

            # 捕捉判定
            for ex, ey in enemies:
                if abs(drone_pos[0]-ex)<=CATCH_RANGE and abs(drone_pos[1]-ey)<=CATCH_RANGE:
                    msg = "捕捉"
                    arrived = False
                    running = False
                    break

            screen.fill(WHITE)
            for y in range(ROWS):
                for x in range(COLS):
                    rect = pygame.Rect(x*GRID, y*GRID, GRID, GRID)
                    if grid_map[y][x] == 1:
                        pygame.draw.rect(screen, GRAY, rect)
                    pygame.draw.rect(screen, (220,220,220), rect, 1)
            for x, y in fixed_obstacles:
                pygame.draw.rect(screen, GRAY, (x*GRID+1, y*GRID+1, GRID-2, GRID-2))
            gx, gy = goal
            pygame.draw.rect(screen, GREEN, (gx*GRID+3, gy*GRID+3, GRID-6, GRID-6))
            for ex, ey in enemies:
                pygame.draw.circle(screen, RED, (ex*GRID+GRID//2, ey*GRID+GRID//2), GRID*2//3)
            for px, py in drone_path:
                pygame.draw.circle(screen, (100, 180, 255), (px*GRID+GRID//2, py*GRID+GRID//2), GRID//4)
            px, py = drone_pos
            pygame.draw.circle(screen, BLUE, (px*GRID+GRID//2, py*GRID+GRID//2), GRID//2)
            count_txt = font_small.render(f'{episode+1}回目/{MAX_EPISODES}', True, BLACK)
            screen.blit(count_txt, (10, 5))
            pygame.display.flip()
            clock.tick(13)
            frame_count += 1

        results.append(msg)
        result_show = font.render(f"{episode+1}回目: {msg}", True, BLACK)
        screen.blit(result_show, (WIDTH//2-80, HEIGHT//2-18))
        pygame.display.flip()
        pygame.time.wait(1100)
        episode += 1

    screen.fill(WHITE)
    endtxt = font.render(f"全{MAX_EPISODES}回終了", True, BLACK)
    screen.blit(endtxt, (WIDTH//2-80, HEIGHT//2-20))
    for i, r in enumerate(results):
        txt = font_small.render(f"{i+1}回目: {r}", True, BLACK)
        screen.blit(txt, (30, HEIGHT//2+20 + i*25))
    pygame.display.flip()
    pygame.time.wait(3500)
    pygame.quit()

if __name__ == "__main__":
    main()


        
アルゴリズム解説:
・ドローンは現在地からゴールまでの最短経路を A*(Aスター)アルゴリズム で探索します。
・A*は「今いる場所からゴールまでの推定コスト」を計算し、最も効率の良い道を毎回選びます。
・敵や障害物の周囲を「通行不可エリア」として扱い、安全な道筋だけを選択します。
・敵や障害物が動いた場合も、ドローンは毎ステップで新しい経路を再計算し、柔軟に対応します。
・ゴール到達まで「衝突を回避し続ける」ことがAIの目的です。

▶ A*アルゴリズム(Wikipedia日本語)

4. ステップアップ:さらにAI体験を深めるには

■ ステップごとに挑戦!

  1. Step 1: 敵や基地を複数配置、障害物を追加してみよう
  2. Step 2: 画像認識(OpenCVなど)を導入し、本物の画像から敵を識別
  3. Step 3: 強化学習(Q-LearningやDeep RL)を使った自己学習型AIへ
  4. Step 4: Webアプリ化して世界中からシミュレーション参加
  5. Step 5: Raspberry Piやマイコンと連携し、リアルドローンで試す
Tips:
Pythonの他にも「Unity + C#」や「Processing」「Javascript」で可視化したり、IoT機器とつなげて自宅セキュリティ実験も可能です!

5. ついでにこのブログを作成するにあたって調べた 注釈付き検索キーワード集

  • Mitigation(緩和):危険や損害を小さくすること
  • Optimization(最適化):ベストな解決策を見つけて効率を高めること
  • Guideline(指針):行動や判断の基準となるルール
  • Transparency(透明性):物事を明確にし、隠しごとがないこと
  • Ethics(倫理):善悪や社会的な規範に関わる考え方
  • Compensation(補償):損害や権利侵害へのお金や支払い
  • Threaten(脅かす):危険にさらすこと

6. まとめと今後の展望

AI搭載ドローンの技術は、今や国家の安全保障から日常の暮らし、趣味まで多様な場面で活躍の場を広げています。実際にプログラミングでシミュレーションを作ってみることで、最新ニュースの意味や、AIがもたらす変化を「自分ごと」として感じられるでしょう。

今後は、リアルな防衛シナリオやIoT機器との連携、AI倫理・法律への理解も欠かせません。まずは楽しく体験から始め、社会課題やキャリア・趣味に応用してみてください!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA