|
| 1 | +#!/usr/bin/env python3 |
| 2 | +# encoding:utf-8 |
| 3 | +import sys |
| 4 | +sys.path.append('/root/thuei-1/sdk-python/') |
| 5 | +import time |
| 6 | +import numpy as np |
| 7 | +from math import sqrt |
| 8 | +import matplotlib.pyplot as plt |
| 9 | +from ArmIK.InverseKinematics import * |
| 10 | +from ArmIK.Transform import getAngle |
| 11 | +from mpl_toolkits.mplot3d import Axes3D |
| 12 | +from HiwonderSDK.Board import setBusServoPulse,getBusServoPulse, setPWMServoPulse, getPWMServoPulse |
| 13 | + |
| 14 | +#机械臂根据逆运动学算出的角度进行移动 |
| 15 | +ik = IK('arm') |
| 16 | +#设置连杆长度 |
| 17 | +l1 = ik.l1 |
| 18 | +l4 = ik.l4 |
| 19 | +ik.setLinkLength(L1=l1+1.3, L4=l4) |
| 20 | + |
| 21 | +class ArmIK: |
| 22 | + servo3Range = (500, 2500.0, 0, 180.0) #脉宽, 角度 |
| 23 | + servo4Range = (500, 2500.0, 0, 180.0) |
| 24 | + servo5Range = (500, 2500.0, 0, 180.0) |
| 25 | + servo6Range = (500, 2500.0, 0, 180.0) |
| 26 | + |
| 27 | + def __init__(self): |
| 28 | + self.setServoRange() |
| 29 | + |
| 30 | + def setServoRange(self, servo3_Range=servo3Range, servo4_Range=servo4Range, servo5_Range=servo5Range, servo6_Range=servo6Range): |
| 31 | + # 适配不同的舵机 |
| 32 | + self.servo3Range = servo3_Range |
| 33 | + self.servo4Range = servo4_Range |
| 34 | + self.servo5Range = servo5_Range |
| 35 | + self.servo6Range = servo6_Range |
| 36 | + self.servo3Param = (self.servo3Range[1] - self.servo3Range[0]) / (self.servo3Range[3] - self.servo3Range[2]) |
| 37 | + self.servo4Param = (self.servo4Range[1] - self.servo4Range[0]) / (self.servo4Range[3] - self.servo4Range[2]) |
| 38 | + self.servo5Param = (self.servo5Range[1] - self.servo5Range[0]) / (self.servo5Range[3] - self.servo5Range[2]) |
| 39 | + self.servo6Param = (self.servo6Range[1] - self.servo6Range[0]) / (self.servo6Range[3] - self.servo6Range[2]) |
| 40 | + |
| 41 | + def transformAngelAdaptArm(self, theta3, theta4, theta5, theta6): |
| 42 | + #将逆运动学算出的角度转换为舵机对应的脉宽值 |
| 43 | + servo3 = int(round(theta3 * self.servo3Param + (self.servo3Range[1] + self.servo3Range[0])/2)) |
| 44 | + if servo3 > self.servo3Range[1] or servo3 < self.servo3Range[0]: |
| 45 | + logger.info('servo3(%s)超出范围(%s, %s)', servo3, self.servo3Range[0], self.servo3Range[1]) |
| 46 | + return False |
| 47 | + |
| 48 | + servo4 = int(round(theta4 * self.servo4Param + (self.servo4Range[1] + self.servo4Range[0])/2)) |
| 49 | + if servo4 > self.servo4Range[1] or servo4 < self.servo4Range[0]: |
| 50 | + logger.info('servo4(%s)超出范围(%s, %s)', servo4, self.servo4Range[0], self.servo4Range[1]) |
| 51 | + return False |
| 52 | + |
| 53 | + servo5 = int(round((self.servo5Range[1] + self.servo5Range[0])/2 + (90.0 - theta5) * self.servo5Param)) |
| 54 | + if servo5 > ((self.servo5Range[1] + self.servo5Range[0])/2 + 90*self.servo5Param) or servo5 < ((self.servo5Range[1] + self.servo5Range[0])/2 - 90*self.servo5Param): |
| 55 | + logger.info('servo5(%s)超出范围(%s, %s)', servo5, self.servo5Range[0], self.servo5Range[1]) |
| 56 | + return False |
| 57 | + |
| 58 | + if theta6 < -(self.servo6Range[3] - self.servo6Range[2])/2: |
| 59 | + servo6 = int(round(((self.servo6Range[3] - self.servo6Range[2])/2 + (90 + (180 + theta6))) * self.servo6Param)) |
| 60 | + else: |
| 61 | + servo6 = int(round(((self.servo6Range[3] - self.servo6Range[2])/2 - (90 - theta6)) * self.servo6Param)) + self.servo6Range[0] |
| 62 | + if servo6 > self.servo6Range[1] or servo6 < self.servo6Range[0]: |
| 63 | + logger.info('servo6(%s)超出范围(%s, %s)', servo6, self.servo6Range[0], self.servo6Range[1]) |
| 64 | + return False |
| 65 | + return {"servo3": servo3, "servo4": servo4, "servo5": servo5, "servo6": servo6} |
| 66 | + |
| 67 | + def servosMove(self, servos, movetime=None): |
| 68 | + #驱动3,4,5,6号舵机转动 |
| 69 | + time.sleep(0.02) |
| 70 | + if movetime is None: |
| 71 | + max_d = 0 |
| 72 | + for i in range(0, 4): |
| 73 | + d = abs(getPWMServoPulse(i + 3) - servos[i]) |
| 74 | + if d > max_d: |
| 75 | + max_d = d |
| 76 | + movetime = int(max_d*1) |
| 77 | + setPWMServoPulse(3, servos[0], movetime) |
| 78 | + setPWMServoPulse(4, servos[1], movetime) |
| 79 | + setPWMServoPulse(5, servos[2], movetime) |
| 80 | + setPWMServoPulse(6, servos[3], movetime) |
| 81 | + |
| 82 | +# setPWMServosPulse(movetime, 4, 3,servos[0], 4,servos[1], 5,servos[2], 6,servos[3]) |
| 83 | + |
| 84 | + return movetime |
| 85 | + |
| 86 | + def setPitchRange(self, coordinate_data, alpha1, alpha2, da = 1): |
| 87 | + #给定坐标coordinate_data和俯仰角的范围alpha1,alpha2, 自动在范围内寻找到的合适的解 |
| 88 | + #如果无解返回False,否则返回对应舵机角度,俯仰角 |
| 89 | + #坐标单位cm, 以元组形式传入,例如(0, 5, 10) |
| 90 | + #da为俯仰角遍历时每次增加的角度 |
| 91 | + x, y, z = coordinate_data |
| 92 | + if alpha1 >= alpha2: |
| 93 | + da = -da |
| 94 | + for alpha in np.arange(alpha1, alpha2, da):#遍历求解 |
| 95 | + result = ik.getRotationAngle((x, y, z), alpha) |
| 96 | + if result: |
| 97 | + theta3, theta4, theta5, theta6 = result['theta3'], result['theta4'], result['theta5'], result['theta6'] |
| 98 | + servos = self.transformAngelAdaptArm(theta3, theta4, theta5, theta6) |
| 99 | + if servos != False: |
| 100 | + return servos, alpha |
| 101 | + |
| 102 | + return False |
| 103 | + |
| 104 | + def setPitchRangeMoving(self, coordinate_data, alpha, alpha1, alpha2, movetime = None): |
| 105 | + #给定坐标coordinate_data和俯仰角alpha,以及俯仰角范围的范围alpha1, alpha2,自动寻找最接近给定俯仰角的解,并转到目标位置 |
| 106 | + #如果无解返回False,否则返回舵机角度、俯仰角、运行时间 |
| 107 | + #坐标单位cm, 以元组形式传入,例如(0, 5, 10) |
| 108 | + #alpha为给定俯仰角 |
| 109 | + #alpha1和alpha2为俯仰角的取值范围 |
| 110 | + #movetime为舵机转动时间,单位ms, 如果不给出时间,则自动计算 |
| 111 | + x, y, z = coordinate_data |
| 112 | + result1 = self.setPitchRange((x, y, z), alpha, alpha1) |
| 113 | + result2 = self.setPitchRange((x, y, z), alpha, alpha2) |
| 114 | + if result1 != False: |
| 115 | + data = result1 |
| 116 | + if result2 != False: |
| 117 | + if abs(result2[1] - alpha) < abs(result1[1] - alpha): |
| 118 | + data = result2 |
| 119 | + else: |
| 120 | + if result2 != False: |
| 121 | + data = result2 |
| 122 | + else: |
| 123 | + return False |
| 124 | + servos, alpha = data[0], data[1] |
| 125 | + movetime = self.servosMove((servos["servo3"], servos["servo4"], servos["servo5"], servos["servo6"]), movetime) |
| 126 | + return servos, alpha, movetime |
| 127 | + |
| 128 | +if __name__ == "__main__": |
| 129 | + AK = ArmIK() |
| 130 | + #setPWMServoPulse(1, 1450, 1500) |
| 131 | + #AK.setPitchRangeMoving((-5,0,2), -90,-90, 90, 1200) |
| 132 | +# print(ik.getLinkLength()) |
| 133 | + print(AK.setPitchRangeMoving((0,6,18),0,-90, 90)) |
| 134 | + time.sleep(2) |
| 135 | + #print(AK.setPitchRangeMoving((-4.8, 15, 1.5), 0, -90, 0, 2000)) |
| 136 | + #AK.drawMoveRange2D(-10, 10, 0.2, 10, 30, 0.2, 2.5, -90, 90, 1) |
0 commit comments