├── FIR.py
├── LICENSE
├── MAX31865.py
├── MAX31885.py
├── MAX6675.py
├── PDM.py
├── PID.py
├── SPI.py
├── lcd.py
├── main.py
├── robocam
├── .DS_Store
├── .idea
│ ├── .name
│ ├── encodings.xml
│ ├── misc.xml
│ ├── modules.xml
│ ├── robocam.iml
│ ├── scopes
│ │ └── scope_settings.xml
│ ├── vcs.xml
│ └── workspace.xml
├── main.py
└── pyboard
│ └── main.py
└── rotary.py
/FIR.py:
--------------------------------------------------------------------------------
1 | __author__ = 'beau'
2 |
3 | import array
4 | class FIR():
5 | """
6 | Finit impulse response filter, aka moving average.
7 | """
8 | def __init__(self, window_size=30,div=1):
9 | self.div = div
10 | self.win_size = window_size
11 | self.a = array.array('l', window_size * [0]) # no double on pyboard? integers logic for now
12 | self.arr_position = 0
13 | self.sum = 0
14 |
15 | def push(self, value):
16 | old_val = self.a[self.arr_position]
17 | self.a[self.arr_position] = value
18 | self.arr_position += 1
19 | self.arr_position %= self.win_size
20 | self.sum -= old_val
21 | self.sum += value
22 |
23 | def get_value(self):
24 | return self.sum / self.win_size / self.div
25 |
26 | def median(self):
27 | return sorted(self.a)[int(self.win_size/2)]
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
167 |
--------------------------------------------------------------------------------
/MAX31865.py:
--------------------------------------------------------------------------------
1 | __author__ = 'beau'
2 | import pyb
3 | import SPI
4 | import math
5 | import FIR
6 |
7 |
8 | class MAX31865():
9 | def __init__(self,DRDY_pin='X9'):
10 | self.spi = SPI.SPI()
11 | self.fir = FIR.FIR(16)
12 |
13 | """
14 | Configuration bits:
15 | Vbias 1=on
16 | Conversion mode 1=auto,0=normally off
17 | 1-shot 1=1-shot (auto-clear)
18 | 3-wire 1=3-wire,0=2/4 wire
19 | Fault detection
20 | Fault detection
21 | Fault Status 1=clear
22 | Filter 1=50Hz,2=60Hz
23 | """
24 |
25 | config = 0b11000011
26 |
27 | buf = bytearray(2)
28 | buf[0] = 0x80 #configuration write addr
29 | buf[1] = config
30 | self.spi.write(buf)
31 |
32 | self.RefR = 100.0325 #RefR/2
33 |
34 | self.last_read_time = 0
35 | self.last_read_temp = 0
36 | self.last_FIR = 0
37 |
38 |
39 | self.conversion_time = 22 #21ms for 50Hz, 17.6 for 60Hz
40 |
41 |
42 | def _RawToTemp(self,raw):
43 | R0 = raw/(1<<15)*200
44 | R0 = R0/self.RefR*100
45 | if R0==0:
46 | return -1,0
47 | #ITS-90 IEC751 Pt-100 coefficients
48 | A = 3.90830e-3
49 | B = -5.77500e-7
50 | return (A - math.sqrt(A*A - 4*B*(1-100/R0) ) ) / (2*B),R0
51 |
52 | def read(self):
53 | if pyb.millis()-self.last_read_time > self.conversion_time:
54 | temp,avg_temp = self._read()
55 | self.last_read_temp = temp
56 | self.last_FIR = avg_temp
57 | return self.last_read_temp,self.last_FIR
58 |
59 |
60 | def _read(self):
61 |
62 | #read config
63 | #config = self.spi.read(0x00,1)[0]
64 | #print ("Config:"+str(bin(config)[2:]))
65 |
66 | #read data
67 | MSB = self.spi.read(0x01,1)[0]
68 | LSB = self.spi.read(0x02,1)[0]
69 |
70 | MSB = MSB<<8
71 | raw = MSB+LSB
72 | raw = raw>>1 #remove fault bit
73 |
74 |
75 |
76 |
77 | self.fir.push(raw)
78 | temp,R0 = self._RawToTemp(raw)
79 | avg_temp,avg_R0 = self._RawToTemp(self.fir.median())
80 |
81 | return temp,avg_temp
82 |
83 |
--------------------------------------------------------------------------------
/MAX31885.py:
--------------------------------------------------------------------------------
1 | __author__ = 'beau'
2 |
3 | import pyb
4 | from FIR import FIR
5 |
6 | class MAX31885():
7 |
8 | def __init__(self,CS_pin='Y5',SO_pin='Y7',SCK_pin='Y6'):
9 | #Thermocouple
10 | self.CS_pin = pyb.Pin(CS_pin, pyb.Pin.OUT_PP)
11 | self.CS_pin.high()
12 |
13 | self.SO_pin = pyb.Pin(SO_pin, pyb.Pin.IN)
14 | self.SO_pin.low()
15 |
16 | self.SCK_pin = pyb.Pin(SCK_pin, pyb.Pin.OUT_PP)
17 | self.SCK_pin.low()
18 |
19 | self.last_read_time = 0
20 | self.last_read_room_temp = 0
21 | self.last_read_tc_temp = 0
22 | self.fault = 0
23 | self.open_circuit = 0
24 | self.short_to_gnd = 0
25 | self.short_to_vcc = 0
26 |
27 | self.FIR = FIR(window_size=16,div=8)
28 |
29 |
30 | def read(self):
31 | # self.CS_pin.low()
32 | # pyb.delay(2)
33 | # self.CS_pin.high()
34 | # pyb.delay(220)
35 |
36 | #check if new reading should be available
37 | #if True:
38 | if pyb.millis()-self.last_read_time > 100:
39 |
40 | #/*
41 | # Bring CS pin low to allow us to read the data from
42 | # the conversion process
43 | #*/
44 | self.CS_pin.low()
45 |
46 | #
47 | # Read bits D[31:18] for the Temp. Loop for each bit reading
48 | # the value and storing the final value in 'temp'
49 | #
50 | tc_temp = 0
51 |
52 | self.SCK_pin.high()
53 | sign = self.SO_pin.value()
54 | self.SCK_pin.low()
55 | for i in range(13):
56 | self.SCK_pin.high()
57 | read = self.SO_pin.value()
58 | read = (read << 13 - i)
59 | tc_temp += read
60 | self.SCK_pin.low()
61 | if sign == 1:
62 | tc_temp*=-1
63 | self.FIR.push(tc_temp)
64 | tc_temp/=8.0
65 |
66 |
67 |
68 | # D17 dummy
69 | self.SCK_pin.high()
70 | pyb.delay(1)
71 | self.SCK_pin.low()
72 |
73 | # D16 fault
74 | self.SCK_pin.high()
75 | self.fault = self.SO_pin.value()
76 | self.SCK_pin.low()
77 |
78 |
79 | # D15-D4
80 | # Roomtemp, signed
81 | self.SCK_pin.high()
82 | sign = self.SO_pin.value()
83 | self.SCK_pin.low()
84 | room_temp = 0
85 | for i in range(11):
86 | self.SCK_pin.high()
87 | read = self.SO_pin.value()
88 | read = (read << 11 - i)
89 | room_temp += read
90 | self.SCK_pin.low()
91 | if sign == 1:
92 | room_temp*=-1
93 | room_temp/=32.0
94 |
95 | # D3 dummy
96 | self.SCK_pin.high()
97 | pyb.delay(1)
98 | self.SCK_pin.low()
99 |
100 | # D2 fault
101 | self.SCK_pin.high()
102 | self.short_to_vcc = self.SO_pin.value()
103 | self.SCK_pin.low()
104 |
105 | # D1 fault
106 | self.SCK_pin.high()
107 | self.short_to_gnd = self.SO_pin.value()
108 | self.SCK_pin.low()
109 |
110 | # D0 fault
111 | self.SCK_pin.high()
112 | self.open_circuit = self.SO_pin.value()
113 | self.SCK_pin.low()
114 |
115 |
116 |
117 | self.CS_pin.high()
118 |
119 |
120 | self.last_read_time = pyb.millis()
121 | self.last_read_room_temp = room_temp
122 | self.last_read_tc_temp = tc_temp
123 |
124 |
125 | return tc_temp,room_temp
126 |
127 | #to soon for new reading
128 | else:
129 | return self.last_read_tc_temp,self.last_read_room_temp
--------------------------------------------------------------------------------
/MAX6675.py:
--------------------------------------------------------------------------------
1 | __author__ = 'beau'
2 |
3 | import pyb
4 | from FIR import FIR
5 |
6 | class MAX6675():
7 |
8 | def __init__(self,CS_pin='Y8',SO_pin='Y7',SCK_pin='Y6'):
9 | #Thermocouple
10 | self.CS_pin = pyb.Pin(CS_pin, pyb.Pin.OUT_PP)
11 | self.CS_pin.high()
12 |
13 | self.SO_pin = pyb.Pin(SO_pin, pyb.Pin.IN)
14 | self.SO_pin.low()
15 |
16 | self.SCK_pin = pyb.Pin(SCK_pin, pyb.Pin.OUT_PP)
17 | self.SCK_pin.low()
18 |
19 | self.last_read_time = 0
20 | self.last_read_temp = 0
21 | self.last_error_tc = 0
22 |
23 | self.FIR = FIR(20)
24 |
25 |
26 | def read(self):
27 | # self.CS_pin.low()
28 | # pyb.delay(2)
29 | # self.CS_pin.high()
30 | # pyb.delay(220)
31 |
32 | #check if new reading should be available
33 | #if True:
34 | if pyb.millis()-self.last_read_time > 220:
35 |
36 | #/*
37 | # Bring CS pin low to allow us to read the data from
38 | # the conversion process
39 | #*/
40 | self.CS_pin.low()
41 |
42 | #/* Cycle the clock for dummy bit 15 */
43 | self.SCK_pin.high()
44 | pyb.delay(1)
45 | self.SCK_pin.high()
46 |
47 | #/*
48 | # Read bits 14-3 from MAX6675 for the Temp. Loop for each bit reading
49 | # the value and storing the final value in 'temp'
50 | # */
51 | value = 0
52 | for i in range(12):
53 | self.SCK_pin.high()
54 | read = self.SO_pin.value()
55 | read = (read << 12 - i)
56 | value += read
57 | self.SCK_pin.low()
58 |
59 |
60 | #/* Read the TC Input inp to check for TC Errors */
61 | self.SCK_pin.high()
62 | error_tc = self.SO_pin.value()
63 | self.SCK_pin.low()
64 |
65 | # /*
66 | # Read the last two bits from the chip, faliure to do so will result
67 | # in erratic readings from the chip.
68 | # */
69 | for i in range(2):
70 | self.SCK_pin.high()
71 | pyb.delay(1)
72 | self.SCK_pin.low()
73 |
74 | self.CS_pin.high()
75 |
76 | self.FIR.push(value)
77 | temp = (value * 0.25)
78 | self.last_read_time = pyb.millis()
79 | self.last_read_temp = temp
80 | self.last_error_tc = error_tc
81 |
82 | return temp,error_tc
83 |
84 | #to soon for new reading
85 | else:
86 | return self.last_read_temp,self.last_error_tc
--------------------------------------------------------------------------------
/PDM.py:
--------------------------------------------------------------------------------
1 | __author__ = 'beau'
2 |
3 | import pyb
4 |
5 | class PDM():
6 | def __init__(self,pout='X11',tim=4,freq=50):
7 | """
8 | :param pout: output pin nr
9 | :param tim: timer number
10 | :param freq: frequency of the bitstream
11 | """
12 | self.max = 2**24-1#2**31-1 crashes with larger ints? 24bit resolution is fine enough ;)
13 |
14 | self.pout = pyb.Pin(pout, pyb.Pin.OUT_PP)
15 |
16 | self.err = 0 # error accumulator
17 | self.output = 0
18 |
19 | self.freq = freq
20 |
21 | self.tim = pyb.Timer(tim)
22 | self.tim.init(freq=freq)
23 | self.tim.callback(lambda t: self.call_me())
24 |
25 | def set_output(self,out):
26 | """
27 | :param out: desired output as a value between 0 and 1
28 | """
29 | print ('setting output to '+str(out))
30 | self.tim.deinit()
31 |
32 | self.output = int(self.max*out)
33 |
34 | self.tim.init(freq=self.freq)
35 | self.tim.callback(lambda t: self.call_me())
36 |
37 | def call_me(self):
38 | if self.err >= 0:
39 | self.pout.low()
40 | self.err -= self.output
41 | else:
42 | self.pout.high()
43 | self.err += self.max
44 | self.err -= self.output
--------------------------------------------------------------------------------
/PID.py:
--------------------------------------------------------------------------------
1 | __author__ = 'beau'
2 | import pyb
3 | class PID:
4 | """
5 | Discrete PID control
6 | """
7 |
8 | def __init__(self,input_fun,output_fun, P=3., I=0.01, D=0.0):
9 |
10 | self.Kp=P
11 | self.Ki=I
12 | self.Kd=D
13 |
14 | self.I_value = 0
15 | self.P_value = 0
16 | self.D_value = 0
17 |
18 | self.I_max=100.0
19 | self.I_min=0
20 |
21 | self.set_point=0.0
22 |
23 | self.prev_value = 0
24 |
25 | self.output = 0
26 |
27 | self.output_fun = output_fun
28 | self.input_fun = input_fun
29 |
30 | self.last_update_time = pyb.millis()
31 |
32 |
33 | def update(self):
34 |
35 | if pyb.millis()-self.last_update_time > 500:
36 | """
37 | Calculate PID output value for given reference input and feedback
38 | """
39 | current_value = self.input_fun()
40 | self.error = self.set_point - current_value
41 | print ('temp '+str(current_value))
42 | print ('SP'+str(self.set_point))
43 |
44 | self.P_value = self.Kp * self.error
45 | self.D_value = self.Kd * ( current_value-self.prev_value)
46 |
47 |
48 | lapsed_time = pyb.millis()-self.last_update_time
49 | lapsed_time/=1000. #convert to seconds
50 | self.last_update_time = pyb.millis()
51 |
52 |
53 |
54 |
55 |
56 | self.I_value += self.error * self.Ki
57 |
58 | if self.I_value > self.I_max:
59 | self.I_value = self.I_max
60 | elif self.I_value < self.I_min:
61 | self.I_value = self.I_min
62 |
63 | self.output = self.P_value + self.I_value - self.D_value
64 |
65 | if self.output<0:
66 | self.output = 0.0
67 | if self.output>100:
68 | self.output = 100.0
69 |
70 | print("Setpoint: "+str(self.set_point))
71 | print("P: "+str(self.P_value))
72 | print("I: "+str(self.I_value))
73 | print("Output: "+str(self.output))
74 | print ()
75 |
76 | self.output_fun(self.output/100.0)
77 |
78 | self.last_update_time=pyb.millis()
79 |
--------------------------------------------------------------------------------
/SPI.py:
--------------------------------------------------------------------------------
1 | __author__ = 'beau'
2 |
3 | import pyb
4 |
5 | class SPI():
6 | def __init__(self,CS_pin='X10',SCK_pin='Y6',MISO_pin='Y7',MOSI_pin='Y8',delay=10):
7 | self.CS = pyb.Pin(CS_pin, pyb.Pin.OUT_PP)
8 | self.CS.high()
9 |
10 | self.MISO = pyb.Pin(MISO_pin,pyb.Pin.IN)
11 | self.MOSI = pyb.Pin(MOSI_pin,pyb.Pin.OUT_PP)
12 |
13 | self.SCK = pyb.Pin(SCK_pin, pyb.Pin.OUT_PP)
14 | self.delay = delay
15 |
16 |
17 |
18 | def write(self,data):
19 | self.CS.low()
20 | pyb.udelay(self.delay)
21 | self._write(data)
22 | self.CS.high()
23 |
24 | def read(self,read_addr,nr_bytes):
25 | buf = bytearray(1)
26 | buf[0]=read_addr
27 | self.CS.low()
28 | pyb.udelay(self.delay)
29 | self._write(buf)
30 | result = self._read(nr_bytes)
31 | self.CS.high()
32 | return result
33 |
34 | def _read(self,nr_bytes):
35 | buf = bytearray(nr_bytes)
36 |
37 | for b in range(nr_bytes):
38 | byte = 0
39 | for i in range(8):
40 | self.SCK.high()
41 | pyb.udelay(self.delay)
42 | read = self.MISO.value()
43 | read = (read << 8 - i)
44 | byte += read
45 | self.SCK.low()
46 | pyb.udelay(self.delay)
47 | buf[b]=byte
48 |
49 | return buf
50 |
51 | def _write(self,data):
52 | msb = 0b10000000
53 |
54 | for byte in data:
55 | bits = [(byte<
2 |
3 |
4 |
--------------------------------------------------------------------------------
/robocam/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/robocam/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/robocam/.idea/robocam.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/robocam/.idea/scopes/scope_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/robocam/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/robocam/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
56 |
57 |
58 |