Lab 3 Activity

The goal of Lab 3 is to prepare for Lab 4 (Thermal Design), scooping up loads of useful skills along the way. By the end, you want to have the capability of reading in four channels of RTD temperature in an automated Python program. In overview, the steps consist of:

Ready for all this?

Task Breakdown

Note: see Tips section below for helpful hints.

Raspberry Pi Connection

  1. Use PuTTY (64-bit) on lab machines to connect to benchX.physlabs.ucsd.edu, where X is the bench number as it appears on the label on the Pi unit at your bench. The username is benchX (same X), and the password defaults to bench1 (same independent of bench number). You can also use ssh from any campus Unix/Linux/mac environment via the command ssh benchX@benchX.physlabs.ucsd.edu
  2. The first task is to change the password to something unique to your bench. Discuss with your bench partner and come up with something you can both remember. Once decided, enter the command passwd at the prompt, which will first ask to confirm the current (original) password, then have you enter a new one twice (must match).

Linux Familiarity

You might find any number of Linux tutorials online. Please explore as much as you like. The suggestions below outline a minimal familiarity level, some of which you may need to ask Google to make progress.

  1. Make a directory (mkdir) to hold your Lab 3 work (call it whatever you want, but be aware that spaces in filenames are not Linux-friendly; see tips).
  2. Learn to use cd, pwd, ls, ls -l, what . and .. mean.
  3. Make some text files to mess with, using various techniques:
    1. $ echo "customized text to end up in file" > filename (modify text to suit, and provide some descriptive filename). Try the echo command without the > filename part to see what it does (and why it's called echo). The > filename part puts the result (stuffs it into) a file instead of the terminal window.
    2. Edit a new file into existence using an editor like vi or nano. See this synopsis of Command-line editors on the Pi. Note that these machines are configured so that typing vi actually runs the (better) vim. To edit a new file, just type the editor command followed by the (new) filename. Create files containing more than ten lines of stuff, to help illustrate a few things later.
  4. Once you have a few files, make copies the following two ways (making up your own names instead of literal use of the placeholders below):
    1. $ cp some_file diff_file (copy)
    2. $ cat another_file > new_file (catenate)
    3. $ cat third_file >> append_to_file (concatenate)
    4. $ cat fourth_file >> append_to_file (concatenate)
    Note the difference between the two flavors of the cat commands. A single greater-than sign creates a new file to receive the contents, whereas two together (>>) appends the content to an existing file (or creates if non-existent). For illustrative purposes, we do the concatenate command twice (possibly using distinct/different input files) so you can see the appending feature in action.
  5. Now do ls (list) to see what you've got; pwd (print working directory) to verify where you are; ls -l (long list) to see more detail on files (permissions; size, creation time); ls -lt to sort by creation time (newest at top); mv to rename (move) a file; cat to dump the contents of a file to the screen; head to print the first 10 lines of a file; head -n3 to print the first three lines; tail to look at the last 10 (or 3; similar arguments to head); less to just look at (not edit) a file (q to exit).
  6. Explore word count (wc), operating on single files, and on the all the entire contents of the directory (via *). The output tells how many lines, words, and characters a file has. Also not a bad idea to look at how the wild-card (*) operator works in command lines so you can target particular file types (try this tutorial, and note the power of the bracket convention to limit the range of possibilities).
  7. Look up how to use the grep command and try it out on some of your files. Grep is a super powerful way to find text in a file. In fact, pick a word/string that only appears in one of your files, and do: $ grep string * to look for the instance in all files in a directory. This is hugely useful for finding stuff.
  8. Pipes! Unix/Linux commands can be strung together so that the output of one process feeds the input to another, and these can be strung along in arbitrarily-long sequences. Try the following examples to get the hang of what's happening:
    1. $ head some_long_file | grep some_string looks for string in first ten lines of file
    2. $ head some_long_file | grep some_string > output_file same as above, but stuffs (any) output into a new file
    3. $ grep some_string some_file | less look for all lines containing a certain string in a certain file (or * for all files in that directory) and put the output to less for easier viewing (especially if the result is voluminous and won't fit on one screen; less allows you to navigate more easily)
    4. $ ls -lt | head shows (up to) ten most recent files in directory—something I often use to discover any files just created by running a process/program
  9. Use the man (manual) command to look up details on commands (e.g., man ls). Note all the flag options. The interface is based on less, so: q exits; space bar pages forward; b goes back one page; G goes to end of file; 1G goes to beginning; and super-important: / initiates a search (just type in text to find after / and hit enter; n finds next and N finds previous; best to start at top of file (1G) because it won't wrap

Python Intro

  1. Type python at the command line to launch an interactive session of Python. Note the version number (may be useful). To exit, type Ctrl-D. The session allows you to test syntax, how lists and indexing works, etc. It's super useful.
  2. Edit a new file with a .py extension. For the first line in the file, put: #!/usr/bin/env python. The shell interprets the #! (pronounced she-bang, helping me keep the order straight) as an interpreter directive. The /usr/bin/env part queries the computer's environment to find the location of the final argument, python, and runs that. It would be possible to just have #!/usr/bin/python to run Python directly, but Python's location (path) may vary from one computer to another, so the env trick makes the code more general.
  3. To get started, have a simple print statement in the program. Save and exit the editor. Now we have to change the permissions of the file to make it executable. We only have to do this once for a file, and future edits will not require re-classifying as executable. Using ls -l, note the permissions of the file may look like -rw-r--r--. The first dash indicates a regular file (d is a directory, for instance). Then come three groups of rwx (or dashes) for read, write, execute. The three groups pertain to the owner (benchX, likely), the group (users, likely), and the rest of the world (account holders not part of the same group). In the example above, everyone can read the file, but only the owner can write (edit). To make the file executable, any of the following will work:
    1. $ chmod +x file.py-rwxr-xr-x → add executable for all
    2. $ chmod u+x file.py-rwxr--r-- → add executable for user (owner) only; if starting from -rw-r--r--
    3. $ chmod 755 file.py-rwxr-xr-x → direct control of all fields 4=r; 2=w; 1=x
    4. $ chmod 744 file.py-rwxr--r--
    5. $ chmod 754 file.py-rwxr-xr--
  4. Run the program from the command line using ./file.py (using your program's name instead of the place holder file.py). The ./ convention says: run this thing that sits in my current (.) directory.
  5. Now expand the functionality of the program (or start a new one) to incorporate command lines, write to a file, and any other features you need to develop in pursuit of the goal. Use the Google to find tutorials to help.
    1. Use import sys to bring in the system command module for command lines; arguments are now available in sys.argv[i], where i is an integer index.
    2. Have the program do something with a command line argument (or multiple ones) and print the result to screen.
    3. Now open a file for writing (outfile = open('myfile.out','w')) and write something to it (outfile.write("some text\n")) and in the end, show good manners by closing the file (outfile.close()). Run the program and check the file for correct/expected content. The \n is a newline; outfile is just a name/handle used in the program—could be anything you want.
    4. Familiarize yourself with the time module (import time). Import into an interactive session and do dir(time) to see what commands are available, and help(time.some_command) to learn more about individual commands. Try the following interactive commands to get a feel for key functions:
      1. time.time() → Time in seconds from Unix epoch (8.5 days before I was born)
      2. time.localtime(time.time()) → familiar format
      3. time.localtime(time.time())[0] → grab year (integer)
      4. time.gmtime(time.time()) → in UTC
      5. time.sleep(5) → note lag before prompt returns
      These can help you schedule readings and print times to the file for recording a data series.

I²C Communications

  1. Following the lead from lecture notes, write a bare-bones I²C interface to at least "energize" the communication lines on the Raspberry Pi header and see activity on the scope:

    import smbus
    i2c_bus = smbus.SMBus(1)
    ADDR = 0x48
    i2c_bus.write_i2c_block_data(ADDR,1,[0x85,0x83])
    # or later: data = i2c_bus.read_i2c_block_data(ADDR,0,2)


  2. The communication will fail (including Python I/O error, usefully) without a device connected, but this is fine as a first step. It allows us to verify that the I²C lines are active and doing what we expect. Probe the SCL and SDA lines on the scope to see what it's doing. Recommended settings: normal trigger mode; 1x probes; 2 V/div; trigger either signal at about 1 V level; adjust time base to get full pattern. You should be able to verify the address is being sent correctly (MSB first), and the read/write bit at the expected value. But crucially, you should see the acknowledge fail (not pulled low) since the device is not connected. Sketch out the waveforms (aligned) for reference and for the report. Do for both read and write commands to see how they differ.
  3. Now hook up the ADS1015 4-channel ADC chip (power, ground, I²C lines; see ADS1015 datasheet). Try the same write and read commands. The Python code should not throw an error this time (big cheer if not). Now the scope should show the acknowledge pulled low, and the read command should be longer, showing data coming back. The goal is to understand each bit in the communication stream: dissect it and compare to the data sheet waveforms to verify the signals are what you expect and every bit is what and where you expect.
  4. Now study the ADS1015 datasheet to figure out how to configure for reading the four individual channels referenced to ground. Each read will consist of a configuration write followed by a read.
  5. Verify that the data coming back makes sense, and that if putting a volt or so on the associated channel, the read/query returns a sensible/valid number. Completion of this step and the previous one represents a significant hurdle cleared. It's downhill from here.

RTD Signal Conditioning

  1. Follow the circuit diagram in the lecture and use the parts provided in the lab to configure a current source for the RTD readout. Use a (precision, ideally) 1.00 kΩ resistor in place of the RTD to tune the potentiometer for a 1.00 V result, meaning you've nailed 1.00 mA. Alternatively, a 1.20 kΩ resistor (or some other value) should produce 1.20 V, for instance.
  2. Connect the RTD and interpret the voltage in terms of room temperature (may also just use ohm-meter to compare). Be careful about handling the RTD, as you can easily change its temperature. Best to tape it to the table or piece of metal to stabilize it.

Read RTD Data

  1. Hook the voltage output of the RTD readout to one channel of the ADS1015 and verify that your Python program can read the voltage correctly.
  2. Convert to temperature and perform regular polling at a cadence of once every second or two, printing result to screen for now. Put your finger on the RTD and see it change.
  3. Modify the program to save the time series to file. Each line should have a time stamp and a temperature. The time stamp may be most usefully expressed as seconds since the start (grab time.time() at the beginning and then for each sample, subtract that off of the current (evolving) time.time() value.
  4. One tip to keep your files from overwriting each other each time you run the program is to format the filename to contain a time stamp. For instance, you can get time.localtime(time.time()) at the start of the program and use the year, month, day, hour, minute, second to make something like 191014-164503.out. Hint: "%02d%02d%02d-%02d%02d%02d.out".

Configure Program for Multiple Channel Logging

  1. Finally, expand your program to read as many as 4 RTDs and save the time sequence to file.
  2. Configure the hardware for at least two channels. This can be done either by populating the breadboard with more channels, or using our snazzy custom-designed and built circuits made to interface gracefully to the ADS1015. It's the same circuit, just different packaging.
  3. Verify that you get reasonable temperature readouts from all channels in a log file.

Tips

Here are some tips that may be useful:

Write-Up

The write-up will be deferred until after Lab 4, since most of the work this week is aimed at building familiarity. This also gives you time to complete all tasks before Lab 4 without spending time on the write-up. However, some things you do this week are worthy of inclusion in the write-up, and are called out below.


Back to Physics 122 page