Package joy ::
Module mxr
|
|
1
2 """
3 Created on Thu Nov 3 17:05:26 2016
4
5 @author: birds
6 """
7 DEBUG = []
8 from time import time as now
9 from ckbot.dynamixel import MX64Module
10 from numpy import nan,exp,angle,abs,clip,pi,isnan,sign
11 from plans import Plan
12 from loggit import progress
13
14
16 - def __init__(self, servo, logger=None, **kw):
17 assert isinstance(servo, MX64Module), "only works with MX"
18 self.servo = servo
19 self.aScl = 36000.0
20 self.rpmScl = 1 / 64.0
21 self.posOfs = 0
22 self.ori = 1
23 self.desAng = 0
24 self.desRPM = 00
25
26 self.deadRPM = 10
27 self.deadZone = 0.10
28 self.punch = 2.0
29 self.Kp = 10
30 self.logger = logger
31 self._clearV()
32 self._v = nan
33 self.__dict__.update(kw)
34 self._ensure_motor = self._set_motor
35 self._ensure_servo = self._set_servo
36
38 """
39 Convert cycle angle (range 0..1) to servo position
40
41 Angle 0 is mapped to .posOfs, growing in direction .ori
42 """
43 return int((((float(ang)-self.posOfs)*self.ori) % 1.0) * self.aScl)
44
46 """
47 Convert cycle angle (range 0..1) to servo position
48
49 Angle 0 is mapped to .posOfs, growing in direction .ori
50 """
51 return float(srv)/self.aScl/self.ori + self.posOfs
52
54 """execute an interaction of the controller update loop"""
55 a = exp(1j * self.get_ang()*2*pi)
56 a0 = exp(1j * self.desAng*2*pi)
57 lead = angle(a / a0)
58 if abs(lead)>0.7*pi:
59 pFB = 0
60 pCH = 0
61 rpm = self.deadRPM
62 if "F" in DEBUG:
63 progress("FB lead %5.2g out of range" % (lead))
64
65 else:
66 pCH = (self.punch * sign(lead)) if abs(lead)>self.deadZone else 0
67 pFB = clip(pCH + self.Kp * lead, -45, 45)
68 rpm = self.desRPM - pFB
69 if abs(rpm)<0.1:
70 rpm = 0
71 if "F" in DEBUG:
72 progress("FB desRPM %g p %g c %g" % (self.desRPM, pFB, pCH))
73 if self.logger:
74 self.logger.write( "ctrl", nid=self.servo.node_id,
75 desRPM=str(self.desRPM), pFB=str(pFB), pCH=str(pCH) )
76
77 self._set_rpm(rpm)
78
80 """(private) set module in servo mode
81
82 also configures the _ensure_* callbacks so that _ensure_* only
83 sends command to motor once
84 """
85 self.servo.set_mode(0)
86 if "h" in DEBUG:
87 progress("%s.set_mode('Servo')" % (self.servo.name))
88 if self.servo.get_mode() == 0:
89 self._ensure_servo = lambda: None
90 self._ensure_motor = self._set_motor
91
93 """(private) set module in motor mode
94
95 also configures the _ensure_* callbacks so that _ensure_* only
96 sends command to motor once
97 """
98 self.servo.set_mode(1)
99 if "h" in DEBUG:
100 progress("%s.set_mode('Motor')" % (self.servo.name))
101 if self.servo.get_mode() == 1:
102 self._ensure_motor = lambda: None
103 self._ensure_servo = self._set_servo
104
106 self.desAng = float(ang) %1.0
107 if "s" in DEBUG:
108 progress("%s.set_angle(%g)" % (self.servo.name, ang))
109 if self.logger:
110 self.logger.write( "set_ang", nid=self.servo.node_id, ang=str(ang) )
111
113 ang = self._srv2ang(self.servo.get_pos())
114 if "g" in DEBUG:
115 progress("%s.get_angle --> %g" % (self.servo.name, ang))
116 if self.logger:
117 self.logger.write( "get_ang", nid=self.servo.node_id, ang=str(ang) )
118 self._updateV(ang)
119 return ang
120
122 """
123 Get a velocity estimate
124 """
125 return self._v
126
128 """Clear state of velocity estimator"""
129 self._lastA = None
130 self._lastT = None
131
133 """
134 Push angle measurement into velocity estimator
135 """
136 t = now()
137 if self._lastA is not None:
138 da = ang - self._lastA
139 dt = t - self._lastT
140 vNew = da / dt * 60.0
141
142 if isnan(self._v):
143 self._v = vNew
144 else:
145 a = 0.2
146 self._v = self._v * (1 - a) + vNew * a
147 self._lastA = ang
148 self._lastT = t
149
151 """Push an RPM setting to the motor"""
152 self._ensure_motor()
153 tq = clip(self.rpmScl * self.ori * rpm, -0.999, 0.999)
154 if "r" in DEBUG:
155 progress("%s.set_torque(%g) <-- rpm %g" % (self.servo.name, tq, rpm))
156 self.servo.set_torque(tq)
157
158 if __name__=="__main__":
159 import ckbot.logical as L
160 from time import sleep
161 T0 = now()
163 print "%5.3g " % (now()-T0),msg,
164 if not sameLine:
165 print
166 c = L.Cluster(count=1)
167 m = c.values()[0]
168 w = ServoWrapperMX(m,ori=-1,posOfs=0.5)
169 try:
170 from pylab import linspace
171 a = linspace(-2,2,103)
172 b = [ w._srv2ang(w._ang2srv(ai)) for ai in a ]
173 assert abs((a-b+.2)%1.0-.2).max() < 0.01
174 except ImportError:
175 print "WARNING: No pylab for error estimate test"
176 DEBUG[:] = ['h','F','r','s']
177 last = now()
178 while 1:
179 w.doCtrl()
180 if now()-last>1:
181 goal = 0.3 * (long(now()) % 2)
182 w.set_ang( goal )
183 last = now()
184 progress("goal %g" % goal)
185 sleep(0.3)
186