diff python/robot.py @ 0:cf2cd5a35d24 draft

Initial commit
author Radomir Dopieralski <sheep-devel@sheep.art.pl>
date Mon, 15 May 2017 16:36:08 +0200
parents
children 8ed8f30b0568
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/robot.py	Mon May 15 16:36:08 2017 +0200
@@ -0,0 +1,97 @@
+# -*- coding: utf-8 -*-
+
+import math
+
+from servos import Servos
+from machine import I2C, Pin
+
+
+PI2 = math.pi / 2
+PI4 = math.pi / 4
+SQRT2 = math.sqrt(2)
+
+
+def _solve_triangle(a, b, c):
+    a, b, c = abs(a), abs(b), abs(c)
+    if a + b < c or a + c < b or b + c < a:
+        raise ValueError("Impossible triangle: %r, %r, %r" % (a, b, c))
+    cos = float(a ** 2 + b ** 2 - c ** 2) / (2 * a * b)
+    return math.acos(cos)
+
+
+def _norm(a, b):
+    return math.sqrt(a ** 2 + b ** 2)
+
+
+class Leg:
+    # Lengths of leg segments, in mm
+    coxa =  36    # between the hip and the knee
+    femur = 39    # between the knee and the ankle
+    tibia = 55    # between the ankle and the foot
+    base =  21    # from the center of body
+
+    def __init__(self, joints, direction, servos):
+        self.servos = servos
+        self.joints = joints
+        self.x_dir, self.y_dir = direction
+        self.home = (self.coxa + self.femur) / math.sqrt(2)
+        self.x = 0
+        self.y = 0
+        self.z = 0
+
+    def move_to(self, x, y, z):
+        print("Moving leg %d, %d to %d, %d, %d" % (self.x_dir, self.y_dir,
+            x, y, z))
+        x += self.home
+        y += self.home
+        z -= self.tibia
+        f = _norm(x, y) - self.coxa
+        d = _norm(f, z)
+        if d > self.femur + self.tibia:
+            raise ValueError("Out of reach")
+        hip = PI4 - math.atan2(y, x)
+        knee = _solve_triangle(self.femur, d, self.tibia) - math.atan2(-z, f)
+        ankle = PI2 - _solve_triangle(self.femur, self.tibia, d)
+        for joint, angle in zip(self.joints, (hip, knee, ankle)):
+            self.servos.position(
+                joint,
+                radians=PI2 - angle * self.x_dir * self.y_dir
+            )
+        self.x = x - self.home
+        self.y = y - self.home
+        self.z = z + self.tibia
+
+    def move_by(self, dx=0, dy=0, dz=0):
+        self.move_to(self.x + dx, self.y + dy, self.z + dz)
+
+    def rotate_by(self, radians):
+        x = self.x + self.base
+        y = self.y + self.base
+        nx = x * math.cos(radians) - y * math.sin(radians) - self.base
+        ny = x * math.sin(radians) + y * math.cos(radians) - self.base
+        self.move_to(nx, ny, self.z)
+
+
+class Robot:
+    def __init__(self):
+        i2c = I2C(-1, Pin(5, Pin.OUT, Pin.PULL_UP),
+                  Pin(4, Pin.OUT, Pin.PULL_UP), freq=100000)
+        self.servos = Servos(i2c)
+        self.legs = (
+            Leg((0, 1, 2), (1,  -1), self.servos),
+            Leg((7, 6, 5), (-1,  -1), self.servos),
+            Leg((8, 9, 10), (-1,  1), self.servos),
+            Leg((15, 14, 13), (1,  1), self.servos),
+        )
+
+    def move_by(self, dx=0, dy=0, dz=0):
+        for leg in self.legs:
+            leg.move_by(dx * leg.x_dir, dy * leg.y_dir, dz)
+
+    def rotate_by(self, radians):
+        for leg in self.legs:
+            leg.rotate_by(radians * leg.x_dir * leg.y_dir)
+
+    def home(self):
+        for leg in self.legs:
+            leg.move_to(0, 0, 0)