遗传算法向目标投掷球

时间:2019-10-23 11:57:59

标签: python genetic-algorithm physics-engine pymunk

我想用Pymunk产生一种遗传算法,其目的是向目标投掷一个球。

我知道大多数遗传算法的知识,但是Pymunk对我来说是新手。这个想法是,球将从一个固定的位置开始,例如距地面1.5m,距篮筐水平20m。假设球重1公斤。然后,球将以一定的力以一定的角度发射。适应度将是它在飞行过程中最接近目标中心的位置。

例如,人口中的某人看起来像[10.0, 5.0],其中10.0表示水平施加10N,5.0表示垂直施加5N。

我不希望它在我能看到的窗口中运行所有模拟,但我希望能够将其打开,以便在一定数量的代数之后或达到一定数量后,可以为最适合的个人运行它一定的健身水平。这是我的意思https://prnt.sc/pn1hoc的直观表示。

我已经尽力使用pymunk文档来解决这个问题,但是我发现它没有什么帮助,所以我很困惑。

我知道我需要启动一个空格

space = pymunk.Space()
space.gravity = (0.0, -900.0)  # not sure what this means?

然后在该空间中创建一个球

def add_ball(space):
    mass = 1
    radius = 14
    moment = pymunk.moment_for_circle(mass, 0, radius)
    body = pymunk.Body(mass, moment)
    body.position = 100, 150
    shape = pymunk.Circle(body, radius)
    space.add(body, shape)
    return shape

尽管这个球会开始掉落,但不确定如何使其静态开始。

然后要生成目标,我应该做类似

的操作
def add_target(space):
    body = pymunk.Body(body_type = pymunk.Body.STATIC)
    body.position = (500, 300)
    target = pymunk.Segment(body, (-150, 0), (-150, 50), 5)
    space.add(target)
    return target

我非常感谢将它们拼接在一起的一些帮助,这样我可以在我的遗传算法中运行仿真,也可以将其切换为在窗口中运行。

谢谢。

编辑:

我已经弄清楚了如何设置地板,这是到目前为止的所有代码

import sys, random
import pygame
from pygame.locals import *
import pymunk
import pymunk.pygame_util


def add_ball(space):
    mass = 1
    radius = 14
    moment = pymunk.moment_for_circle(mass, 0, radius)
    body = pymunk.Body(mass, moment)
    body.position = (50, 150)
    shape = pymunk.Circle(body, radius)
    space.add(body, shape)
    return shape


def add_floor(space):
    body = pymunk.Body(body_type = pymunk.Body.STATIC)
    body.position = (0, 0)
    target = pymunk.Segment(body, (0, 5), (600, 5), 5)
    space.add(target)
    return target


def add_target(space):
    body = pymunk.Body(body_type = pymunk.Body.STATIC)
    body.position = (700, 300)
    target = pymunk.Segment(body, (-150, 0), (-150, 50), 5)
    space.add(target)
    return target


def main():
    pygame.init()
    screen = pygame.display.set_mode((600, 600))
    clock = pygame.time.Clock()

    space = pymunk.Space()
    space.gravity = (0.0, -900.0)

    target = add_target(space)
    floor = add_floor(space)
    balls = []
    draw_options = pymunk.pygame_util.DrawOptions(screen)

    ball_count = 0
    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                sys.exit(0)
            elif event.type == KEYDOWN and event.key == K_ESCAPE:
                sys.exit(0)

        if ball_count < 1:
            ball_shape = add_ball(space)
            balls.append(ball_shape)
            ball_count += 1

        space.step(1/50.0)

        screen.fill((255,255,255))
        space.debug_draw(draw_options)

        pygame.display.flip()
        clock.tick(50)

if __name__ == '__main__':
    main()

1 个答案:

答案 0 :(得分:1)

我认为这个问题有几个部分。我的第一建议是从最小的东西开始,然后从那里开始扩展。当有多个部分令人困惑或您不知道如何解决时,这对于各种问题都非常有效。

以下是一些指针:

您需要弄清楚要如何测量健身度。一些示例:

  1. 在一定时间后测量球到目标的距离。这应该非常容易实现,因为当仿真结束时,您只需要测量一次即可。但是,可能很难决定应该几点。

  2. 在一次“掷”中测量球到目标的最小距离。我想这要好于1,但要取决于您要培训的内容。在这种情况下,您可以在每次调用step函数时测量距离,并跟踪其最小值。我认为我会从这种适合度的测量方法开始,因为它相当容易,但仍然感觉还可以。

您可能希望将模拟与显示分开。因此,您应该尝试编写执行一圈/“掷”的功能并将其模拟到最后。

例如,这是一个简单的示例,我将其与方法do_one_throw组合在一起,该方法以脉冲的脉冲作为输入,并通过1000个模拟步骤返回到目标的最小距离:

def add_ball(space):
    mass = 1
    radius = 14
    moment = pymunk.moment_for_circle(mass, 0, radius)
    body = pymunk.Body(mass, moment)
    body.position = (50, 150)
    shape = pymunk.Circle(body, radius)
    space.add(body, shape)
    return shape


def add_floor(space):
    body = pymunk.Body(body_type = pymunk.Body.STATIC)
    body.position = (0, 0)
    target = pymunk.Segment(body, (0, 5), (600, 5), 5)
    space.add(target)
    return target


def add_target(space):
    body = pymunk.Body(body_type = pymunk.Body.STATIC)
    body.position = (700, 300)
    target = pymunk.Segment(body, (-150, 0), (-150, 50), 5)
    space.add(target)
    return target

def do_one_throw(impulse):
    space = pymunk.Space()
    space.gravity = (0.0, -900.0)

    ball_shape = add_ball(space)
    add_floor(space)
    target_shape = add_target(space)

    ball_shape.body.apply_impulse_at_local_point(impulse)

    min_distance_to_target = 1000000
    steps = 1000
    for _ in range(steps):
        space.step(1/50.0)
        distance_to_target = target_shape.body.position.get_distance(ball_shape.body.position)
        if distance_to_target < min_distance_to_target:
            min_distance_to_target = distance_to_target
    return min_distance_to_target

一旦具备这些基本知识,就可以添加更多精美功能

  • 例如,您可以简单地通过使用打印来打印出模拟中发生的事情来轻松开始。
  • 您在空间上设置的重力是重力矢量。请注意,pymunk是独立于单元的,因此只要您传递的所有内容都是一致的,它就可以正确执行:http://www.pymunk.org/en/latest/overview.html#mass-weight-and-units
  • 您可以在上面优化我的快速而又肮脏的代码,例如,通过一些更聪明的逻辑来决定何时结束仿真,因此,如果球已经过去而没有机会回来,则无需运行所有1000步。
  • 您可以添加pygame绘图代码,看起来您已经在这里取得了长足的进步
  • 改进了到目标的距离的度量,现在我通过测量物体之间的距离来获得最简单的解决方案,但是您可能想要形状之间的距离,因此,如果形状发生碰撞,则距离为0。