Module main

Functions

def captureInputs() ‑> object
Expand source code
def captureInputs() -> object: # need to capture max 3 inputs, 2 have defaults
        '''Captures command line parameters provided by the user when calling the script. 
        For example:
        
        ```bash
        python3 main.py --path "./config.json" --ylims 30, 100 --window 100
        ```
        
        Parameters
        ----------
        path : str
                Optional parameter to set path to the JSON configuration file for the controller
        
        ylims: list(float)
                Optional parameter to set the maximum and minimum values of Y axis.
        
        window : float
                Optional parameter to set the width of the X axis time window. 
        
        nsamples : int
                Optional parameter for the number of data samples used to initially configure the plots. \
                Must be larger than zero. 
        
        Returns
        -------
        data : object
                Object with the data mentioned in the description. It contains the fields: \
                `path`, `ylims`, and `window`.
        '''
        parser = argparse.ArgumentParser()
        
        parser.add_argument("--path", type=str, default=None, \
                            help="Path to the JSON file with the controller configuration. \
                                  Ex: './coefficients.json'")
        
        parser.add_argument('--ylims', type=list_of_floats, default=[20, 80], \
                            help="minimum and maximum Limits of the Y axis (Celsius): [min, max]'")
        
        parser.add_argument('--window', type=float, default=120, \
                            help="Width of time window shown in the X axis (Seconds)")

        parser.add_argument('--nsamples', type=positive_int, default=10, \
                            help="Number of data samples used to initialize the plot. Must be \
                                 larger than zero")
        
        return parser.parse_args()      # object with arguments

Captures command line parameters provided by the user when calling the script. For example:

python3 main.py --path "./config.json" --ylims 30, 100 --window 100

Parameters

path : str
Optional parameter to set path to the JSON configuration file for the controller
ylims : list(float)
Optional parameter to set the maximum and minimum values of Y axis.
window : float
Optional parameter to set the width of the X axis time window.
nsamples : int
Optional parameter for the number of data samples used to initially configure the plots. Must be larger than zero.

Returns

data : object
Object with the data mentioned in the description. It contains the fields: path, ylims, and window.
def list_of_floats(string: str) ‑> list
Expand source code
def list_of_floats(string: str) -> list:
        '''Converts a string delimited by commas into an array of strings.
        
        Parameters
        ----------
        string: str
                String of delimited parameters
        
        Returns
        -------
        data : list(str)
                array of strings
        '''
        return list( map(float, string.split(',')) )

Converts a string delimited by commas into an array of strings.

Parameters

string : str
String of delimited parameters

Returns

data : list(str)
array of strings
def main(window, ylims, path, nsamples)
Expand source code
def main(window, ylims, path, nsamples):
        '''Interactive plot that displays temperature measurement in real time. Terminal can be used
        at the same time to send commands to the Arduino and modify the behavior of controller.
        
        Parameters
        ----------
        window : float
                Horizontal size of x-axis of the real time plot
        
        ylims : list
                Range of visible temperatures in the real time plot; [minimum, maximum]
        
        path : str
                path to json file that contains the parameters to configure the controller
        
        nsamples : int
                number of data samples used to generate the first points in the plot.
        '''
        # ---- Serial ----
        try:
                controller = cntl.TempControllerCN0391(path=path)
        except:
                print("Unable to establish Serial connection - Exiting")
                return  # exit function
        
        # ---- keyboard inputs ----
        keythread = kb.KeyboardThread() # starts thread automatically
        
        # ---- Plots ----
        # Size of data
        time_init = 0
        time.sleep(2)                   # wait for serial to reload
        
        y_init = sum( [vert_array(controller.get_filter()) for i in range(nsamples)] ) / nsamples
        n_data = np.size(y_init)
        
        # figure
        x = np.array( [] )
        y = np.array( [] )
        
        # plot graphs
        figure, ax = plt.subplots()
        lines = [ ax.plot(x, y, label=f'Port {i+1}')[0] for i in range(n_data) ] 

        #---- configure plot ----
        ax.legend()
        ax.set_xlim( [0, window] )
        ax.set_ylim( ylims )
        ax.set_xlabel("Seconds")
        ax.set_ylabel("Celsius")

        plt.ion()
        plt.show()
        
        #---- loop ----
        while controller.is_active():   # check connection
                try:
                        # ----- serial inputs -----
                        if keythread.flag():
                                key_input = keythread.input()
                                
                                if key_input == "exit":
                                        break
                                elif key_input != "":
                                        reply = controller.send_serial_command(key_input)
                                        print(reply)
                        
                        #----- plot -----
                        time_now = time.time()
                        
                        if np.size(x) == 0: 
                                time_init = time_now
                                y = y_init.copy()
                        else:
                                ynew = controller.get_filter()  # breaks when interrupt is called
                                ynew = vert_array(ynew)                 # transform to vertical numpy array
                                y = np.hstack( (y, ynew) )
                        
                        time_zero = time_now - time_init
                        x = np.append(x, time_zero);
                        
                        if time_zero > window:
                                y = y[:, 1:]                            # delete first vertical slice
                                x = np.delete(x, 0)
                                ax.set_xlim( [ x[0], x[-1] ] )
                        
                        # update plots
                        for i in range(n_data):
                                lines[i].set_xdata(x)
                                lines[i].set_ydata( y[i] )
                        
                        figure.canvas.draw()
                        figure.canvas.flush_events()
                
                except:
                        print("Data Transfer Failed - Exiting")
                        break   # exit loop
        
        #---- exit program ----
        print("CLOSED-PYTHON")
        controller.set_disable_all()
        controller.serial.reset()
        controller.serial.close()
        keythread.stop()

Interactive plot that displays temperature measurement in real time. Terminal can be used at the same time to send commands to the Arduino and modify the behavior of controller.

Parameters

window : float
Horizontal size of x-axis of the real time plot
ylims : list
Range of visible temperatures in the real time plot; [minimum, maximum]
path : str
path to json file that contains the parameters to configure the controller
nsamples : int
number of data samples used to generate the first points in the plot.
def positive_int(string: str) ‑> int
Expand source code
def positive_int(string: str) -> int:
        '''Converts a string to positive integer. 
        
        Parameters
        ----------
        string: str
                String that contains numbers
        
        Returns
        -------
        num : int
                Integer that is at least 1. Can be greater than one.
        '''
        num = int(string)
        if num > 0:
                return num
        else:
                return 1

Converts a string to positive integer.

Parameters

string : str
String that contains numbers

Returns

num : int
Integer that is at least 1. Can be greater than one.
def vert_array(arr: list) ‑> numpy.ndarray
Expand source code
def vert_array(arr: list) -> np.ndarray:
        '''Convert an horizontal array into a vertical numpy array. This function is well suited to
        transform parsed data into a form that is easily plotted by matplotlib. 
        
        Returns
        -------
        output : np.array
                Numpy array with the shape: [[]...[]]
        '''
        return np.array(arr).reshape(-1,1) 

Convert an horizontal array into a vertical numpy array. This function is well suited to transform parsed data into a form that is easily plotted by matplotlib.

Returns

output : np.array
Numpy array with the shape: [[]…[]]