Docs
Software Code:
1 # analog_in.py
2 # This file declares a class to use analog GPIO pins as inputs
3
4
5 # importing libraries
6 import Adafruit_BBIO.ADC as ADC
7
8
9 class Analog_In:
10
11 def __init__(self, pin):
12 # pin: dictionary containing used input pin
13 self.sig = pin["ain"]
14 ADC.setup()
15
16 def read(self):
17 # function: read normalized analog value
18 # function returns: float number from 0.0 to 1.0
19 return ADC.read(self.sig)
20
21 def read_raw(self):
22 # function: read raw analog value
23 # function returns: float number from 0.0 to 4095.0
24 return ADC.read_raw(self.sig)
1 # config.py
2 # This file list all used pins for blood smearing device
3 # Note: please leave pin labels alone, other files depend on those specific labels
4
5
6 # active output pins for linear guide
7 # "ena": digital LOW enables pulses to be sent
8 # digital HIGH disables pulses
9 # "dir": digital LOW for ccw rotation
10 # digital HIGH for cw rotation
11 # "pul": digital HIGH then LOW turns motor one step
12 slide_pins = {"ena": "P8_11", "dir": "P8_15", "pul": "P8_17"}
13
14 # active digital input pin for home (opposite side of stepper motor) limit switch
15 limit_home_pin = {"sig": "P9_11"}
16
17 # active digital input pin for end (same side as stepper motor) limit switch
18 limit_end_pin = {"sig": "P9_12"}
19
20 # active digital output pin for activating drying fan
21 fan_pin = {"sig": "P8_16"}
22
23 # active output pulse pin for blade ejection linear servo
24 linear_pin = {"pul": "P9_14"} # 6V
25
26 # active output pulse pin for blade ejection pulley servo
27 pulley_pin = {"pul": "P9_16"} # 6V
28
29 # active output pulse pin for blade ejection rotation servo
30 rotation_pin = {"pul": "P8_19"} # 6V
31
32 # active output power and input analog pins for force sensor
33 force_pins = {"sig": "P8_21", "ain": "P9_33"}
1 # digital_io.py
2 # This file declares a class to use digital GPIO pins as inputs/outputs
3
4
5 # importing libraries
6 import Adafruit_BBIO.GPIO as GPIO
7 import numpy as np
8 import time
9
10
11 class Digital_Io:
12
13 # class initialization also initializes pin
14 def __init__(self, pin, direction, value=None):
15 # pin: dictionary containing used input/output pin
16 # direction: string "in" to set up pin as an input or
17 # string "out" to set up pin as an output
18 # value: int 0 for initial LOW output or
19 # int 1 for initial HIGH output
20 self.sig = pin["sig"]
21 if direction == "in":
22 self.dir = GPIO.IN
23 GPIO.setup(self.sig, self.dir)
24 elif direction == "out":
25 self.dir = GPIO.OUT
26 if value == 0:
27 GPIO.setup(self.sig, self.dir, initial=GPIO.LOW)
28 elif value == 1:
29 GPIO.setup(self.sig, self.dir, initial=GPIO.HIGH)
30 else:
31 print("\nError: Invalid value input")
32 else:
33 print("\nError: Invalid string direction input (\"in\" or \"out\"")
34 print("\"in\" for input pin or \"out\" for output pin")
35 print("Please include quotation marks")
36
37 def read(self):
38 # function: read input voltage as HIGH or LOW
39 # function returns: int 0 when nothing is detected and
40 # int 1 when sensor is triggered
41 return GPIO.input(self.sig)
42
43 def output(self, value):
44 # function: output 3.3V or 0V
45 # value: int 0 outputs 0V or
46 # int 1 outputs 3.3V
47 if value == 0:
48 GPIO.output(self.sig, GPIO.LOW)
49 elif value == 1:
50 GPIO.output(self.sig, GPIO.HIGH)
51 else:
52 print("\nError: Invalid value input")
53
54 def add_event(self, edge):
55 # function: add event detection
56 # edge: string "rise" to detect rising edge
57 # string "fall" to detect falling edge
58 # string "both" to detect both edges
59 if edge == "rise":
60 self.edge = GPIO.RISING
61 GPIO.add_event_detection(self.sig, self.edge)
62 elif edge == "fall":
63 self.edge = GPIO.FALLING
64 GPIO.add_event_detection(self.sig, self.edge)
65 elif edge == "both":
66 self.edge = GPIO.BOTH
67 GPIO.add_event_detection(self.sig, self.edge)
68 else:
69 print("Error: Invalid string edge input")
70 print("\"rise\" for rising edge")
71 print("\"fall\" for falling edge")
72 print("\"both\" for both edges")
73 print("Please add quotation marks")
74
75 def event(self):
76 # function: detect event
77 # function returns: bool True if edge is detected or
78 # bool False otherwise
79 return GPIO.event_detected(self.sig)
80
81 def wait(self):
82 # function: wait for event
83 GPIO.wait_for_edge(self.sig, self.edge)
84
85 def remove_event(self):
86 # function: remove event detection
87 GPIO.remove_event_detect(self.sig)
88
89 def read2(self, num_samples, correct_samples, frequency):
90 # function: read input by many samples
91 # num_samples: int number of samples
92 # correct_samples: int number of correct samples
93 # frequency: float number sampling rate in [Hz]
94 # function returns: bool True if read input is correct
95 # bool False if read input is incorrect
96 num_samples = int(num_samples)
97 correct_samples = int(correct_samples)
98 if correct_samples > num_samples:
99 print("Error: correct_samples cannot be higher than num_samples")
100 samples = np.array([0] * num_samples)
101 sleepTime = float(1 / frequency)
102 for i in range(num_samples):
103 samples[i] = self.read()
104 time.sleep(sleepTime)
105 if np.sum(samples) >= correct_samples:
106 return True
107 else:
108 return False
109
110 def cleanup(self):
111 # function: clean up pin
112 GPIO.remove_event_detect(self.sig)
113 GPIO.cleanup()
1 # servo.py
2 # This file declares a class to use any servo motor
3
4
5 # importing libraries
6 import Adafruit_BBIO.PWM as PWM
7 import time
8
9
10 class Servo:
11
12 def __init__(self, pin, angle_range=180):
13 # pin: dictionary containing used servo PWM pin
14 # angle_range: float number describing the max angle range of a servo
15 # motor [degrees], by default 180 degrees
16 self.pul = pin["pul"]
17 self.range = angle_range
18
19 def start(self, duty_min, duty_max, frequency=50, polarity=0):
20 # function: start/initialize servo
21 # duty_min: float PWM duty cycle for 0 [degrees]
22 # duty_max: float PWM duty cycle for angle range [degrees]
23 # frequency: float PWM frequency [Hz], must be > 0, by default 50Hz
24 # polarity: int defines whether the duty affects the PWM waveform
25 # by default 0 (rising edge), 1 (falling edge)
26 self.min = float(duty_min)
27 self.max = float(duty_max)
28 self.span = duty_max - duty_min
29 duty = self.min
30 PWM.start(self.pul, duty, frequency, polarity)
31
32 def update_duty(self, duty):
33 # function: change servo duty cycle
34 # duty: float PWM duty cycle from 0-100
35 PWM.set_duty_cycle(self.pul, duty)
36
37 def update_angle(self, angle):
38 # function: set servo angle
39 # angle: float servo angle from (0, max) [degrees]
40 duty = angle * self.span / self.range + self.min
41 self.update_duty(duty)
42
43 def change_angle(self, start, end, time2turn=2):
44 # function: move servo from a start angle to an end angle
45 # start: float number for starting angle position [degrees]
46 # end: float number for ending angle position [degrees]
47 # time2turn: float number for total time for servo to move
48 diff = abs(end - start)
49 time_sleep = time2turn / diff
50 if end > start:
51 angle = start
52 while angle <= end:
53 self.update_angle(angle)
54 time.sleep(time_sleep)
55 angle += 1
56 else:
57 angle = end
58 while angle >= start:
59 self.update_angle(angle)
60 time.sleep(time_sleep)
61 angle -= 1
62
63 def disable(self):
64 # function: disable servo motor
65 PWM.stop(self.pul)
66
67 def cleanup(self):
68 # function: cleanup servo PWM pin
69 PWM.stop(self.pul)
70 PWM.cleanup()
1 # stepper.py
2 # This file declares a class to use any stepper motor
3
4
5 # importing libraries
6 import Adafruit_BBIO.GPIO as GPIO
7 import time
8 from math import pi
9
10
11 class Stepper:
12
13 # class initialization also initializes motor
14 def __init__(self, pins, circumference, microstep=8):
15 # pins: dictionary containing used stepper motor pins
16 # circumference: float number for distance traveled by one motor
17 # revolution
18 # microstep: int number for current microstep configuration for
19 # stepper motor, by default microstep is 8
20 self.ena = pins["ena"]
21 self.dir = pins["dir"]
22 self.pul = pins["pul"]
23 self.circum = circumference
24 self.radius = self.circum / (pi * 2)
25 self.mms2rpm = 30 / (self.radius * pi)
26 self.micro = microstep
27 if microstep == 1:
28 self.pulses = 200 # 1 micro step = 200 pulses
29 elif microstep == 2:
30 self.pulses == 400 # 2 micro steps = 400 pulses
31 elif microstep == 4:
32 self.pulses = 800 # 4 micro steps = 800 pulses
33 elif microstep == 8:
34 self.pulses = 1600 # 8 micro steps = 1600 pulses
35 elif microstep == 10:
36 self.pulses = 2000 # 10 micro steps = 2000 pulses
37 elif microstep == 16:
38 self.pulses = 3200 # 16 micro steps = 3200 pulses
39 elif microstep == 32:
40 self.pulses = 6400 # 32 micro steps = 6400 pulses
41 else:
42 print("Error: Invalid micro step value")
43 GPIO.setup(self.pul, GPIO.OUT, initial=GPIO.LOW)
44 GPIO.setup(self.dir, GPIO.OUT)
45 GPIO.setup(self.ena, GPIO.OUT, initial=GPIO.LOW)
46
47 def step(self):
48 # function: step motor
49 GPIO.output(self.pul, GPIO.HIGH)
50
51 def stop(self):
52 # function: stop stepping motor
53 GPIO.output(self.pul, GPIO.LOW)
54
55 def set_direction(self, direction):
56 # function: set motor rotation direction
57 # direction: string "cw" for clockwise rotation or
58 # string "ccw" for counter-clockwise rotation
59 if direction == "cw":
60 GPIO.output(self.dir, GPIO.HIGH)
61 elif direction == "ccw":
62 GPIO.output(self.dir, GPIO.LOW)
63 else:
64 print(
65 "Error: Invalid direction sting [\"cw\" for cw or \"ccw\" for ccw]")
66 print("Please include quotation marks")
67
68 def convert_mms2rpm(self, mms):
69 # function: convert linear velocity [mm/s] to rotational velocity [rpm]
70 # mms: float number of motor load's linear velocity [mm/s]
71 # function return: float number to motor's rotational velocity [rpm]
72 return (mms * self.mms2rpm)
73
74 def rotate(self, rotations, rpm, direction):
75 # function: move motor by rotations
76 # rotations: float number of motor rotations
77 # rpm: float number of motor's rpm
78 # direction: string "cw" for clockwise or
79 # string "ccw" for counter-clockwise
80 sleep_time = float(0.3 * 1.34 / (rpm * self.micro))
81 steps = round(rotations * self.pulses)
82 if direction == "cw":
83 GPIO.output(self.dir, GPIO.HIGH)
84 for x in range(steps):
85 self.step()
86 time.sleep(sleep_time)
87 GPIO.output(self.pul, GPIO.LOW)
88 elif direction == "ccw":
89 GPIO.output(self.dir, GPIO.LOW)
90 for x in range(steps):
91 self.step()
92 time.sleep(sleep_time)
93 GPIO.output(self.pul, GPIO.LOW)
94 else:
95 print(
96 "Error: Invalid direction sting [\"cw\" for cw or \"ccw\" for ccw]")
97 print("Please include quotation marks")
98
99 def move_steps(self, numberOfSteps, rpm, direction):
100 # function: move motor by amount of steps
101 # numberOfSteps: int number of steps motor will turn
102 # rpm: float number of motor's rpm
103 # direction: string "cw" for clockwise or
104 # string "ccw" for counter-clockwise
105 rotations = numberOfSteps / self.pulses
106 self.rotate(rotations, rpm, direction)
107
108 def move_linear(self, distance, rpm, direction):
109 # function: move motor with respect to linear load distance
110 # distance: float number of motor's linear distance to travel [mm]
111 # rpm: float number of motor's rpm [rpm]
112 # direction: string "cw" for clockwise or
113 # string "ccw" for counter-clockwise
114 rotations = distance / self.circum
115 self.rotate(rotations, rpm, direction)
116
117 def disable_pulse(self):
118 # function: disable motor from sending pulses
119 GPIO.output(self.ena, GPIO.HIGH)
120
121 def enable_pulse(self):
122 # function: enable motor to send pulses
123 GPIO.output(self.ena, GPIO.LOW)
124
125 def cleanup(self):
126 # function: cleanup up pins from use
127 self.disable_pulse()
128 GPIO.cleanup()
PCB Circuit Traces: