Пример #1
0
class Lid:
  """ Interface to the Lid."""
  open_pos = 180
  close_pos = 0
  def __init__(self, lid_servo_channel):
    """
        lid_servo_channel: Provide the channel (on the Servo driver) that the
                           lid Servois connected to.
        init_pos: A number between 0 and 180 that specifies the initial angle
    """
    self.lid_servo = Servo(lid_servo_channel, Lid.open_pos)
    self.is_lid_open = True

  def open(self):
    self.lid_servo.move_to(Lid.open_pos)
    self.is_lid_open = True

  def close(self):
    self.lid_servo.move_to(Lid.close_pos)
    self.is_lid_open = False

  def is_open(self):
    return self.is_lid_open

  def shutdown(self):
    self.open()
Пример #2
0
 def __init__(self, lid_servo_channel):
   """
       lid_servo_channel: Provide the channel (on the Servo driver) that the
                          lid Servois connected to.
       init_pos: A number between 0 and 180 that specifies the initial angle
   """
   self.lid_servo = Servo(lid_servo_channel, Lid.open_pos)
   self.is_lid_open = True
Пример #3
0
 def __init__(self, servo_channel, switch_bcm_pin, sampling_interval_s = 5):
   """
       servo_channel: Provide the channel (on the Servo driver) that the lid
                      Servo is connected to.
       init_pos: A number between 0 and 180 that specifies the initial angle
   """
   self.servo = Servo(servo_channel, StoveController.low_pos)
   self.switch_bcm_pin = switch_bcm_pin
   GPIO.setmode(GPIO.BCM)
   GPIO.setup(self.switch_bcm_pin, GPIO.OUT)
   self.off()
   self.temp_sensor = TMP006.TMP006(address=0x41)
   self.temp_sensor.begin()
   self.temp_pid_controller = pid_controller.PIDController(StoveController.kP,
                                                           StoveController.kI,
                                                           StoveController.kD,
                                                           20, # setpoint
                                                           sampling_interval_s,
                                                           self.get_temperature_C,
                                                           self.set_knobpos_from_percentage)
   self.temp_pid_controller.start()
Пример #4
0
 def __init__(self, rail_dir_pin, rail_step_pin, rail_enable_pin,
              base_servo_channel,
              vertical_servo_channel,
              horizontal_servo_channel,
              level_servo_channel,
              tipping_servo_channel,
              grasp_servo_channel):
   self.base_servo = Servo(base_servo_channel)
   self.vertical_servo = Servo(vertical_servo_channel)
   self.horizontal_servo = Servo(horizontal_servo_channel)
   self.level_servo = Servo(level_servo_channel)
   self.tipping_servo = Servo(tipping_servo_channel)
   self.grasp_servo = Servo(grasp_servo_channel)
   self.rail = stepper_axis.StepperAxis(rail_dir_pin, rail_step_pin, rail_enable_pin,
                                        RoboticArm.max_rail_translation_mm,
                                        inc_clockwise=False)
   self.move_to_base()
Пример #5
0
class StoveController:
  """ Interface to the Stove/HotPlate."""
  high_pos = 180
  low_pos = 0
  kP = 0.3 # Set these values appropriately.
  kI = 0.001
  kD = 0.0

  def __init__(self, servo_channel, switch_bcm_pin, sampling_interval_s = 5):
    """
        servo_channel: Provide the channel (on the Servo driver) that the lid
                       Servo is connected to.
        init_pos: A number between 0 and 180 that specifies the initial angle
    """
    self.servo = Servo(servo_channel, StoveController.low_pos)
    self.switch_bcm_pin = switch_bcm_pin
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(self.switch_bcm_pin, GPIO.OUT)
    self.off()
    self.temp_sensor = TMP006.TMP006(address=0x41)
    self.temp_sensor.begin()
    self.temp_pid_controller = pid_controller.PIDController(StoveController.kP,
                                                            StoveController.kI,
                                                            StoveController.kD,
                                                            20, # setpoint
                                                            sampling_interval_s,
                                                            self.get_temperature_C,
                                                            self.set_knobpos_from_percentage)
    self.temp_pid_controller.start()

  def on(self):
    GPIO.output(self.switch_bcm_pin, GPIO.HIGH)
    self.is_on = True

  def off(self):
    GPIO.output(self.switch_bcm_pin, GPIO.LOW)
    self.is_on = False

  # Shutdown for good. Cannot use stove without restarting.
  def shutdown(self):
    self.off()
    self.temp_pid_controller.stop()
    self.temp_pid_controller.join()

  # Hold the stove at the current setting and pause temperature control.
  def hold_freeze(self):
    self.temp_pid_controller.pause()

  def is_on(self):
    return self.is_on

  def set_knobpos_from_percentage(self, percentage):
    if percentage < 0 or percentage > 100:
      raise ValueError("KnobPos is set through percentage. Needs to be in [0, 100]")
    print "Dest %: " + str(percentage)
    target_value = int((float(abs(StoveController.low_pos - StoveController.high_pos)) * percentage)/ 100)
    self.servo.move_to(int(StoveController.low_pos + target_value))

  # Public methods
  def set_temperature_C(self, temperature):
    self.on()
    self.temp_pid_controller.set_new_setpoint(temperature)

  def get_temperature_C(self):
    temp = self.temp_sensor.readObjTempC()
    print "Current Temp: " + str(temp) + "*C"
    return temp

  def set_knobpos(self, pos):
    self.hold_freeze()
    self.set_knobpos_from_percentage(pos)
Пример #6
0
class RoboticArm:
  # Dimensions of the Arm
  vertical_offset_mm = 50
  vertical_arm_mm = 100
  horizontal_arm_mm = 100
  level_arm_len= 20
  claw_offset_to_center = 10

  small_cup_positions = [(100, 0, 30, 30, 30),
                         (100, 0, 30, 30, 30),
                         (100, 0, 30, 30, 30),
                         (100, 0, 30, 30, 30),
                         (100, 0, 30, 30, 30),
                         (100, 0, 30, 30, 30)]

  large_cup_positions = [(100, 0, 30, 30, 30),
                         (100, 0, 30, 30, 30),
                         (100, 0, 30, 30, 30),
                         (100, 0, 30, 30, 30),
                         (100, 0, 30, 30, 30),
                         (100, 0, 30, 30, 30)]

  # Positions of the cooking utensils by size.
  # Increasing index of size implies increasing diameter.
  utensil_positions_size = [(100, 180, 30, 30, 30),
                            (100, 180, 30, 30, 30),
                            (100, 180, 30, 30, 30)]
    
  # Positions of the components when the arm is at base
  base_pos = (100, 0, 30, 30, 30)
                      
  # Dimensions of the Rail
  max_rail_translation_mm = 520
  
  def __init__(self, rail_dir_pin, rail_step_pin, rail_enable_pin,
               base_servo_channel,
               vertical_servo_channel,
               horizontal_servo_channel,
               level_servo_channel,
               tipping_servo_channel,
               grasp_servo_channel):
    self.base_servo = Servo(base_servo_channel)
    self.vertical_servo = Servo(vertical_servo_channel)
    self.horizontal_servo = Servo(horizontal_servo_channel)
    self.level_servo = Servo(level_servo_channel)
    self.tipping_servo = Servo(tipping_servo_channel)
    self.grasp_servo = Servo(grasp_servo_channel)
    self.rail = stepper_axis.StepperAxis(rail_dir_pin, rail_step_pin, rail_enable_pin,
                                         RoboticArm.max_rail_translation_mm,
                                         inc_clockwise=False)
    self.move_to_base()

# Begin unfinished methods 
  def move_rail_rotate_base(self, dest_pos):
    self.at_base = False
    self.rail.move_to(max(0, min(RoboticArm.max_rail_translation_mm, dest_pos[1])))
    curr_y_pos = self.rail.get_curr_pos_mm()
    # Need to rotate base servo to point from (0,curr_pos[1]) to (dest_pos[0],dest_pos[1])
    # degrees to rotate clockwise with 0 pointing along x axis towards containers
    degrees = degrees(atan(float(curr_y_pos - dest_pos[1])
                                     /float(0 - dest_pos[0])))
    if (degrees < 0 or degrees > 180):
       raise ValueError("Invalid rotation angle:" +
                        str(degrees) + " degrees. Current position: "
                        + curr_y_pos + "Dest position: " + dest_pos)
    self.base_servo.move_to(degrees)

  def get_corrected_vertical_angle(vertical_angle):
    vertical_servo_offset = 15
    vertical_angle_corrected = vertical_angle - vertical_servo_offset
    if vertical_angle_corrected < 0:
      vertical_angle_corrected = vertical_angle_corrected - vertical_servo_offset
    return vertical_angle_corrected
  
  # All angles are in degrees. 
  def get_claw_x_from_servo_pos(base_angle, vertical_angle, horizontal_angle):
    """ Gets the position of the claw from the positions of the base, vertical
        and horizontal servos. """
    vertical_angle_corrected = get_corrected_vertical_angle(vertical_angle)

  def get_claw_y_from_servo_pos(base_angle, vertical_angle, horizontal_angle):
    None
    
# End of unfinished methods 
  
  def claw_grasp(self):
    self.grasp_servo.move_to(10)

  def claw_release(self):
    self.grasp_servo.move_to(55)

  
  def pour(self):
    """ Pours the container assuming that it is positioned over the vessel and
        waits for a few seconds before straightening it up. """
    self.tipping_servo.move_to(180)
    # Wait a few seconds for the contents to drain out.
    time.sleep(5)
    self.straighten_tipping_servo()

  def straighten_tipping_servo(self):
    self.tipping_servo.move_to(0)

  # Rail stepper and base servo have been adjusted as necessary. This function
  # Adjusts the three servos Vertical, Horizontal and Level servos to get the
  # required Z and X from to_pos.
  def execute_move_claw_xz(self, to_pos):
    from_pos = (self.vertical_servo.get_current_pos(),
                self.horizontal_servo.get_current_pos(),
                self.level_servo.get_current_pos())
    pos_delta = (to_pos[2] - from_pos[0],
                 to_pos[3] - from_pos[1],
                 to_pos[4] - from_pos[2])
    max_delta = max(abs(pos_delta[0]), abs(pos_delta[1]), abs(pos_delta[2]))
    for i in range(1, int(max_delta + 1)):
      # Update each servo proportionally
      update = [(float(i)/max_delta) * x for x in pos_delta]
      new_pos = [int(update[j] + from_pos[j]) for j in range(0, len(from_pos))]
      self.vertical_servo.move_to(new_pos[0])
      self.horizontal_servo.move_to(new_pos[1])
      self.level_servo.move_to(new_pos[2])
    self.vertical_servo.move_to(to_pos[0])
    self.horizontal_servo.move_to(to_pos[1])
    self.level_servo.move_to(to_pos[2])
    
  def move_to_cup(self, is_small_cup, cup_num):
    if is_small_cup:
      if cup_num < 0 or cup_num > 6:
        raise ValueError("Invalid small cup number:" + cup_num)
    else:
      if cup_num < 0 or cup_num > 5:
        raise ValueError("Invalid large cup number:" + cup_num)
      
    # Positions of the various servos.
    if is_small_cup:
      pos_for_cup = RoboticArm.small_cup_positions[cup_num]
    else:
      pos_for_cup = RoboticArm.large_cup_positions[cup_num]
    # Move the arm away from stirrer before moving rail.
    self.base_servo.move_to(pos_for_cup[1])
    # Arm out of collision path with stirrer. So, we can move the rail.
    self.rail.move_to(pos_for_cup[0])
    # Position claw around the cup.
    self.execute_move_claw_xz(pos_for_cup)
    self.at_base = False
    None

  def move_to_utensil(self, utensil_size):
    if utensil_size < 0 or utensil_size > 2:
      raise ValueError("Invalid utensil size:" + utensil_size)
    # Positions of the various servos.
    desired_servo_pos = RoboticArm.utensil_positions_size[utensil_size]
    self.execute_move_claw_xz(desired_servo_pos)
    self.rail.move_to(desired_servo_pos[0])
    self.base_servo.move_to(desired_servo_pos[1])
    self.at_base = False

  def move_to_base(self):
    self.execute_move_claw_xz(RoboticArm.base_pos)
    self.base_servo.move_to(RoboticArm.base_pos[1])
    self.rail.move_to(RoboticArm.base_pos[0])
    self.rail.disable()
    self.at_base = True
    None

  def is_at_base(self):
    return self.at_base

  # API method exposed by the RoboticArm
  def add_cup(self, is_small_cup, cup_num, utensil_size):
    # Init
    self.straighten_tipping_servo()
    self.claw_release()
    # Move and position around cup and grasp it
    self.move_to_cup(is_small_cup, cup_num)
    self.claw_grasp()
    self.move_to_utensil(utensil_size)
    # Pours and straightens.
    self.pour()
    self.move_to_cup(is_small_cup, cup_num)
    self.claw_release()
    self.move_to_base()
    self.rail.disable()

  def shutdown(self):
    self.move_to_base()