class Channel: def __init__(self, name, output_pin, input_pin=None): self.name = name self.state = None self.output_pin = output_pin if input_pin is not None: self.input_pin = input_pin self.output_device = DigitalOutputDevice(output_pin) if input_pin: self.input_device = DigitalInputDevice(input_pin) def set(self, state): """Sets the channel output""" self.state = state if state == 'On': self.output_device.on() elif state == 'Off': self.output_device.off() else: raise NotImplementedError log.info('Channel %s set to %s', self.name, state) def valid(self): """ Checks if the channel output is valid Returns: True, if the output and input pin states match. False, if they don't match. None, if no input pin is defined. """ if self.input_pin is None: return None else: return self.output_device.value == self.input_device.value def status(self): return { 'state': self.state, 'valid': self.valid(), }
class PCD8544(SPIDevice): """ PCD8544 display implementation. This implementation uses software shiftOut implementation? @author SrMouraSilva Based in 2013 Giacomo Trudu - wicker25[at]gmail[dot]com Based in 2010 Limor Fried, Adafruit Industries https://github.com/adafruit/Adafruit_Nokia_LCD/blob/master/Adafruit_Nokia_LCD/PCD8544.py Based in CORTEX-M3 version by Le Dang Dung, 2011 [email protected] (tested on LPC1769) Based in Raspberry Pi version by Andre Wussow, 2012, [email protected] Based in Raspberry Pi Java version by Cleverson dos Santos Assis, 2013, [email protected] https://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md The SPI master driver is disabled by default on Raspbian. To enable it, use raspi-config, or ensure the line dtparam=spi=on isn't commented out in /boot/config.txt, and reboot. :param int din: Serial data input :param int sclk: Serial clock input (clk) :param int dc: Data/Command mode select (d/c) :param int rst: External reset input (res) :param int cs: Chip Enable (CS/SS, sce) :param contrast :param inverse """ def __init__(self, din, sclk, dc, rst, cs, contrast=60, inverse=False): super(PCD8544, self).__init__(clock_pin=sclk, mosi_pin=din, miso_pin=9, select_pin=cs) self.DC = DigitalOutputDevice(dc) self.RST = DigitalOutputDevice(rst) self._reset() self._init(contrast, inverse) self.drawer = DisplayGraphics(self) self.clear() self.dispose() def _reset(self): self.RST.off() time.sleep(0.100) self.RST.on() def _init(self, contrast, inverse): # H = 1 self._send_command(SysCommand.FUNC | Setting.FUNC_H) self._send_command(SysCommand.BIAS | Setting.BIAS_BS2) self._send_command(SysCommand.VOP | contrast & 0x7f) # H = 0 self._send_command(SysCommand.FUNC | Setting.FUNC_V) self._send_command(SysCommand.DISPLAY | Setting.DISPLAY_D | Setting.DISPLAY_E * (1 if inverse else 0)) def _send_command(self, data): self.DC.off() self._spi.write([data]) def _send_data_byte(self, x, y, byte): self._set_cursor_x(x) self._set_cursor_y(y) self.DC.on() self._spi.write([byte]) def set_contrast(self, value): self._send_command(SysCommand.FUNC | Setting.FUNC_H) self._send_command(SysCommand.VOP | value & 0x7f) self._send_command(SysCommand.FUNC | Setting.FUNC_V) def write_all(self, data): self._set_cursor_x(0) self._set_cursor_y(0) self.DC.on() self._spi.write(data) def _set_cursor_x(self, x): self._send_command(SysCommand.XADDR | x) def _set_cursor_y(self, y): self._send_command(SysCommand.YADDR | y) def clear(self): self._set_cursor_x(0) self._set_cursor_y(0) self.drawer.clear() @property def width(self): return DisplaySize.WIDTH @property def height(self): return DisplaySize.HEIGHT @property def value(self): return 0 def close(self): super(PCD8544, self).close() @property def draw(self): return self.drawer.draw def dispose(self): self.drawer.dispose()
class KamigamiInterface(): def __init__(self, do_calibrate=True): """ Initialize Kamigami interface """ # Setup ROS subscribers, publishers pwm_sub = rospy.Subscriber('kamigami/motor_cmd', PWMCommand, self.recieve_motor_cmd) step_sub = rospy.Subscriber('kamigami/step_cmd', StepCommand, self.recieve_step_cmd) self.imu_pub = rospy.Publisher('imu/data_raw', Imu, queue_size=10) # Setup action clients, servers # None as of now, should be using one for stepping but VREP only supports services/actions for ROS2 # TODO: Add a debugging mode (multiple levels) or take advantage of ROS's own tools # Setup IMU i2c = busio.I2C(board.SCL, board.SDA) self.sensor = LSM6DS33(i2c) # TODO: Read in from config file # Running these at slightly above 100 Hz # These are currently the default values self.sensor.accelerometer_data_rate = Rate.RATE_104_HZ self.sensor.gyro_data_rate = Rate.RATE_104_HZ self.sensor.accelerometer_range = AccelRange.RANGE_4G self.sensor.gyro_range = GyroRange.RANGE_250_DPS # Setup Raspberry Pi Pins # TODO: Take pin definitions from a config file self.motor_standby = DigitalOutputDevice(17) self.motor_right_pwm = PWMOutputDevice(13) self.motor_left_pwm = PWMOutputDevice(18) self.motor_right_forward = DigitalOutputDevice(27) self.motor_right_backward = DigitalOutputDevice(22) self.motor_left_forward = DigitalOutputDevice(24) self.motor_left_backward = DigitalOutputDevice(23) self.pins_on() # TODO: Take in constants from some kind of config file self._loop_rate = 100 self._step_pwm = .6 self._step_rest_time = .35 self._left_ang_desired = .09 self._right_ang_desired = -.09 self._threshold = .02 self._filter_alpha = .98 if do_calibrate: # Calibrate first print("\nCalibrating! Please keep robot still.") calibration_time = 3 calibration_start = rospy.get_time() x_ang_vels = [] x_tilt = [] while (rospy.get_time() - calibration_start) < calibration_time: x_ang_vels.append(self.sensor.gyro[0]) x_tilt.append( self.acceleration_to_tilt(self.sensor.acceleration)) # Estimate gyro bias in the roll direction by averaging the angular velocity over all samples self.x_ang_bias = sum(x_ang_vels) / len(x_ang_vels) # Estimate current tilt self.x_tilt_start = sum(x_tilt) / len(x_tilt) print("\nCalibration finished!") print(f"Gyro x bias: {self.x_ang_bias}") print(f"Starting tilt: {self.x_tilt_start}") # Instance variables self.roll_estimate = 0 # TODO: Find a better way to represent step commands... self.queued_left_steps = 3 self.queued_right_steps = 3 # Custom shutdown function to stop all motors rospy.on_shutdown(self.shutdown) def recieve_motor_cmd(self, data): """ Recieve KamigamiCommand message and control motors from that """ self.motor_cmd(data.motor_left, data.motor_right) def motor_cmd(self, motor_left_speed, motor_right_speed): """ Set both motors of Kamigami to input values """ # Saturate max/min PWMs motor_left_speed = max(min(1, motor_left_speed), -1) motor_right_speed = max(min(1, motor_right_speed), -1) # Determine pins to set high and output PWM if motor_left_speed >= 0: self.motor_left_forward.on() self.motor_left_backward.off() self.motor_left_pwm.value = motor_left_speed else: self.motor_left_forward.off() self.motor_left_backward.on() self.motor_left_pwm.value = -motor_left_speed if motor_right_speed >= 0: self.motor_right_forward.on() self.motor_right_backward.off() self.motor_right_pwm.value = motor_right_speed else: self.motor_right_forward.off() self.motor_right_backward.on() self.motor_right_pwm.value = -motor_right_speed # print('Setting motor left to {}'.format(motor_left_speed)) # print('Setting motor right to {}'.format(motor_right_speed)) def recieve_step_cmd(self, data): # self.take_steps(data.left_steps, data.right_steps) self.queued_left_steps = data.left_steps self.queued_right_steps = data.right_steps # def take_steps(self, left_steps, right_steps): # for i in range(left_steps): # while(abs(self.roll_estimate - self._ang_desired) > self._threshold) and (not rospy.is_shutdown()) # return # # for i in range(n_steps): # # last = rospy.get_time() # # ang = 0 # # for _ in range(left_steps): # # while (abs(ang - ang_desired) > threshold) and (not rospy.is_shutdown()): # # ang_desired = abs(ang_desired) # # send_cmd(pwm, 0) # # cur = rospy.get_time() # # gyro_estimate = ang + (cur - last) * (angular_velocity[0] - x_ang_bias) # # accel_estimate = get_tilt() - x_tilt_start # # last = cur # # # Complementary filter equation # # # TODO: Refine parameters based on cutoff frequencies, sampling times # # ang = self._filter_alpha*(gyro_estimate) + (1-self._filter_alpha)*accel_estimate # # # Only trust accelerometer if it is reasonable # # # if abs(gyro_estimate - accel_estimate) < .1: # # # ang = .98 * (gyro_estimate) + .02 * accel_estimate # # # else: # # # ang = gyro_estimate # # ang_pub.publish(ang) # # if rospy.is_shutdown(): # # break def acceleration_to_tilt(self, linear_acceleration): return math.atan2( linear_acceleration[1], math.sqrt(linear_acceleration[1] * linear_acceleration[1] + linear_acceleration[2] * linear_acceleration[2])) def update_state(self, last_time): """ Updating state of the Kamigami by - polling sensors for new data - TODO: filtering - publishing new IMU data to imu/data_raw topic """ # Poll IMU sensors angular_velocity = list(self.sensor.gyro) linear_acceleration = self.sensor.acceleration # print("Angular Velocity: {}".format(angular_velocity) # print("Linear Acceleration: {}".format(linear_acceleration)) # Apply drift correction angular_velocity[0] = angular_velocity[0] - self.x_ang_bias # Update internal roll estimate cur_time = rospy.get_time() gyro_estimate = self.roll_estimate + angular_velocity[0] * (cur_time - last_time) accelerometer_estimate = math.atan2( linear_acceleration[1], math.sqrt(linear_acceleration[1] * linear_acceleration[1] + linear_acceleration[2] * linear_acceleration[2])) # Simple complementary filter # TODO: Use a Kalman filter! self.roll_estimate = self._filter_alpha * gyro_estimate + ( 1 - self._filter_alpha) * accelerometer_estimate # print (f"Roll: {self.roll_estimate}") # Create and populate IMU message imu_data = Imu() imu_data.header.stamp = rospy.Time.now() imu_data.header.frame_id = 'imu_link' imu_data.angular_velocity.x, imu_data.angular_velocity.y, imu_data.angular_velocity.z = angular_velocity imu_data.linear_acceleration.x, imu_data.linear_acceleration.y, imu_data.linear_acceleration.z = linear_acceleration # Publish new state data self.imu_pub.publish(imu_data) return cur_time def shutdown(self): """ Disable Kamigami by - shutting off motors - deactivating pins """ self.motor_cmd(0, 0) self.pins_off() print("Kamigami interface shutdown.") def pins_on(self): """ Enable Raspberry Pi pins """ self.motor_standby.on() def pins_off(self): """ Deactivate Raspberry Pi pins """ self.motor_standby.off() self.motor_right_pwm.off() self.motor_left_pwm.off() self.motor_right_forward.off() self.motor_right_backward.off() self.motor_left_forward.off() self.motor_left_backward.off() def run(self): """ Keep the Kamigami interface running and update state messages """ rate = rospy.Rate(self._loop_rate) last_step = last_time = rospy.get_time() while not rospy.is_shutdown(): # Update state last_time = self.update_state(last_time) # If we should be taking steps, do that if rospy.get_time() - last_step > self._step_rest_time: if self.queued_left_steps: if (abs(self.roll_estimate - self._left_ang_desired) > self._threshold): self.motor_cmd(self._step_pwm, 0) print(f"Roll: {self.roll_estimate}") # print(f"Left desired: {self._left_ang_desired}") # print(f"Threshold: {self._threshold}") else: print("Left step completed!") self.motor_cmd(0, 0) self.queued_left_steps = max( self.queued_left_steps - 1, 0) last_step = rospy.get_time() elif self.queued_right_steps: if (abs(self.roll_estimate - self._right_ang_desired) > self._threshold): print(f"Roll: {self.roll_estimate}") # print(f"Right desired: {self._right_ang_desired}") # print(f"Threshold: {self._threshold}") self.motor_cmd(0, self._step_pwm) else: print("Right step completed!") self.motor_cmd(0, 0) self.queued_right_steps = max( self.queued_right_steps - 1, 0) last_step = rospy.get_time() else: print("Waiting before next step...") rate.sleep() self.shutdown()
from gpiozero import PWMOutputDevice, DigitalOutputDevice from time import sleep enAPin = 12 enBPin = 13 in1Pin = 7 in2Pin = 8 in3Pin = 9 in4Pin = 10 enA = PWMOutputDevice(enAPin) enB = PWMOutputDevice(enBPin) in1 = DigitalOutputDevice(in1Pin) in2 = DigitalOutputDevice(in2Pin) in3 = DigitalOutputDevice(in3Pin) in4 = DigitalOutputDevice(in4Pin) enA.value = 1 enB.value = 1 in1.on() in2.off() in3.on() in4.off() sleep(5)
from gpiozero import DigitalOutputDevice from time import sleep sleep_time = 5 test_pin = DigitalOutputDevice(17) while True: test_pin.on() sleep(sleep_time) test_pin.off() sleep(sleep_time)
DHT_MODEL = 11 HEAT_PIN = 17 COOL_PIN = 27 LIGHT_PIN = 18 lastUpdate = 0 print "Initializing grbl communication" grbl = serial.Serial('/dev/serial0', 115200) grbl.write("\r\n\r\n") print "Creating heat/cool pins" # https://gpiozero.readthedocs.io/en/stable/api_output.html heatRelay = DigitalOutputDevice(HEAT_PIN) coolRelay = DigitalOutputDevice(COOL_PIN) lightRelay = DigitalOutputDevice(LIGHT_PIN) lightRelay.on() heatRelay.on() coolRelay.on() print "Authenticating with firebase..." # Use a service account cred = credentials.Certificate('/home/pi/Pycotronics/private_firebase_key.json') firebase_admin.initialize_app(cred, { 'databaseURL': 'https://mycotronics2.firebaseio.com/' }) print "Fetching settings from firebase..." settings = db.reference("settings/3") print "Getting reference to logs" doc = db.reference("logs/3") print "Getting reference to image bucket"
#!/usr/bin/env python from gpiozero import DigitalOutputDevice from time import sleep rLight = DigitalOutputDevice(21,active_high=False) rPump = DigitalOutputDevice(20,active_high=False) rLight.on() sleep(1) rLight.off() sleep(1) rLight.on() sleep(1) rLight.off() sleep(5) rLight.on() rPump.on() sleep(30) rPump.off() sleep(10) rLight.off()
from gpiozero import DigitalInputDevice, DigitalOutputDevice from time import sleep led_pin = DigitalOutputDevice(7) button_pin = DigitalInputDevice(14, pull_up=False) while True: print(button_pin.value) if button_pin.value == 1: led_pin.on() else: led_pin.off() sleep(0.1)
from gpiozero import DigitalOutputDevice from time import sleep pinAred = DigitalOutputDevice(17) pinByellow = DigitalOutputDevice(27) pinCgreen = DigitalOutputDevice(22) pinDblack = DigitalOutputDevice(23) pinEred = DigitalOutputDevice(13) pinFyellow = DigitalOutputDevice(6) pinGgreen = DigitalOutputDevice(5) pinHblack = DigitalOutputDevice(12) pinAred.off() pinByellow.on() pinCgreen.on() pinDblack.off() pinEred.off() pinFyellow.off() pinGgreen.on() pinHblack.on() sleep(1) pinAred.close() pinByellow.close() pinCgreen.close() pinDblack.close() pinEred.close() pinFyellow.close() pinGgreen.close() pinHblack.close()
a = pin_a.is_pressed b = pin_b.is_pressed prev_a = not a prev_b = not b prev_z = True counter = 0 loop = True delay = .001 while(loop): device.on() sleep(delay) device.off() sleep(delay) if a != pin_a.is_pressed or b != pin_b.is_pressed: if pin_a.is_pressed == prev_a and pin_b.is_pressed == prev_b: counter -= 1 else: counter += 1 print(str(int(pin_a.is_pressed)) + " " + str(int(pin_b.is_pressed)) + " " + str(int(pin_z.is_pressed)) + " " + str(counter)) #print(str(pin_a.is_pressed) + " " + str(pin_b.is_pressed) + " " + str(pin_z.is_pressed)) a = pin_a.is_pressed prev_a = a b = pin_b.is_pressed prev_b = b loop = pin_z.is_pressed or prev_z
from gpiozero import DigitalOutputDevice from time import sleep import random d = DigitalOutputDevice(2, active_high=False) d.on() sleep(3) d.off()
class Printer(object): # Initialise objects and variables. def __init__(self): # HARDWARE INITIALISATION. # LIMIT SWITCHES self.xLim = Button(15, pull_up=False) self.yLim = Button(14, pull_up=False) # SOLENOID self.sol = DigitalOutputDevice(20) # STATUS LED self.sLED = DigitalOutputDevice(21) # MOTOR DRIVERS self.pins = [[ DigitalOutputDevice(8), DigitalOutputDevice(7), DigitalOutputDevice(12), DigitalOutputDevice(16) ], [ DigitalOutputDevice(18), DigitalOutputDevice(23), DigitalOutputDevice(24), DigitalOutputDevice(25) ]] # SOFTWARE INITIALISATION self.VERSION = "1.0" self.ARCHITECTURE = "DOT-MATRIX" # MOTOR STEP SEQUENCE self.seq = [[1, 0, 1, 0], [0, 1, 1, 0], [0, 1, 0, 1], [1, 0, 0, 1]] # POSITION self.pos = [200, 200] # STEP INDEX IN SEQUENCE self.step = 0 # MAXIMUM ALLOWED STEPS self.maxSteps = 200 # Output current position to console. def printPos(self): print("Position: (%d, %d)" % (self.pos[0], self.pos[1])) # Step pin set by number of steps def doSteps(self, pins, sDir, steps): # Step the requested number of steps. for x in range(steps): for x in range(4): if (self.seq[self.step][x]): pins[x].on() else: pins[x].off() if sDir: self.step += 1 else: self.step -= 1 sleep(0.005) #GOOD SPEED 0.005 if self.step >= 4: self.step = 0 elif self.step < 0: self.step = 3 # Step axis by number of steps # Direction 1 is towards limits. # Axis X is 0. def stepAxis(self, axis, sDir, steps): # Modifier for adjusting position. mod = -1 if sDir else 1 # DEBUG #print("Stepping axis %d by %d steps in direction %d" % (axis, steps, dir)) # Check if step is valid from position. if (self.pos[axis] + mod * steps >= self.maxSteps) or (self.pos[axis] + mod * steps < 0): print( "Cannot perform command: \'Step %d steps from position (%d, %d)\'" % (steps, self.pos[0], self.pos[1])) print(self.pos[axis] + mod * steps) return 0 # Perform Steps self.doSteps(self.pins[axis], sDir, steps) self.pos[axis] = self.pos[axis] + mod * steps # Step to position given. def stepToPos(self, pos): # Check bounds if (max(pos) > self.maxSteps) or (min(pos) < 0): print("Invalid Position (%d, %d)." % (pos[0], pos[1])) return 0 # Calculate deltas in dimensions. dx = pos[0] - self.pos[0] dy = pos[1] - self.pos[1] # Step required amounts for axis, value in [[0, dx], [1, dy]]: sleep(0.1) sDir = 0 if (value >= 0) else 1 self.stepAxis(axis, sDir, int(math.fabs(value))) return 1 # Home Axes and reset position. def home(self): sleep(0.5) print("Homing Axes.") for axis, limit in ([[0, self.xLim], [1, self.yLim]]): while not (limit.is_pressed): self.stepAxis(axis, 1, 1) self.pos = [200, 200] print("Axis %d homed." % axis) self.pos = [0, 0] # Offset by 20 steps self.stepAxis(0, 0, 20) self.stepAxis(0, 0, 20) sleep(0.5) # Draw a pixel at current position. def drawPixel(self): self.sol.on() sleep(0.15) self.sol.off() # Print the matrix onto paper. def printMatrix(self, matrix): self.sol.off() # Home self.home() # Iterate over pixels. print("Printing...") for x in range(len(matrix) - 1): for y in range(len(matrix[0]) - 1): # If pixel is active. if (matrix[x][y] == "1"): # Step to position. #print("Moving to Position (%d, %d)" % (x, y)) r = self.stepToPos([x, y]) # Invalid position error. Something has broken. if not (r): print("Error Encountered. Cancelling print.") self.sol.off() self.home() return sleep(0.15) self.drawPixel() # Done. self.sol.off() print("Complete.") # Home. self.home()
really_close_to_target = target - 5 if not power: background = make_blank_background("black") relay.off() elif value == target: background = make_blank_background("green") relay.off() elif value >= target: background = make_blank_background("red") relay.off() elif value >= really_close_to_target: background = make_blank_background("turquoise") relay.blink(on_time=2, off_time=4, n=1, background=False) elif value >= close_to_target: background = make_blank_background("aqua") relay.blink(on_time=2, off_time=2, n=1, background=False) else: background = make_blank_background("blue") relay.on() image = write_white_text(background, (str(value)) + u"\u00B0", 0, big_font) image = write_gray_text(background, (str(target)) + u"\u00B0", 150, small_font) lcd.display(image)
class JoeSlot: def __init__(self, mcp: MCP23017, pwm_pin, control_pins, supply_voltage, pwm=True): self.mcp = mcp self.supply_voltage = supply_voltage self.control_pins = control_pins self.pwm = pwm if self.pwm: self.pwm_pin = PWMOutputDevice(pwm_pin) else: self.pwm_pin = DigitalOutputDevice(pwm_pin) self.pwm_pin.on() self.mcp.setup(self.control_pins[0], 0) self.mcp.setup(self.control_pins[1], 0) self._scale_factor = 1 self._speed = 1 self._direction = 0 @property def voltage(self): return self._scale_factor * self.supply_voltage @voltage.setter def voltage(self, value): if self.pwm: if value <= self.supply_voltage: self._scale_factor = round((value / self.supply_voltage), 3) else: print("Cannot set higher than supply!") else: print("Can't set speed for non-pwm pin.") @property def speed(self): '''Gets speed''' return self._speed @speed.setter def speed(self, value): '''Sets speed as pwm value.''' if self.pwm: if value <= 1 and value >= 0: self._speed = value self.pwm_pin.value = self._scale_factor * value else: print("Invalid speed.") else: print("Can't set speed for non-pwm pin.") @property def direction(self): '''Get direction''' return self._direction @direction.setter def direction(self, value): '''Sets the directional control pins.''' if value == 0: self.mcp.output(self.control_pins[0], 0) self.mcp.output(self.control_pins[1], 0) self._direction = 0 elif value == 1: self.mcp.output(self.control_pins[0], 0) self.mcp.output(self.control_pins[1], 1) self._direction = 1 elif value == -1: self.mcp.output(self.control_pins[0], 1) self.mcp.output(self.control_pins[1], 0) self._direction = -1 else: print("Invalid direction")
class Robot(object): SPEED_HIGH = int(config.get("robot.speed","speed_high")) SPEED_MEDIUM = int(config.get("robot.speed","speed_medium")) SPEED_LOW = int(config.get("robot.speed","speed_low")) ##Define the arc of the turn process by a tuple wheels speed (left, right) LEFT_ARC_CLOSE = eval(config.get("robot.speed","left_arc_close")) LEFT_ARC_OPEN = eval(config.get("robot.speed","left_arc_open")) RIGHT_ARC_CLOSE = eval(config.get("robot.speed","right_arc_close")) RIGHT_ARC_OPEN = eval(config.get("robot.speed","right_arc_open")) #Pin pair left FORWARD_LEFT_PIN = int(config.get("robot.board.v1","forward_left_pin")) BACKWARD_LEFT_PIN = int(config.get("robot.board.v1","backward_left_pin")) #Pin pair right FORWARD_RIGHT_PIN = int(config.get("robot.board.v1","forward_right_pin")) BACKWARD_RIGHT_PIN = int(config.get("robot.board.v1","backward_right_pin")) #PWM PINS PWM_LEFT_PIN = int(config.get("robot.board.v1","pwm_left_pin")) PWM_RIGHT_PIN = int(config.get("robot.board.v1","pwm_right_pin")) #Frecuency by hertz FRECUENCY = int(config.get("robot.board.v1","frecuency")) # Cycles fits for pwm cycles LEFT_CYCLES_FIT = int(config.get("robot.board.v1","left_cycles_fit")) RIGHT_CYCLES_FIT = int(config.get("robot.board.v1","right_cycles_fit")) #Pin settings for head control HEAD_HORIZONTAL_PIN = int(config.get("robot.board.v1","head_pwm_pin_horizontal_axis")) HEAD_VERTICAL_PIN = int(config.get("robot.board.v1","head_pwm_pin_vertical_axis")) HEAD_HORIZONTAL_RANGE = config.get("robot.board.v1","head_horizontal_range").split(",") HEAD_VERTICAL_RANGE = config.get("robot.board.v1","head_vertical_range").split(",") RIGHT_WHEEL_SENSOR = int(config.get("robot.board.v1","right_wheel_sensor")) LEFT_WHEEL_SENSOR = int(config.get("robot.board.v1", "left_wheel_sensor")) CONTROLLER_BOARD = config.get("robot.controller", "board") #v2 WHEEL_LEFT_ENABLED = int(config.get("robot.board.v2", "wheel_left_enabled")) WHEEL_LEFT_HEADING = int(config.get("robot.board.v2", "wheel_left_heading")) WHEEL_LEFT_STEP = int(config.get("robot.board.v2", "wheel_left_step")) WHEEL_RIGHT_ENABLED = int(config.get("robot.board.v2", "wheel_right_enabled")) WHEEL_RIGHT_HEADING = int(config.get("robot.board.v2", "wheel_right_heading")) WHEEL_RIGHT_STEP = int(config.get("robot.board.v2", "wheel_right_step")) SERVO_V = None SERVO_H = None head_vertical_current_position = None head_horizontal_current_position = None def __init__(self): if env == "prod": log.debug("Using %s configuration" % self.CONTROLLER_BOARD ) self.SERVO_H = AngularServo(self.HEAD_HORIZONTAL_PIN, min_angle=-80, max_angle=80) self.SERVO_V = AngularServo(self.HEAD_VERTICAL_PIN, min_angle=-80, max_angle=80) ##Digital devices self.forward_left_device = None self.forward_right_device = None self.backward_left_device = None self.backward_right_device = None self.wheel_right_step = None self.wheel_left_step = None self.wheel_right_heading = None self.wheel_left_heading = None self.wheel_right_enabled = None self.wheel_left_enabled = None self.pwm_left = None self.pwm_right = None if self.CONTROLLER_BOARD == "v1": self.forward_left_device = DigitalOutputDevice(self.FORWARD_LEFT_PIN, True, False) self.forward_right_device = DigitalOutputDevice(self.FORWARD_RIGHT_PIN, True, False) self.backward_left_device = DigitalOutputDevice(self.BACKWARD_LEFT_PIN, True, False) self.backward_right_device = DigitalOutputDevice(self.BACKWARD_RIGHT_PIN, True, False) self.pwm_left = PWMOutputDevice(self.PWM_LEFT_PIN, True, False, self.FRECUENCY) self.pwm_right = PWMOutputDevice(self.PWM_RIGHT_PIN, True, False, self.FRECUENCY) if self.CONTROLLER_BOARD == "v2": self.wheel_right_step = DigitalOutputDevice(self.WHEEL_RIGHT_STEP, True, False) self.wheel_left_step = DigitalOutputDevice(self.WHEEL_LEFT_STEP, True, False) self.wheel_right_heading = DigitalOutputDevice(self.WHEEL_RIGHT_HEADING, True, False) self.wheel_left_heading = DigitalOutputDevice(self.WHEEL_LEFT_HEADING, True, False) self.wheel_right_enabled = DigitalOutputDevice(self.WHEEL_RIGHT_ENABLED, True, False) self.wheel_left_enabled = DigitalOutputDevice(self.WHEEL_LEFT_ENABLED, True, False) self.current_horizontal_head_pos = 0 self.current_vertical_head_pos = 0 self.center_head() self._counting_steps = 0 self._current_steps = 0 self._stepper_current_step = 0 def _set_left_forward(self): if self.CONTROLLER_BOARD == "v1": self.forward_left_device.on() self.backward_left_device.off() def _set_left_backward(self): if self.CONTROLLER_BOARD == "v1": self.forward_left_device.off() self.backward_left_device.on() def _set_left_stop(self): if self.CONTROLLER_BOARD == "v1": self.forward_left_device.on() self.backward_left_device.on() def _set_right_forward(self): if self.CONTROLLER_BOARD == "v1": self.forward_right_device.on() self.backward_right_device.off() def _set_right_backward(self): if self.CONTROLLER_BOARD == "v1": self.forward_right_device.off() self.backward_right_device.on() def _set_right_stop(self): if self.CONTROLLER_BOARD == "v1": self.forward_right_device.on() self.backward_right_device.on() def set_forward(self): log.debug("setting movement to forward") if env == "prod": self._set_left_forward() self._set_right_forward() def set_backward(self): log.debug("setting movement to backward") if env == "prod": self._set_left_backward() self._set_right_backward() def set_rotate_left(self): log.debug("setting movement to rotate left") if env == "prod": self._set_left_backward() self._set_right_forward() def set_rotate_right(self): log.debug("setting movement to rotate right") if env == "prod": self._set_right_backward() self._set_left_forward() def stop(self): log.debug("stopping") if env == "prod": if self.CONTROLLER_BOARD == "v1": self.pwm_left.off() self.pwm_right.off() def move(self, speed=None, arc=None, steps=100, delay=0.7, heading=1): if self.CONTROLLER_BOARD == "v1": self._move_dc(speed, arc) elif self.CONTROLLER_BOARD == "v2": self._move_steppers_bipolar(steps=steps, delay=delay, heading=heading) def _move_dc(self, speed, arc): log.debug("Moving using DC motors") if (speed and arc): print("Error: speed and arc could not be setted up at the same time") return if env == "prod": self.pwm_left.on() self.pwm_right.on() if (speed): log.debug("moving on " + str(speed)) log.debug("aplying fit: left " + str(self.LEFT_CYCLES_FIT) + " right " + str(self.RIGHT_CYCLES_FIT)) aditional_left_clycles = self.LEFT_CYCLES_FIT if ((speed + self.LEFT_CYCLES_FIT) <= 100.00) else 0.00 aditional_right_clycles = self.RIGHT_CYCLES_FIT if ((speed + self.RIGHT_CYCLES_FIT) <= 100.00) else 0.00 if env == "prod": self.pwm_left.value = (speed + aditional_left_clycles) / 100.00 self.pwm_right.value = (speed + aditional_right_clycles) / 100.00 if (arc): cycle_left, cycle_right = arc log.debug("turning -> left wheel: " + str(cycle_left) + " right wheel: " + str(cycle_right)) if env == "prod": self.pwm_left.value = cycle_left / 100.00 self.pwm_right.value = cycle_right / 100.00 def _move_steppers_bipolar(self, steps, heading, delay): """ Currently it would take 4 steps to complete a whole wheel turn """ log.debug("Moving steppers bipolars . Steps " + str(steps) + " delay " + str(delay)) steps_left = abs(steps) if env == "prod": self.wheel_left_enabled.off() self.wheel_right_enabled.off() while(steps_left!=0): log.debug("Current step: " + str(steps_left)) if env == "prod": if heading: self.wheel_left_heading.on() self.wheel_right_heading.off() else: self.wheel_left_heading.off() self.wheel_right_heading.on() self.wheel_left_step.off() self.wheel_right_step.off() sleep(delay/1000.00) self.wheel_left_step.on() self.wheel_right_step.on() sleep(delay/1000.00) steps_left -= 1 if env == "prod": self.wheel_left_enabled.on() self.wheel_right_enabled.on() def center_head(self): log.debug("centering head") self.head_horizontal_current_position = 0 self.head_vertical_current_position = 0 if env == "prod": self.SERVO_H.mid() self.SERVO_V.mid() sleep(0.2) self.SERVO_H.detach() self.SERVO_V.detach() def _angle_to_ms(self,angle): return 1520 + (int(angle)*400) / 45 def move_head_horizontal(self, angle): log.debug("horizontal limits: " + self.HEAD_HORIZONTAL_RANGE[0] +" "+ self.HEAD_HORIZONTAL_RANGE[1]) log.debug("new horizontal angle: " + str(angle)) if angle > int(self.HEAD_HORIZONTAL_RANGE[0]) and angle < int(self.HEAD_HORIZONTAL_RANGE[1]): log.debug("moving head horizontal to angle: " + str(angle)) self.head_horizontal_current_position = angle if env == "prod": self.SERVO_H.angle = angle sleep(0.2) self.SERVO_H.detach() def move_head_vertical(self, angle): log.debug("vertical limits: " + self.HEAD_VERTICAL_RANGE[0] +" "+ self.HEAD_VERTICAL_RANGE[1]) log.debug("new vertical angle: " + str(angle)) if angle > int(self.HEAD_VERTICAL_RANGE[0]) and angle < int(self.HEAD_VERTICAL_RANGE[1]): log.debug("moving head vertical to angle: " + str(angle)) self.head_vertical_current_position = angle if env == "prod": self.SERVO_V.angle = angle sleep(0.2) self.SERVO_V.detach() #Used for encoders def steps(self, counting): self._current_steps = counting self.move(speed=self.SPEED_HIGH) self.move(speed=self.SPEED_MEDIUM) rpio.add_interrupt_callback(RIGHT_WHEEL_SENSOR, self._steps_callback, threaded_callback=True) rpio.add_interrupt_callback(LEFT_WHEEL_SENSOR, self._steps_callback, threaded_callback=True) rpio.wait_for_interrupts(threaded=True) def _steps_callback(self, gpio_id, value): self._counting_steps += 1 if self._counting_steps > self._current_steps: self._counting_steps = 0 self._current_steps = 0 rpio.stop_waiting_for_interrupts()
from gpiozero import Button, DigitalOutputDevice from gpiozero.pins.rpigpio import RPiGPIOPin, RPiGPIOFactory from time import sleep from flask import Flask, request, jsonify #Tried using the debounce option but it isn't working as expected #This bug is confirmed by the interwebs... greenButton = Button(4, pull_up=False) redButton = Button(17, pull_up=False) output1 = DigitalOutputDevice(27) output2 = DigitalOutputDevice(14) output1.on() class Actuator(): pin1 = 27 pin2 = 14 def __init__(self): output1 = DigitalOutputDevice(pin1) output2 = DigitalOutputDevice(pin2) def Work(self): output1.on() output2.off() def Home(self): output1.off() output2.on()
class PCD8544(SPIDevice): """ PCD8544 display implementation. This implementation uses software shiftOut implementation? @author SrMouraSilva Based in 2013 Giacomo Trudu - wicker25[at]gmail[dot]com Based in 2010 Limor Fried, Adafruit Industries https://github.com/adafruit/Adafruit_Nokia_LCD/blob/master/Adafruit_Nokia_LCD/PCD8544.py Based in CORTEX-M3 version by Le Dang Dung, 2011 [email protected] (tested on LPC1769) Based in Raspberry Pi version by Andre Wussow, 2012, [email protected] Based in Raspberry Pi Java version by Cleverson dos Santos Assis, 2013, [email protected] https://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md The SPI master driver is disabled by default on Raspbian. To enable it, use raspi-config, or ensure the line dtparam=spi=on isn't commented out in /boot/config.txt, and reboot. :param int din: Serial data input :param int sclk: Serial clock input (clk) :param int dc: Data/Command mode select (d/c) :param int rst: External reset input (res) :param int cs: Chip Enable (CS/SS, sce) :param contrast :param inverse """ def __init__(self, din, sclk, dc, rst, cs, contrast=60, inverse=False): super(PCD8544, self).__init__(clock_pin=sclk, mosi_pin=din, miso_pin=9, select_pin=cs) self.DC = DigitalOutputDevice(dc) self.RST = DigitalOutputDevice(rst) self._reset() self._init(contrast, inverse) self.drawer = DisplayGraphics(self) self.clear() self.dispose() def _reset(self): self.RST.off() time.sleep(0.100) self.RST.on() def _init(self, contrast, inverse): # H = 1 self._send_command(SysCommand.FUNC | Setting.FUNC_H) self._send_command(SysCommand.BIAS | Setting.BIAS_BS2) self._send_command(SysCommand.VOP | contrast & 0x7f) # H = 0 self._send_command(SysCommand.FUNC | Setting.FUNC_V) self._send_command( SysCommand.DISPLAY | Setting.DISPLAY_D | Setting.DISPLAY_E * (1 if inverse else 0) ) def _send_command(self, data): self.DC.off() self._spi.write([data]) def _send_data_byte(self, x, y, byte): self._set_cursor_x(x) self._set_cursor_y(y) self.DC.on() self._spi.write([byte]) def set_contrast(self, value): self._send_command(SysCommand.FUNC | Setting.FUNC_H) self._send_command(SysCommand.VOP | value & 0x7f) self._send_command(SysCommand.FUNC | Setting.FUNC_V) def write_all(self, data): self._set_cursor_x(0) self._set_cursor_y(0) self.DC.on() self._spi.write(data) def _set_cursor_x(self, x): self._send_command(SysCommand.XADDR | x) def _set_cursor_y(self, y): self._send_command(SysCommand.YADDR | y) def clear(self): self._set_cursor_x(0) self._set_cursor_y(0) self.drawer.clear() @property def width(self): return DisplaySize.WIDTH @property def height(self): return DisplaySize.HEIGHT @property def value(self): return 0 def close(self): super(PCD8544, self).close() @property def draw(self): return self.drawer.draw def dispose(self): self.drawer.dispose()
class PhotoBox: """My PhotoBox""" # Configuration config = None FBI = "/usr/bin/sudo /usr/bin/fbi" FBI_KILL = "/usr/bin/sudo /usr/bin/killall fbi" GPHOTO = "/usr/bin/gphoto2" OMX = "/usr/bin/omxplayer" # class variables button_instant = None button_delayed = None switch_light_A = None switch_light_B = None last_picture = None standby_timer = None review_timer = None error_timer = None def __init__(self): logger.info("Initializing PhotoBox") self.config = configparser.ConfigParser() if os.path.isfile("photobox.ini"): self.config.read("photobox.ini") else: raise Exception("photobox.ini not found") # import pdb; pdb.set_trace() gpio = int(self.config['GPIO']['button_instant']) self.button_instant = Button(gpio, hold_time=3) gpio = int(self.config['GPIO']['button_delayed']) self.button_delayed = Button(gpio) gpio = int(self.config['GPIO']['button_shutdown']) self.button_shutdown = Button(gpio) self.button_shutdown.when_pressed = self.shutdownRaspi gpio = int(self.config['GPIO']['switch_light_A']) self.switch_light_A = DigitalOutputDevice(gpio, active_high=False) gpio = int(self.config['GPIO']['switch_light_B']) self.switch_light_B = DigitalOutputDevice(gpio, active_high=False) # Prepare Standby Timer t = int(self.config['TIMES']['standby']) self.standby_timer = Timer(t * 60.0, self.standby) t = int(self.config['TIMES']['review']) self.review_timer = Timer(t * 1.0, self.active) t = 5 # also change _dtb ## fixed: 5sec error screen self.error_timer = Timer(t * 1.0, self.active) # set camera settings os.system("%s --set-config-value capturetarget=1" % self.GPHOTO) # setting config value does not seem to stick with all cameras. So just modifying gphoto2 settings here. Need to exist... # Yes, sorry, this does expect Linux, for now. Well, as do file/dir separators later on :) os.system( '/bin/grep "ptp2=capturetarget=card" ~/.gphoto/settings || /bin/echo "ptp2=capturetarget=card" >>~/.gphoto/settings' ) # go into Active after init self.active() def shutdownRaspi(self): self._switch_lights(to=True) sleep(2) self._switch_lights(to=False) sleep(2) self._switch_lights(to=True) sleep(2) self._switch_lights(to=False) sleep(2) self._switch_lights(to=True) sleep(2) self._switch_lights(to=False) sleep(2) os.system("sudo shutdown -r now") def _remove_state(self, state): f = self.config['PATHS']['state'] + "/" + state if os.path.isfile(f): os.remove(f) def _set_state(self, state): if not self.config['PATHS']['state']: return # remove all possible files - do not care about old state self._remove_state("active") self._remove_state("standby") self._remove_state("error") self._remove_state("maintenance") f = open(self.config['PATHS']['state'] + "/" + state, "w+") f.write(state) f.close() ## disable timers and buttons def _dtb(self): dtbdebug = False dtbdebug and logger.debug( "_dtb: Disabling all Timers and Button activities") # Disable Timers and Buttons dtbdebug and logger.debug("_dtb: cancel standby") self.standby_timer.cancel() t = int(self.config['TIMES']['standby']) self.standby_timer = Timer(t * 60.0, self.standby) dtbdebug and logger.debug("_dtb: cancel review") self.review_timer.cancel() t = int(self.config['TIMES']['review']) self.review_timer = Timer(t * 1.0, self.active) dtbdebug and logger.debug("_dtb: cancel error") self.error_timer.cancel() t = 5 # also change __init__ ## fixed: 5sec error screen self.error_timer = Timer(t * 1.0, self.active) dtbdebug and logger.debug("_dtb: unset instant when_held") self.button_instant.when_held = None dtbdebug and logger.debug("_dtb: unset instant when_pressed") self.button_instant.when_pressed = None dtbdebug and logger.debug("_dtb: unset delayed when_pressed") self.button_delayed.when_pressed = None def _switch_lights(self, to=False): logger.debug("_switch_lights: Switching Lights state") if to is None: # toggle self.switch_light_A.value = not self.switch_light_A.value self.switch_light_B.value = not self.switch_light_B.value elif to == True: # turn on self.switch_light_A.on() self.switch_light_B.on() else: # secure state = off self.switch_light_A.off() self.switch_light_B.off() def _fbi(self, file=None, folder=None, delay=15, random=0): logger.debug("_fbi: Displaying image") # remove all old images os.system(self.FBI_KILL) # show new image fbi = self.FBI + " --noverbose -a -T 1" if random: fbi += " -u " if folder is None: fbi += " %s " % file else: fbi += " -t %d -u %s/*" % (delay, folder) os.system(fbi) def _get_battery_level(self): logger.debug("_get_battery_level") call = "LANG=en %s --get-config /main/status/batterylevel" % self.GPHOTO out = subprocess.Popen(call, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True).communicate()[0] # analyze lines returned power = 0 cameraerror = False if out: # analyze lines returned for o in out.splitlines(): logger.debug("LINE: %s" % o) # look for battery current state mtch = re.search('Current: (\d+)%', o) if mtch: power = int(mtch.group(1)) logger.info("---- Found Battery level %i" % power) # look for error state mtch = re.search('Error: No camera found', o) if mtch: cameraerror = True logger.critical("---- Found No Camera found error") # camera error - unrecoverable: Go to maintenance if cameraerror: self.maintenance() return # battery power low? show notice for 5 seconds if power <= 15: self._fbi(file="fbi/battery.png") sleep(3) return # and do whatever was planned to do next :) return power def _take_photo(self, delay=None, rnd=0): logger.debug("_take_photo") self._dtb() # disable Timer and Buttons # tried to take a photo 3 times - something is wrong, going to error mode if (rnd == 3): logger.warn("Encountered multiple errors, stopping at 3 retries") self.error(file="fbi/error-retry.png") return # delayed picture: show countdown video if delay is None: # No countdown, just turn on lights if self.config['LIGHTS']['flash_lights']: self._switch_lights(True) # and give it a second to be sure it's on sleep(1) elif delay == 3: if self.config['LIGHTS']['flash_lights']: self._switch_lights(True) subprocess.Popen([self.OMX, "countdown/countdown3.mp4"]) sleep(3) else: subprocess.Popen([self.OMX, "countdown/countdown.mp4"]) sleep(5) # time delayed display, so that it will take a photo at 0 if self.config['LIGHTS']['flash_lights']: self._switch_lights(True) sleep(4) self.last_picture = self.config['PATHS']['storage'] + "/current.png" call = "LANG=en %s --filename %s --force-overwrite --keep-raw --capture-image-and-download --get-config /main/status/batterylevel" % ( self.GPHOTO, self.last_picture) logger.debug("starting: " + call) prc = subprocess.Popen(call, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) self._fbi(file="fbi/transfer.png") # blocking, await gphoto2 finish out = prc.communicate()[0] if self.config['LIGHTS']['flash_lights']: self._switch_lights(False) # analyze lines returned power = 0 filename = "" focuserror = False cameraerror = None if out: # analyze lines returned for o in out.splitlines(): logger.debug("LINE: %s" % o) # look for filename mtch = re.search('Deleting file .*/(DSC.*\.JPG) on the camera', o) if mtch: filename = mtch.group(1) logger.debug("---- Found filename %s" % filename) # look if camera is set to RAW mtch = re.search('Keeping file .*/(DSC.*\.NEF) on the camera', o) if mtch: logger.error("---- Camera uses RAW/NEF") cameraerror = "fbi/error-raw.png" # look for battery level mtch = re.search('Current: (\d+)%', o) if mtch: power = int(mtch.group(1)) logger.debug("---- Found Battery level %i" % power) # look for error state # no camera mtch = re.search('Error: No camera found', o) if mtch: cameraerror = "fbi/error-nocam.png" logger.error("---- Found No Camera error") # sd card problems (most likely full) mtch = re.search('PTP Store Not Available', o) if mtch: cameraerror = "fbi/storage-ptp.png" logger.error("---- Found PTP (SD Card) error") # camera does not store to SD mtch = re.search( 'New file is in location /capt0000.jpg on the camera', o) if mtch: cameraerror = "fbi/storage-sd.png" logger.error( "---- Found file location error, not storing to SD card" ) # local pi storage full mtch = re.search('write: No space left on device', o) if mtch: cameraerror = "fbi/storage-pi.png" logger.error("---- Found Storage (main or backup) error") mtch = re.search('Out of Focus', o) if mtch: focuserror = True logger.debug("---- Found Focus error") # camera error - unrecoverable: Go to maintenance if cameraerror: self._fbi(file=cameraerror) sleep(30) self.maintenance() return # focus error - try again, up to 3 times if focuserror: self._take_photo(rnd=rnd + 1) return # battery power low? show notice for 5 seconds if power <= 15: logger.warn("Low battery level: %i %" % power) self._fbi(file="fbi/battery.png") sleep(3) return if filename: # review pic # note: will not activate buttons self.review(activateButtons=False) splfile = filename.split('.') splfile.insert(len(splfile) - 1, str(uuid.uuid4())) filenameuuid = '.'.join(splfile) # copy to storage dir new_target = self.config['PATHS']['storage'] + "/" + filenameuuid try: copyfile(self.last_picture, new_target) except (OSError, IOError) as e: # if an error occurs, assume storage problem and move to maintenance logger.critical(e) self._fbi(file="fbi/storage-file.png") sleep(30) self.maintenance() return # copy to backup dir, if exists if self.config['PATHS']['backup']: new_target = self.config['PATHS']['backup'] + "/" + filenameuuid try: copyfile(self.last_picture, new_target) except (OSError, IOError) as e: # if an error occurs, assume storage problem and move to maintenance logger.critical(e) self._fbi(file="fbi/storage-backup.png") sleep(30) self.maintenance() return # copy to web last dir, if exists if self.config['PATHS']['lastweb']: new_target = self.config['PATHS'][ 'lastweb'] + "/" + filenameuuid try: copyfile(self.last_picture, new_target) # Create HTML file lw = open(self.config['PATHS']['lastweb'] + "/index.html", "w+") lw.write( '<html><body><img width="640" src="%s" /></body></html>' % filenameuuid) lw.close() except (OSError, IOError) as e: # if an error occurs, ignore. logger.critical(e) logger.critical("ignored for web") return # activate buttons in review mode self.review(buttonsOnly=True) return else: # no filename found - most likely not downloaded from camera? logger.error("no filename found in camera output") self.error(file="fbi/error-file.png") return def _take_photo_delayed(self): logger.debug("_take_photo_delayed") return self._take_photo(delay=1) def _take_photo_delayedshort(self): logger.debug("_take_photo_delayedshort") return self._take_photo(delay=3) def _delete_photo(self): logger.debug("_delete_photo") self._dtb() # disable Timer and Buttons # Sorry, never delete anything :) # But I'll mark it deleted, by moving it to another folder # TODO file handling - move to deleted folder # Display DELETED message # wait for 2 seconds so the users will notice it sleep(2) # become active afterwards self.active() def standby(self): logger.debug("standby") self._dtb() # disable Timer and Buttons self._set_state("standby") # Turn off Lights if not self.config['LIGHTS']['flash_lights']: self._switch_lights(False) # FBI slideshow "standby" folder self._fbi(folder="fbi/standby", random=1) # Wait for any key press to become active self.button_instant.when_pressed = self.active self.button_delayed.when_pressed = self.active def active(self): logger.debug("active") self._dtb() # disable Timer and Buttons self._set_state("active") # looks for battery level, will display warning, and go to maintenance if camera not found self._get_battery_level() # Turn on Lights if not self.config['LIGHTS']['flash_lights']: self._switch_lights(True) # FBI main screen self._fbi(file="fbi/active.png") # Wait for key press to init countdown / directly snap self.button_instant.when_pressed = self._take_photo_delayedshort self.button_delayed.when_pressed = self._take_photo_delayed # after self.standby minutes without state change, go to standby self.standby_timer.start() def review(self, activateButtons=True, buttonsOnly=False): logger.debug("review") if buttonsOnly == False: self._dtb() # disable Timer and Buttons # Keep lights are they were # Show picture self._fbi(file=self.last_picture) if buttonsOnly == True or activateButtons == True: # at "long?" Instant keypress, move Image to Deleted self.button_instant.when_held = self._delete_photo # at Delayede keypress or after 15sec, restart active self.button_delayed.when_pressed = self.active self.button_instant.when_pressed = self.active if buttonsOnly == False: # go to active after review time self.review_timer.start() def error(self): logger.debug("error") self._dtb() # disable Timer and Buttons self._set_state("error") # Keep lights are they were # FBI error screen self._fbi(file="fbi/error.png") # at Delay keypress or after 15sec, restart active self.button_delayed.when_pressed = self.active self.button_instant.when_pressed = self.active # go to active after review time self.error_timer.start() def maintenance(self): logger.debug("maintenance") self._dtb() # disable Timer and Buttons self._set_state("maintenance") # Turn off lights if not self.config['LIGHTS']['flash_lights']: self._switch_lights(False) # FBI slideshow "maintenance" folder self._fbi(folder="fbi/maintenance", random=1) # On DUAL keypress, output error information while 1: if self.button_instant.is_pressed and self.button_delayed.is_pressed: # TODO output error messages break sleep(0.5) # output log to console 1 os.system(self.FBI_KILL) os.system("/usr/bin/sudo /bin/cat ~pi/photobox.log >/dev/tty1") sleep(5) # to avoid instant triggering # get active on keypress self.button_instant.when_pressed = self.active self.button_delayed.when_pressed = self.active
#!/usr/bin/env python print("Loading...")\ from gpiozero import DigitalOutputDevice from time import sleep pin = DigitalOutputDevice(21) print("Turning fan on for 20 seconds, turn potentiometer to test.") pin.on() sleep(20) print("Turning fan off") pin.off() print("Exiting") pin.close() exit()
from gpiozero import DigitalOutputDevice from time import sleep sol = DigitalOutputDevice(20) sLED = DigitalOutputDevice(21) for i in range(10): sol.on() sLED.on() sleep(0.5) sol.off() sLED.off() sleep(0.5) sol.close()
class MotorControl: def __init__(self): #Define a winch carabiner height variable (meters) self.z_winch = 0 #Define winch to to climber margin of error (meters) self.WINCH_OFFSET = .05 #Define winch speed CONSTANT (meters/s) self.WINCH_SPEED = 0.1 #Define winch_in timer self.winch_in_timer = 0 #Define winch_out timer self.winch_out_timer = 0 #Define winch out switch variable (meters/s) self.winch_out = DigitalOutputDevice(23) #Define a lowering flag self.lower_flag = 0 #Define winch in switch variable (meters/s) self.winch_in = DigitalOutputDevice(25) #Deine a fall flag self.fall_flag = 0 #Define fall timer for seeing how long after a fall self.fall_timer = 0 # stop motor if above threshold self.threshhold = .5 def rotate(self, z_climber, acc): #Update the winch position if (self.winch_in.value == 1): self.z_winch = self.z_winch + self.WINCH_SPEED * ( time.time() - self.winch_in_timer) elif (self.winch_out.value == 1): self.z_winch = self.z_winch - self.WINCH_SPEED * ( time.time() - self.winch_out_timer) else: self.z_winch = self.z_winch #check if a fall has occurred if (self.fall_flag == 1): #Check the timer to see if 2 seconds has elapsed and lower climber if ((time.time() - self.fall_timer) >= 5): self.lower_flag = 1 self.fall_flag = 0 #check if lowering elif (self.lower_flag == 1): #Check if climber to winch distance is greater than 5 cm # if((z_climber - self.z_winch) > self.WINCH_OFFSET): # #turn off motor_out # self.winch_out.off(); # #Reset motor_out_timer # self.winch_out_timer = 0; # #turn on motor_in # self.winch_in.on(); # #Record motor_in_timer start time # self.winch_in_timer = time.time(); # #If at the bottom, stop the winch if (self.z_winch < self.WINCH_OFFSET): #Turn off motor_in and motor_out self.winch_in.off() #Reset motor_in_timer self.winch_in_timer = 0 self.winch_out.off() #Reset motor_out_timer self.winch_out_timer = 0 #Otherwise continue lowering else: self.winch_out.on() #Record motor_out_timer start time self.winch_out_timer = time.time() self.winch_in.off() #Reset motor_in_timer self.winch_in_timer = 0 #Normal climbing mode else: if (self.z_winch >= self.threshhold): self.winch_out.off() self.winch_out_timer = 0 self.winch_in.off() self.winch_in_timer = 0 #Check if climber is higher than winch carabiner elif ((z_climber - self.z_winch) > self.WINCH_OFFSET): #Check if motor in and out are both on if (self.winch_in.value == 1 and self.winch_out.value == 1): #Turn off winch_out self.winch_out.off() #Reset motor_out_timer self.winch_out_timer = 0 #Turn on winch_in self.winch_in.on() #Record motor_in_timer start time self.winch_out_timer = time.time() #Check if winch_in is off and motor_out is 1 elif (self.winch_in.value == 0 and self.winch_out.value == 1): #Turn off motor_out self.winch_out.off() #Reset motor_out_timer self.winch_out_timer = 0 #Turn on winch_in self.winch_in.on() #Record motor_in_timer start time self.winch_in_timer = time.time() #Check if motor in and out are off elif (self.winch_in.value == 0 and self.winch_out.value == 0): #Turn off motor_out self.winch_out.off() #Reset motor_out_timer self.winch_out_timer = 0 #Turn on motor_in self.winch_in.on() #Record motor_in_timer start time self.winch_in_timer = time.time() #Check if motor_in is on and motor_out is off elif (self.winch_in.value == 1 and self.winch_out.value == 0): #Turn off motor_out self.winch_out.off() #Reset motor_out_timer self.winch_out_timer = 0 #Turn on motor_in self.winch_in.on() #Record motor_in_timer start time self.winch_in_timer = time.time() #motor_in == 1 must always be true in this condition else: self.winch_out.off() #Reset motor_out_timer self.winch_out_timer = 0 self.winch_in.on() #Record motor_in_timer start time self.winch_in_timer = time.time() #Check if climber and winch positions are equal elif (np.abs(z_climber - self.z_winch) < self.WINCH_OFFSET): #Turn off motor_in and motor_out self.winch_in.off() #Reset winch_in_timer self.winch_in_timer = 0 self.winch_out.off() #Reset winch_out_timer self.winch_in_timer = 0 #Check if climber position is less than carabiner if (acc < -8.5 ): #((z_climber - self.z_winch) < (-1*self.WINCH_OFFSET)): #This is a fall condition we need to accomodate self.fall_flag = 1 #start fall timer self.fall_timer = time.time() #Turn off motor_in self.winch_in.off() #Record motor_in_timer start time self.winch_in_timer = 0 #Turn on motor_out self.winch_out.off() #Set winch_out_timer start time self.winch_out_timer = 0
#!/usr/bin/env python from gpiozero import DigitalOutputDevice from time import sleep rLight = DigitalOutputDevice(21,active_high=False) rLight.on() #sleep(10) #rLight.off()
from gpiozero import DigitalOutputDevice from time import sleep print("blink.py start") led_pin = DigitalOutputDevice(7) print(type(led_pin)) while True: led_pin.on() # HIGH print(led_pin.value) # Gets the state of the pin sleep(3) led_pin.off() # LOW print(led_pin.value) sleep(1)
from gpiozero import DigitalOutputDevice import time #import sys signal = DigitalOutputDevice(14) print("Running") #print(sys.argv[1]) #if(sys.argv[1] == '0'): # print("Turn off") # signal.on() #elif(sys.argv[1] == '1'): # print("Turn on") # signal.off() while True: now = time.localtime() time.sleep(60) if (now.tm_hour >= 19 or now.tm_hour < 1): signal.off() else: signal.on()
from gpiozero import DigitalOutputDevice import time winch_in = DigitalOutputDevice(25) winch_out = DigitalOutputDevice(23) winch_in.off() winch_out.off() for i in range(1): winch_out.on() time.sleep(1) winch_in.off() winch_out.off()
class PM25: def __init__(self, channel, tca, pwr_pin, num_iterations=3, precision=3): if pwr_pin is None: raise ValueError(f"must supply pwr_pin") # TODO: I'm not doing anything with the units here self.pwr_pin = DigitalOutputDevice(pwr_pin) # TODO: improve logic self.device = self._create_device(channel, tca) self.num_iterations = num_iterations self.precision = precision self.accepted_units = ["ug/m^3", "um/0.1L"] def _parse_sensor(self): self.pwr_pin.on() # NOTE: the device needs to run for 30+ seconds to initialize time.sleep(40) try: aqdata = self.device.read() except (OSError, RuntimeError) as e: print(f"ERROR!: {e}") aqdata = None vals, units = {}, {} if aqdata: # keys # reading key, unit, new_name # Particle Matter concentrations of different size particles in micro-gram per cubic meter sensor_keys = [ ("particles 03um", "03um/0.1L", "particle_03um"), ("particles 05um", "05um/0.1L", "particle_05um"), ("particles 10um", "10um/0.1L", "particle_10um"), ("particles 25um", "25um/0.1L", "particle_25um"), ("particles 50um", "50um/0.1L", "particle_50um"), ("particles 100um", "100um/0.1L", "particle_100um"), ("pm10 standard", "ug/m^3", "standard_pm10"), ("pm10 env", "ug/m^3", "env_pm10"), ("pm25 standard", "ug/m^3", "standard_pm25"), ("pm25 env", "ug/m^3", "env_pm25"), ("pm100 standard", "ug/m^3", "standard_pm100"), ("pm100 env", "ug/m^3", "env_pm100"), ] for skt in sensor_keys: vals[skt[2]] = aqdata[skt[0]] units[skt[2]] = skt[1] return vals, units def _create_device(self, channel, tca): self.pwr_pin.on() # NOTE: must allow device to be on for initialization time.sleep(2) try: device = PM25_I2C(tca[channel]) except OSError: # Try one more time self.pwr_pin.off() time.sleep(1) self.pwr_pin.on() time.sleep(2) try: device = PM25_I2C(tca[channel]) except Exception: raise OSError( f"Unable to initialize PM25 device. please double check {self.pwr_pin} is correct on/off pin" ) return device def return_value(self, **kwargs): # TODO: this is a pretty rough first cut # the units will need to be addressed more elegantly try: unit = kwargs["unit"] except KeyError: raise ValueError(f"unit not in {kwargs}") if unit: if not isinstance(unit, str): raise ValueError( f"unit ({unit}) is expected to be type {str}, not {type(unit)}" ) if unit not in self.accepted_units: raise ValueError( f"unit {unit} not currently supported. Please select from {self.accepted_units}" ) else: raise ValueError(f"`unit` is expected to exist") raw_vals = {} cur_u = {} for i in range(self.num_iterations): cur_v, cur_u = self._parse_sensor() # sleep betweek events time.sleep(10) raw_vals[f"{i}"] = cur_v self.pwr_pin.off() val_dict = average_dict(raw_vals) # format output if self.precision: for k, v in val_dict.items(): val_dict[k] = round(v, self.precision) additional_vals = { "particle_num_unit": "um/0.1L", "particle_concentration_unit": "ug/m^3", "num_iterations": self.num_iterations, } out = {**val_dict, **additional_vals} return out
from gpiozero import DigitalOutputDevice from time import sleep pinAred = DigitalOutputDevice(17) pinByellow = DigitalOutputDevice(27) pinCgreen = DigitalOutputDevice(22) pinDblack = DigitalOutputDevice(23) pinEred = DigitalOutputDevice(13) pinFyellow = DigitalOutputDevice(6) pinGgreen = DigitalOutputDevice(5) pinHblack = DigitalOutputDevice(12) pinAred.on() pinByellow.on() pinCgreen.off() pinDblack.off() pinEred.off() pinFyellow.off() pinGgreen.off() pinHblack.on() sleep(1) pinAred.close() pinByellow.close() pinCgreen.close() pinDblack.close() pinEred.close() pinFyellow.close() pinGgreen.close() pinHblack.close()
class Bot: def __init__(self): self.leftMotorEnable = PWMOutputDevice(LEFT_MOTOR_ENABLE_PIN) self.leftMotorDirection1 = DigitalOutputDevice(LEFT_MOTOR_IN1_PIN) self.leftMotorDirection2 = DigitalOutputDevice(LEFT_MOTOR_IN2_PIN) self.rightMotorEnable = PWMOutputDevice(RIGHT_MOTOR_ENABLE_PIN) self.rightMotorDirection1 = DigitalOutputDevice(RIGHT_MOTOR_IN1_PIN) self.rightMotorDirection2 = DigitalOutputDevice(RIGHT_MOTOR_IN2_PIN) self.speed = 0 self.speedLeft = 0 self.speedRight = 0 self.direction = 0 def processCommand(self, command): speed, direction = struct.unpack('>Hh', command) print(speed, direction) self.updateBot(speed, direction) def updateBot(self, speed, direction): self.speed = speed self.direction = direction if speed == 0: self.stop() else: self.speedLeft = DIRECTIONS[str(direction)][0] * (self.speed / 100) self.speedRight = DIRECTIONS[str(direction)][1] * (self.speed / 100) self.setLeftMotorSpeed(self.speedLeft) self.setRightMotorSpeed(self.speedRight) def setLeftMotorSpeed(self, speed): print('leftForwardSpeed' + str(speed)) self.leftMotorEnable.value = abs(speed) if speed > 0: self.leftMotorDirection1.on() self.leftMotorDirection2.off() else: self.leftMotorDirection1.off() self.leftMotorDirection2.on() def setRightMotorSpeed(self, speed): print('rightForwardSpeed' + str(speed)) self.rightMotorEnable.value = abs(speed) if speed > 0: self.rightMotorDirection1.on() self.rightMotorDirection2.off() else: self.rightMotorDirection1.off() self.rightMotorDirection2.on() def leftMotorStop(self): self.leftMotorEnable.off() def rightMotorStop(self): self.rightMotorEnable.off() def stop(self): self.leftMotorStop() self.rightMotorStop()
# Version: 1.0 # Library Import from gpiozero import DigitalOutputDevice # DIGITALOUTPUTDEVICE is for RELAIS from gpiozero import Button from gpiozero.pins.pigpio import PiGPIOFactory import time # IPADRES CHANGE THE GREEN TEXT TO CHANGE IP ADRES factory = PiGPIOFactory('192.168.0.112') # Setup Outputs # Relais CH1 = DigitalOutputDevice(17, True, False, pin_factory=factory) # LED's LED1 = DigitalOutputDevice(26, pin_factory=factory) # Setup Inputs # Buttons BTN1 = Button(pin=14, pull_up=False, bounce_time=0.25, pin_factory=factory) if BTN1.value == 1 and CH1.value == 0: CH1.on() LED1.on() time.sleep(0.25) if BTN1.value == 1 and CH1.value == 1: CH1.off() LED1.off() time.sleep(0.25)
class Control: controls = [] # array of all sensor instances (in order of creation for status printout) by_name = {} # dict of all controls by name by_pin = {} # dict of all controls by pin names = [] # array of control names (in order of creation for status printout) def __init__(self, pin, name, active_high=True, initial_value=False, toggle_delay=0.5): # TODO throw exception if pin not set self.name = name self.isControl = True self.device = DigitalOutputDevice(pin=pin, active_high=active_high, initial_value=initial_value) self.toggle_delay = toggle_delay Gpio.Control.controls.append(self) Gpio.Control.by_name[name] = self Gpio.Control.by_pin[pin] = self Gpio.Control.names.append(name) # Fob control magic if (name == 'fob'): self.fob_wait = self.toggle_delay + 3.0 # Delay after toggle to check for roof motion self.fob_tries = 3 # How many times we try toggling before we give up self.togglingFob = 0 # Flag to track when we're toggling def turnOn(self): self.device.on() browser.browser.updateBrowser() logging.info(printStatus()) def turnOff(self): self.device.off() browser.browser.updateBrowser() logging.info(printStatus()) def is_active(self): return(self.device.value == 1) def isOn(self): return(self.device.value == 1) def isOff(self): return(self.device.value == 0) def toggle(self, step=0): """Toggle the control ouput on then off""" if (step == 0): logging.info("Toggle {}".format(self.name)) self.turnOn(); threading.Timer(self.toggle_delay, self.toggle, [1]).start() elif (step == 1): self.turnOff(); else: logging.error("WTF? toggle() called with step %".format(step)) # Fob has speical toggle magic to ensure the roof starts moving def toggleFob(self, step=0): """Toggle fob and check for roof movement, retrying up to fob_tries times""" if (self.name != 'fob'): logging.error("toggleFob() called for {}".format(self.name)) return(-1) if (step == 0 and self.togglingFob): logging.error("toggleFob() called while toggling already in progress") return(-1) # If roof is middle just revert to toggle if (step == 0 and Gpio.open.roofPosition() == roof.MIDWAY): self.togglingFob = 0 self.toggle() return(0) # If we're a scheduled callback check for status if (step > 0 and Gpio.open.roofPosition() == roof.MIDWAY): browser.browser.sendNotice("Roof is midway") logging.info("toggleFob() detected roof movement") self.togglingFob = 0 return(0) # Bail after x tries if (step >= self.fob_tries): browser.browser.sendNotice("No roof movement; giving up") logging.error("toggleFob() failed to detect movement after {} tries; giving up".format(step)) self.togglingFob = 0 return(1) # Toggle and schedule a callback to check for movement if (step > 0): browser.browser.sendNotice("Retrying fob ({}/{})".format(step+1, self.fob_tries)) self.togglingFob = 1 # Should we use a timestamp so we can "expire" just in case? self.toggle() logging.info("toggleFob({}) waiting {} seconds".format(step, self.fob_wait)) threading.Timer(self.fob_wait, self.toggleFob, [step+1]).start() return(0)
Setup GPIO 17 as digital output """ fan_switch = DigitalOutputDevice(17, True, False) def fan_on(): print("turning fan on") fan_switch.on() def fan_off(): print("turning fan off") fan_switch.off() from gpiozero import CPUTemperature from time import sleep fan = DigitalOutputDevice(17) TEMP_TH = 40.0 # CPU Temp threshold (C)) cpu = CPUTemperature() if (cpu.temperature > TEMP_TH): print("turning fan on") fan.on() sleep(5) else: print("turning fan off") fan.off()
def motor_jog(current_step, velocity = 3200, acceleration = 2000, steps = 1600, absolute = False): # velocity in steps/s, acceleration in steps/s^2 # defines pin numbers pulse_pin = DigitalOutputDevice(24) direction_pin = DigitalOutputDevice(25) enable_pin = DigitalOutputDevice(22) # sets correct direction pin voltage and enables the enable pin enable_pin.on() if absolute: target_step = steps multiplier = np.sign(steps - current_step) else: target_step = current_step + steps multiplier = np.sign(steps) steps = np.abs(steps) if multiplier == 1: direction_pin.off() elif multiplier == -1: direction_pin.on() # creates loop variables jog_steps = [] jog_times = [] current_velocity = 100 initial_step = current_step acceleration_steps = velocity**2/(2*acceleration) # approx. num. of steps taken during acceleration current_time = time.perf_counter() try: #steps forward at the appropriate time while current_step != target_step: #turn pulse pin on and get current time last_time = current_time current_time = time.perf_counter() pulse_pin.on() dt = current_time - last_time ## calculate delay time to next step half_over = np.absolute(current_step - initial_step) > np.absolute(target_step - current_step) # are we more than half done travelling? # if we are still accelerating, increase current_velocity if (current_velocity != velocity and not half_over): current_velocity = min(velocity, current_velocity + acceleration * max(dt,1E-7)) # if we are decelerating, decrease current_velocity elif (np.absolute(target_step - current_step) < acceleration_steps != velocity and half_over): current_velocity = max(100, current_velocity - acceleration * dt) # each step takes 1/current_velocity time (in s) delay = 1/current_velocity # save values jog_times.append(current_time) # save current time current_step = current_step + multiplier # calculate current step jog_steps.append(current_step) # save current step # WAIT to turn pulse pin off, then wait again better_sleep(delay/2, current_time) # turn pulse pin off, WAIT pulse_pin.off() better_sleep(delay, current_time) # done with movement, so we turn the enable pin off enable_pin.off() except KeyboardInterrupt: print("\nUser exit during motor usage. Powering down.\n") pulse_pin.off() enable_pin.off() sys.exit(0) return jog_steps, jog_times, current_step
time.sleep(.1) state = 0 latitude = 0.0 longitude = 0.0 while(1): try: blynk.run() print(sensor.readThermistor()) if sensor.readThermistor() > 40.0 and mq_sensor.value == 1 and state == 0: print("Fire Alert") blynk.virtual_write(0, 1, latitude, longitude, "Fire_location") blynk.virtual_write(1, latitude) blynk.virtual_write(2, longitude) blynk.notify("Fire Alert") sprinkler.on() state = 1 elif sensor.readThermistor() < 40.0 and mq_sensor.value == 0 : sprinkler.off() state = 0 data = gps.readline() data_str = data.decode('ascii') message = data[0:6] if (message == "$GPRMC"): parts = data.split(",") if parts[2] == "V": print("GPS receiver warning") else: longitude = float(formatDegreesMinutes(parts[5], 3)) latitude = float(formatDegreesMinutes(parts[3], 2)) print("Your position: lon = " + str(longitude) + ", lat = " + str(latitude))
class Motor: def __init__(self, ain1=None, ain2=None, bin1=None, bin2=None, pwma=None, pwmb=None): print("init") self.ain1 = DigitalOutputDevice(ain1, initial_value=False) self.ain2 = DigitalOutputDevice(ain2, initial_value=False) self.bin1 = DigitalOutputDevice(bin1, initial_value=False) self.bin2 = DigitalOutputDevice(bin2, initial_value=False) self.pwma = PWMOutputDevice(pwma, initial_value=.5) self.pwmb = PWMOutputDevice(pwmb, initial_value=.5) def stop(self): print("stop") self.ain1.off() self.ain2.off() self.bin1.off() self.bin2.off() def forward(): print("forward") self.ain1.on() self.ain2.off() self.bin1.on() self.bin2.off() def backward(): print("backward") self.ain1.off() self.ain2.on() self.bin1.off() self.bin2.on() def turn_left(): print("turn_left") self.ain1.off() self.ain2.on() self.bin1.on() self.bin2.off() def turn_right(): print("turn_right") self.ain1.on() self.ain2.off() self.bin1.off() self.bin2.on()