如何设置 pymunk SimpleMotor 的旋转速率以达到特定角度?

问题描述

我正在尝试创建一个函数(用于深度学习),在该函数中,我可以通过发送具有角度差的特定列表来控制机器人的角度值,然后电机应旋转直到达到该角度。当我使用键盘控件时,设置 SimpleMotor.rate 在 while 循环内起作用,但是当我尝试在 while 循环外的函数中使用它时它不起作用。任何人都可以请建议吗?代码如下:

    def change_angle(angles):
        chassis_angle = self.chassis_b.angle*180/np.pi
        cur_angles = [self.leftLeg_1b_body.angle*180/np.pi- chassis_angle,self.leftLeg_1a_body.angle*180/np.pi-chassis_angle,self.rightLeg_1a_body.angle*180/np.pi-chassis_angle,self.rightLeg_1b_body.angle*180/np.pi-chassis_angle]
        target_angles = [cur_angles[0]+angles[0],cur_angles[1]+angles[1],cur_angles[2]+angles[2],cur_angles[3]+angles[3]]
        #time = angle/omega
        if target_angles[0]-cur_angles[0]>0:
                self.motor_ba1Left.rate = -2
                print("1")
        else:
                self.motor_ba1Left.rate = 2
                print("2")
        if target_angles[1]-cur_angles[1]>0:
                self.motor_ac1Left.rate = -2
                print("3")
        else:
                self.motor_ac1Left.rate = 2
                print("4")
        if target_angles[2]-cur_angles[2]>0:
                self.motor_ac1Right.rate = 2
                print("5")
        else:
                self.motor_ac1Right.rate = -2
                print("6")
        if target_angles[3]-cur_angles[3]>0:
                self.motor_ba1Right.rate = 2
                print("7")
        else:
                self.motor_ba1Right.rate = -2
                print("8")
        while (target_angles[0]!=cur_angles[0]) or (target_angles[1]!=cur_angles[1]) or (target_angles[2]!=cur_angles[2]) or (target_angles[3]!=cur_angles[3]):
            if target_angles[0]-cur_angles[0]==0:
                self.motor_ba1Left.rate = 0
            if target_angles[1]-cur_angles[1]==0:
                self.motor_ac1Left.rate = 0
            if target_angles[2]-cur_angles[2]==0:
                self.motor_ac1Right.rate = 0
            if target_angles[3]-cur_angles[3]==0:
                self.motor_ba1Right.rate = 0
            cur_angles = [self.leftLeg_1b_body.angle*180/np.pi- chassis_angle,self.rightLeg_1b_body.angle*180/np.pi-chassis_angle]

        self.motor_ba1Left.rate = 0
        self.motor_ac1Right.rate = 0
        self.motor_ac1Left.rate = 0
        self.motor_ba1Right.rate = 0

   

    


    simulate = True
    rotationRate = 1
    while running:
        for event in pygame.event.get():
            if event.type == QUIT or (event.type == KEYDOWN and event.key in (K_q,K_ESCAPE)):
                sys.exit(0)
            elif event.type == KEYDOWN and event.key == K_z:
                # Start/stop simulation.
                simulate = not simulate
            elif event.type == KEYDOWN and event.key == K_r:
                # Reset.
                self.reset_bodies()
            elif event.type == KEYDOWN and event.key == K_h:
                
                self.chassis_b.angular_veLocity = -2
            elif event.type == KEYDOWN and event.key == K_u:
                self.chassis_b.apply_force_at_local_point([0,-1500000])
            elif event.type == KEYDOWN and event.key == K_j:
                self.chassis_b.apply_force_at_local_point([0,1500000])
                
            elif event.type == KEYDOWN and event.key == K_k:
                self.chassis_b.angular_veLocity = 2
            elif event.type == KEYDOWN and event.key == K_w:
                self.motor_ba1Left.rate = -rotationRate
            elif event.type == KEYDOWN and event.key == K_s:
                self.motor_ba1Left.rate = rotationRate
            elif event.type == KEYDOWN and event.key == K_a:
                self.motor_ac1Left.rate = -rotationRate
            elif event.type == KEYDOWN and event.key == K_d:
                self.motor_ac1Left.rate = rotationRate
            elif event.type == KEYDOWN and event.key ==K_UP:
                self.motor_ba1Right.rate = rotationRate
            elif event.type == KEYDOWN and event.key ==K_DOWN:
                self.motor_ba1Right.rate = -rotationRate
            elif event.type == KEYDOWN and event.key ==K_LEFT:
                self.motor_ac1Right.rate = -rotationRate
            elif event.type == KEYDOWN and event.key ==K_RIGHT:
                self.motor_ac1Right.rate = rotationRate
            elif event.type == KEYUP:
                print("keyup")
                self.motor_ba1Left.rate = 0
                self.motor_ac1Left.rate = 0
                self.motor_ba1Right.rate = 0 
                self.motor_ac1Right.rate = 0
                self.chassis_b.angular_veLocity = 0
                #self.chassis_b.veLocity = 0d
        self.draw()
        change_angle([30,40,-30,-40])
        
        ### Update physics
        fps = 50
        iterations = 25
        dt = 1.0/float(fps)/float(iterations)
        if simulate:
            for x in range(iterations): # 10 iterations to get a more stable simulation
                self.space.step(dt)
        #self.rotation()
        self.check_collide()
        #self.arm_collide_check()
        #self.printinfo()
        pygame.display.flip()
        clock.tick(fps)

    if __name__ == '__main__':
sim = Simulator()
sim.main()

解决方法

我不认为 change_angle 中的 while 循环按预期工作。

您从 while running: 循环调用 change_angles 的每一帧。在该函数中,您首先使用 if 语句确定电机的速率。到现在为止还挺好。在此之后,速率将被设置为某个值,但电机尚未旋转任何东西,因为这发生在阶跃函数中:self.space.step(dt) 这是实际向前移动模拟的部分,运行电机,施加重力,解决冲突等

在这部分之后有一个 while 循环,我认为这个想法是确定角度是否已更新为目标角度。然而,这永远不会发生,因为模拟只发生在我上面描述的阶跃函数中。

我认为您可以尝试删除该 while 循环,而是在 change_angle 的开头放置一个大的 if 语句,以检查是否达到目标角度,如果达到,则将电机的速率重置为 0 并返回。 (否则继续现有的 if 语句)。

最后一个提示:角度是浮点数,例如42.234567.... 尝试比较这些数字是否完全相等几乎从来都不是一个好主意,因为由于四舍五入错误,它们可能永远不会变得相等。相反,最好检查差异是否小于某个增量,例如target_angles[0]!=cur_angles[0] 变为 abs(target_angles[0]-cur_angles[0]) < delta,其中 delta 是一个小数(例如 delta=0.01