铰接关节导致永久运动

0 投票
1 回答
15 浏览
提问于 2025-04-14 16:16

我正在尝试用pymunk和pygame模拟一个链条。为此,我有三个对象:ChainChainLinkChainEstremity。它们分别是:一个装所有链环的容器,一个像胶囊形状的物体,由两个pymunk的Circle对象组成,还有一个静态的盒子,用来固定链条的起始或结束部分。

ChainLink有4个约束,3个PinJoint用来保持它们的形状不变(记住它们由两个形状组成),还有1个RotaryLimitJoint用来防止旋转超过90度。多个链环可以通过link_to函数连接在一起,这个函数会添加一个SlideJoint。最后,一个链环和一个链条的末端通过PinJoint连接在一起。我的代码可以在github上找到 这里

我遇到的问题是链条一直在随机抖动,时间久了也不会停止,这让模拟看起来不真实。我尝试调整物体的质量,并给物体的角速度添加手动阻尼,但这些措施都没有任何效果。

这是链条的样子: 链条

下面是我如何初始化这些类和link_to函数的:

class ChainEstremity:
    def __init__(self, center):
        half_side = ChainEstremity.half_side
        self.body = pymunk.Body(body_type=pymunk.Body.STATIC)
        self.shape = pymunk.Poly(self.body,
                                 [(-half_side,-half_side), (half_side,-half_side), (half_side,half_side), (-half_side, half_side)]
                                 )
        self.shape.mass = ChainEstremity.mass
        self.body.position = center
        space.add(self.body, self.shape)



    
class Chain:
    def __init__(self, point_a, point_b, chain_links):
        Chain.estremities.append(ChainEstremity(point_a))
        Chain.estremities.append(ChainEstremity(point_b))

        estremities_dist = Chain.estremities[0].body.position.get_distance(Chain.estremities[1].body.position)
        links_length = estremities_dist // chain_links
        first_link = ChainLink(links_length)
        Chain.all_links.append(first_link)
        first_link.setup(Chain.estremities[0].body.position)
        first_link_constraint = pymunk.constraints.PinJoint(Chain.estremities[0].body, first_link.shape1.body)
        first_link_constraint.collide_bodies = False
        space.add(first_link_constraint)
        
        for i in range(1, chain_links):
            new_link = ChainLink(links_length)
            Chain.all_links.append(new_link)
            new_link.setup(Chain.estremities[0].body.position + Vec2d(links_length * i, 0))
            new_link.link_to(Chain.all_links[i-1])
            
            if i == chain_links - 1:
                last_link_costraint = pymunk.constraints.PinJoint(Chain.estremities[1].body, new_link.shape2.body)
                last_link_costraint.collide_bodies = False
                space.add(last_link_costraint)



class ChainLink:
    def __init__(self, length):
        self.length = length
        self.shape1 = pymunk.Circle(pymunk.Body(), ChainLink.radius)
        self.shape2 = pymunk.Circle(pymunk.Body(), ChainLink.radius)
        self.shape1.mass = ChainLink.mass
        self.shape2.mass = ChainLink.mass
        self.rotary_limit = pymunk.constraints.RotaryLimitJoint(self.shape1.body, self.shape2.body, 0, 0)
        space.add(self.shape1, self.shape1.body, self.shape2, self.shape2.body, self.rotary_limit)


    def link_to(self, other):
        #NOTE: in the chain this object links to the previous one added
        slide_constraint = pymunk.constraints.SlideJoint(self.shape1.body, other.shape2.body,
                                                 Vec2d(0, 0), Vec2d(-ChainLink.radius, 0),
                                                 other.get_full_length() // 2, (other.get_full_length() + ChainLink.radius) // 2)
        rotary_constraint = pymunk.constraints.RotaryLimitJoint(self.shape1.body, other.shape2.body, -math.pi // 2, math.pi // 2)
        slide_constraint.collide_bodies = False
        rotary_constraint.collide_bodies = False
        space.add(slide_constraint, rotary_constraint)

1 个回答

0

我有几个建议可以试试:

  1. ChainLink 做成一个整体。你可以通过把两个圆形的形状连接到同一个物体上,并稍微错开位置来实现。这样一来,你的设置会简单很多,因为就不需要用约束来把它们固定在一起了。

  2. 你可以尝试调整约束中的 max_bias 和/或 max_force 的不同数值。

  3. 你可以试着把 space.damping 设置为稍微低于1的数值。

撰写回答