from math import cos, sin, pi, atan2, tan, dist, radians class Robot: # position pos=(0.1,1) # orientation rot=pi/2 # velocite v=0 # velocite angulaire angv=0 # velocite des roues (non angulaire) wv=[0,0] # velocite max wmv=0.3 # espace entre les deux roues l=0.1 # time t = 0 # pins level pins = [0]*32 # acceleration maximal avant de perdre l'adhérance maxRotAccel = 10 # pins reliés au moteurs (bw_l, fw_l, bw_r, fw_r) motors_pins = ((9,10),(12,11)) # position du spot lumineux light_pos = (9, 1.5) # ecart entre les deux photores photores_l = 0.07 # longeur du séparateur entre les photorésistances photores_sep_l = 0.6 # constantes de résistance des photoresistances PHOTORES_LIGHT = 100 PHOTORES_SHADOW = 20000 PHOTORES_BRIDGE = 1000 pr_l_pin = 20 # A0 voir adapter_ard.h pr_r_pin = 21 # A1 # rayon de mesure des capteurs ultrason ultr_sense_max = 4 ultr_sense_rays = (pi/2, -pi/2) ultr_sense_scatter = radians(6) # TODO: check dists = [None] * len(ultr_sense_rays) tr = [0]*len(ultr_sense_rays) ci = [0]*len(tr) def __init__(self, laby): self.laby = laby self.pr_max_ang = tan((self.photores_l/2)/self.photores_sep_l) self.t = 0 self.dt = -1 self.angle2spot = 0 def update(self): if(self.dt == -1): return self.update_ultr_sense() self.compute_light() print("***********", self.t, "****", self.dt) # https://robotics.stackexchange.com/questions/106/what-is-a-suitable-model-for-two-wheeled-robots self.v = 1/2*(self.wv[0]+self.wv[1]) self.angv = 1/self.l*(self.wv[1]-self.wv[0]) self.rot += self.angv*self.dt self.pos = (self.pos[0]+self.v*sin(self.rot)*self.dt,self.pos[1]+self.v*cos(self.rot)*self.dt) def compute_light(self): a2s = atan2(self.light_pos[1]-self.pos[1],self.light_pos[0]-self.pos[0]) self.angle2spot = pi/2-a2s-self.rot%(2*pi) if abs(self.angle2spot) > pi/2: self.pr_l = self.PHOTORES_SHADOW self.pr_r = self.PHOTORES_SHADOW elif abs(self.angle2spot) < self.pr_max_ang: self.pr_l = self.PHOTORES_LIGHT self.pr_r = self.PHOTORES_LIGHT else: if self.angle2spot > 0: self.pr_l = self.PHOTORES_LIGHT self.pr_r = self.PHOTORES_SHADOW else: self.pr_l = self.PHOTORES_SHADOW self.pr_r = self.PHOTORES_LIGHT self.pins[self.pr_l_pin] = int(1024 * self.pr_l/(self.pr_l+self.PHOTORES_BRIDGE)) self.pins[self.pr_r_pin] = int(1024 * self.pr_r/(self.pr_r+self.PHOTORES_BRIDGE)) def analogWrite(self, pin, dc): print(f">> set pin {pin} to {dc}") speedDelta = (self.pins[pin] - dc) / self.dt #assert(speedDelta < self.maxRotAccel) self.pins[pin] = dc for ind, mp in enumerate(self.motors_pins): assert(bool(mp[0] > 0) ^ bool(mp[1] > 0), "deux pins moteur allumés en même temps") self.wv[ind] = (-self.pins[mp[0]]+self.pins[mp[1]])/255*self.wmv def digitalWrite(self, pin, level): self.analogWrite(pin, level*255) def setTime(self, t): self.dt = (t/1000000 - self.t) self.t = t/1000000 assert(self.dt < 0.1) def update_ultr_sense(self): for ind,r in enumerate(self.ultr_sense_rays): #tr = (self.pos[0]+self.ultr_sense_max*sin(r+self.rot), self.pos[1]+self.ultr_sense_max*cos(r+self.rot)) #self.tr[ind] = tr self.ci[ind] = self.laby.get_closest_wall_dist(self.pos, r+self.rot, self.ultr_sense_max, self.ultr_sense_scatter) #self.ci[ind] = self.laby.get_closest_wall_dist((self.pos, tr)) if self.ci[ind]: self.dists[ind] = dist(self.pos, self.ci[ind]) else: self.dists[ind] = None