gpt4 book ai didi

python - Theo Jansen 行走机构的进化算法

转载 作者:IT老高 更新时间:2023-10-28 20:55:05 27 4
gpt4 key购买 nike

有一位荷兰艺术家/工程师创造了一种非常精细的行走机制。工作原理可以看这里:

http://www.strandbeest.com/beests_leg.php

奇怪的是,他使用了自制的进化算法来计算理想的链接长度,页面底部有描述。

我创建了一个 Python 脚本来直观地分析循环的接地部分,它必须满足两个先决条件:

  1. 尽量笔直,以免上下晃动;
  2. 保持速度尽可能恒定,以免一只脚拖到另一只脚上;

这两个标准会产生“轮状”效果,机器直线前进而不会浪费动能。

问题是:

“你有什么建议可以用简单的进化迭代公式来优化腿长(通过在下面的代码中插入正确的突变),从而在上述两个标准的情况下改善步行路径吗?”

编辑:关于基因组候选者的“拟合规则”的一些​​建议:

  • 考虑循环的“下半部分”(接地),因为它对应于曲柄转数的三分之一(注意下半部分可能具有非水平斜率,但仍然是线性的);
  • 对这个“接地”部分的点位置应用线性回归;
  • 根据线性回归计算垂直变化(最小二乘?)
  • 通过与回归线平行的一点与前一点之间的差异计算速度变化;
  • (可选)绘制这些“误差函数”的图表,可能允许直观地选择突变体(嘘……;o)。

这是我在 Python + GTK 中的代码,可以直观地了解问题:(编辑:现在参数化的魔数(Magic Number)会被 mut 的值改变)

# coding: utf-8

import pygtk
pygtk.require('2.0')
import gtk, cairo
from math import *

class Mechanism():
def __init__(s):
pass

def assemble(s, angle):

# magic numbers (unmutated)
mu = [38, 7.8, 15, 50, 41.5, 39.3, 61.9, 55.8, 40.1, 39.4, 36.7, 65.7, 49]

# mutations
mut = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

# mutated
mn = [mu[n]+mut[n] for n in range(13)]

s.A = Point(0,0)
s.B = Point(-mn[0], -mn[1])

s.C = fromPoint(s.A, mn[2], angle)
s.ac = Line(s.A, s.C)

s.D = linkage(s.C, mn[3], s.B, mn[4])
s.cd = Line(s.C, s.D)
s.bd = Line(s.B, s.D)

s.E = linkage(s.B, mn[5], s.C, mn[6])
s.be = Line(s.B, s.E)
s.ce = Line(s.C, s.E)

s.F = linkage(s.D, mn[7], s.B, mn[8])
s.df = Line(s.D, s.F)
s.bf = Line(s.B, s.F)

s.G = linkage(s.F, mn[9], s.E, mn[10])
s.fg = Line(s.F, s.G)
s.eg = Line(s.E, s.G)

s.H = linkage(s.G, mn[11], s.E, mn[12])
s.gh = Line(s.G, s.H)
s.EH = Line(s.E, s.H)


return s.H


class Point:
def __init__(self, x, y):
self.x, self.y = float(x), float(y)
def __str__(self):
return "(%.2f, %.2f)" % (self.x, self.y)

class Line:
def __init__(self, p1, p2):
self.p1, self.p2 = p1, p2
def length(self):
return sqrt((p1.x-p2.x)**2 + (p1.y-p2.y)**2)

def fromPoint(point, distance, angle):
angle = radians(angle)
return Point(point.x + distance * cos(angle),
point.y + distance * sin(angle))

def distance(p1, p2):
return sqrt( (p1.x - p2.x)**2 + (p1.y - p2.y)**2 )

def ccw(p1, p2, px):
""" Test if px is at the right side of the line p1p2 """
ax, ay, bx, by = p1.x, p1.y, p2.x, p2.y
cx, cy = px.x, px.y
return (bx-ax)*(cy-ay)-(by-ay)*(cx-ax) < 0

def linkage(p1, l1, p2, l2):
l1 = float(l1)
l2 = float(l2)
dx,dy = p2.x-p1.x, p2.y-p1.y
d = sqrt(dx**2 + dy**2) # distance between the centers
a = (l1**2 - l2**2 + d**2) / (2*d) # distance from first center to the radical line
M = Point(p1.x + (dx * a/d), p1.y + (dy * a/d)) # intersection of centerline with radical line
h = sqrt(l1**2 - a**2) # distance from the midline to any of the points
rx,ry = -dy*(h/d), dx*(h/d)
# There are two results, but only one (the correct side of the line) must be chosen
R1 = Point(M.x + rx, M.y + ry)
R2 = Point(M.x - rx, M.y - ry)
test1 = ccw(p1, p2, R1)
test2 = ccw(p1, p2, R2)
if test1:
return R1
else:
return R2




###############################33

mec = Mechanism()
stepcurve = [mec.assemble(p) for p in xrange(360)]

window=gtk.Window()
panel = gtk.VBox()
window.add(panel)
toppanel = gtk.HBox()
panel.pack_start(toppanel)

class Canvas(gtk.DrawingArea):
def __init__(self):
gtk.DrawingArea.__init__(self)
self.connect("expose_event", self.expose)

def expose(self, widget, event):
cr = widget.window.cairo_create()
rect = self.get_allocation()
w = rect.width
h = rect.height
cr.translate(w*0.85, h*0.3)
scale = 1
cr.scale(scale, -scale)
cr.set_line_width(1)

def paintpoint(p):
cr.arc(p.x, p.y, 1.2, 0, 2*pi)
cr.set_source_rgb(1,1,1)
cr.fill_preserve()
cr.set_source_rgb(0,0,0)
cr.stroke()

def paintline(l):
cr.move_to(l.p1.x, l.p1.y)
cr.line_to(l.p2.x, l.p2.y)
cr.stroke()

for i in mec.__dict__:
if mec.__dict__[i].__class__.__name__ == 'Line':
paintline(mec.__dict__[i])

for i in mec.__dict__:
if mec.__dict__[i].__class__.__name__ == 'Point':
paintpoint(mec.__dict__[i])

cr.move_to(stepcurve[0].x, stepcurve[0].y)
for p in stepcurve[1:]:
cr.line_to(p.x, p.y)
cr.close_path()
cr.set_source_rgb(1,0,0)
cr.set_line_join(cairo.LINE_JOIN_ROUND)
cr.stroke()

class FootPath(gtk.DrawingArea):
def __init__(self):
gtk.DrawingArea.__init__(self)
self.connect("expose_event", self.expose)

def expose(self, widget, event):
cr = widget.window.cairo_create()
rect = self.get_allocation()
w = rect.width
h = rect.height

cr.save()
cr.translate(w/2, h/2)

scale = 20
cr.scale(scale, -scale)

cr.translate(40,92)

twocurves = stepcurve.extend(stepcurve)

cstart = 305
cr.set_source_rgb(0,0.5,0)
for p in stepcurve[cstart:cstart+121]:
cr.arc(p.x, p.y, 0.1, 0, 2*pi)
cr.fill()

cr.move_to(stepcurve[cstart].x, stepcurve[cstart].y)
for p in stepcurve[cstart+1:cstart+121]:
cr.line_to(p.x, p.y)
cr.set_line_join(cairo.LINE_JOIN_ROUND)
cr.restore()
cr.set_source_rgb(1,0,0)
cr.set_line_width(1)
cr.stroke()




cr.save()
cr.translate(w/2, h/2)
scale = 20
cr.scale(scale, -scale)
cr.translate(40,92)

cr.move_to(stepcurve[cstart+120].x, stepcurve[cstart+120].y)
for p in stepcurve[cstart+120+1:cstart+360+1]:
cr.line_to(p.x, p.y)
cr.restore()
cr.set_source_rgb(0,0,1)
cr.set_line_width(1)
cr.stroke()



canvas = Canvas()
canvas.set_size_request(140,150)
toppanel.pack_start(canvas, False, False)

toppanel.pack_start(gtk.VSeparator(), False, False)

footpath = FootPath()
footpath.set_size_request(1000,-1)
toppanel.pack_start(footpath, True, True)


def changeangle(par):
mec.assemble(par.get_value()-60)
canvas.queue_draw()
angleadjust = gtk.Adjustment(value=0, lower=0, upper=360, step_incr=1)
angleScale = gtk.HScale(adjustment=angleadjust)
angleScale.set_value_pos(gtk.POS_LEFT)
angleScale.connect("value-changed", changeangle)
panel.pack_start(angleScale, False, False)


window.set_position(gtk.WIN_POS_CENTER)
window.show_all()
gtk.main()

最佳答案

Try the demo!

enter image description here

这是一个有趣的问题,虽然我认为有点超出了 Stack Overflow 的范围:这不是几分钟内就能解决的问题,所以我会在这里贴一个大纲,如果我有任何进展,我会更新它。任何方法都将分为三个部分:

  1. 对足迹进行评分:链接是否中断?脚印的形状是否正确?它有多平坦?运动有多顺畅?它在平坦的部分花费了足够的时间吗?

  2. 寻找神奇数字的好值。目前尚不清楚这是否必须是一种进化算法(尽管我可以理解为什么这种算法的想法会吸引 Theo Jansen,因为它符合他艺术中的动物隐喻);也许其他方法,如局部搜索(爬山)或模拟退火会很有成效。

  3. 寻找良好的 ARM 配置。这就是进化方法似乎最值得的地方。

您可以在我的 Javascript/canvas 演示中尝试不同的魔数(Magic Number),看看您可以获得什么样的运动(例如,CD = 55.4 非常有趣)。有一个完整的mathematical theory of linkages ,顺便说一下,它将链接的配置空间连接到拓扑流形。


我在演示中添加了一些简单的评分。 ground score 是脚在地面上所花费的周期的分数,我认为它是 y 坐标在最低点的某个容差范围内的所有点。 阻力分数是脚着地时任意两个水平速度之间的最大差异。 (它总是负数,因此更高的值 = 速度的小差异 = 更好。)

但这就是困难所在。为了对任何类型的搜索进行编程,我需要能够结合这些分数。但是我该如何平衡它们呢? Jansen 魔术数字给了我 groundScore:0.520;拖动分数:-0.285。如果我设置 AC=10, GH=65, EH=50, 我得到 groundScore: 0.688;拖动分数:-0.661。近 70% 的时间是脚着地。但是起飞很拖沓。比詹森的好还是差?

我认为获得实际工程反馈以确定好分数将是这里的大问题,而不是实际搜索。

关于python - Theo Jansen 行走机构的进化算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6573415/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com