仿真环境下实现场景切换、定位物体和导航行走

发布于:2025-02-28 ⋅ 阅读:(107) ⋅ 点赞:(0)

1. 代码(以微波炉为例)

from ai2thor.controller import Controller
import math
import random

def distance_2d(pos1, pos2):
    """计算两点之间的二维欧几里得距离(忽略Z轴)"""
    return math.sqrt((pos1['x'] - pos2['x']) ** 2 + (pos1['y'] - pos2['y']) ** 2)

def get_reachable_positions(controller):
    """获取所有可达位置"""
    reachable_positions = controller.step(
        action="GetReachablePositions"
    ).metadata["actionReturn"]
    return [{k: pos[k] for k in ['x', 'y']} for pos in reachable_positions]

def move_towards_target_2d(controller, target_position):
    """导航到目标位置(仅考虑X和Y坐标)"""
    max_attempts = 5
    attempt = 0
    while attempt < max_attempts:
        current_position = {k: controller.last_event.metadata["agent"]["position"][k] for k in ['x', 'y']}
        if distance_2d(current_position, target_position) <= 0.5:  # 目标精度为0.5米
            print("到达目标附近")
            return True
        
        diff_x = target_position['x'] - current_position['x']
        diff_y = target_position['y'] - current_position['y']

        if abs(diff_x) > abs(diff_y):
            action = "MoveRight" if diff_x > 0 else "MoveLeft"
        else:
            action = "MoveAhead" if diff_y > 0 else "MoveBack"

        event = controller.step(action=action, moveMagnitude=0.5)
        print(f"移动:{action}{event.metadata['lastActionSuccess']}")
        if not event.metadata["lastActionSuccess"]:
            print(f"移动失败:{event.metadata['errorMessage']}")
            possible_actions = ["MoveRight", "MoveLeft", "MoveAhead", "MoveBack"]
            possible_actions.remove(action)  # 移除当前尝试失败的动作
            random_action = random.choice(possible_actions)
            event = controller.step(action=random_action, moveMagnitude=0.5)
            if not event.metadata["lastActionSuccess"]:
                print(f"尝试反方向移动也失败了:{event.metadata['errorMessage']}")
                back_action = "MoveBack" if diff_y > 0 else "MoveAhead"
                controller.step(action=back_action, moveMagnitude=0.5)
                attempt += 1
                continue
            else:
                print(f"新方向移动成功:{random_action}")
    print("不知道如何抵达")
    return False

def manual_movement(controller):
    """手动控制移动"""
    while True:
        user_input = input("请输入移动指令(WASD键分别代表上、左、下、右),输入Q退出手动模式:").upper()
        if user_input == 'Q':
            print("退出手动模式")
            break
        elif user_input in ['W', 'A', 'S', 'D']:
            action_map = {'W': 'MoveAhead', 'A': 'MoveLeft', 'S': 'MoveBack', 'D': 'MoveRight'}
            action = action_map[user_input]
            event = controller.step(action=action, moveMagnitude=0.5)
            if event.metadata["lastActionSuccess"]:
                print(f"{action} 成功!")
            else:
                print(f"{action} 失败:{event.metadata['errorMessage']}")
        else:
            print("无效输入,请重新输入")

controller = Controller(
    width=1280,
    height=720,
    fieldOfView=110,
    visibilityDistance=5,
    renderInstanceSegmentation=True
)

scenes = ["FloorPlan1", "FloorPlan201", "FloorPlan301", "FloorPlan401"]
scene_names = ["厨房", "客厅", "卧室", "浴室"]

while True:
    scene_choice = input("请输入场景编号(1-厨房,2-客厅,3-卧室,4-浴室),输入'Q'进入手动模式:")
       
    if scene_choice.lower() == 'q':
        print("进入手动模式")
        manual_movement(controller)
        continue
    
    try:
        scene_number = int(scene_choice)
        if scene_number < 1 or scene_number > 4:
            raise ValueError()
    except ValueError:
        print("无效的输入,请重新输入")
        continue

    selected_scene = scenes[scene_number - 1]
    selected_scene_name = scene_names[scene_number - 1]
    
    controller.reset(selected_scene)
    reachable_positions = get_reachable_positions(controller)

    microwaves = [obj for obj in controller.last_event.metadata["objects"] if obj["objectType"] == "Microwave"]

    if len(microwaves) > 0:
        target = microwaves[0]
        target_position = {'x': target["position"]['x'], 'y': target["position"]['y']}
        print(f"{selected_scene_name}中目标微波炉位置: {target_position}")
        success = move_towards_target_2d(controller, target_position)
        if success:
            # 抓取动作
            event = controller.step(action="PickupObject", objectId=target["objectId"])
            if event.metadata["lastActionSuccess"]:
                print(f"{selected_scene_name}中抓取成功!")
            else:
                print(f"{selected_scene_name}中抓取失败:{event.metadata['errorMessage']}")
    else:
        print(f"{selected_scene_name}中没有微波炉")

controller.stop()

2. 效果

ITHOR场景切换、导航

ITHOR场景切换、导航
在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到