diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..27b72cf --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.vscode/ +__pycache__ +build/ +dist/ +**.egg-info/ \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6802bc4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index f8f7179..d39b298 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,22 @@ -# TF-Luna LiDAR with Raspberry Pi -Python codes for configuring and reading the TF-Luna Light Detection And Ranging (LiDAR) module interfaced with a Raspberry Pi computer. +# TF-Luna LiDAR Python Driver -Tutorial: https://makersportal.com/blog/distance-detection-with-the-tf-luna-lidar-and-raspberry-pi +The [TF-Luna sensor](https://www.dfrobot.com/product-1995.html) is a LiDAR sensor, which can be read either with I2C or Serial. -Buy a TF-Luna from our Store: https://makersportal.com/shop/tf-luna-lidar-module +This repository contains the code permitting to use the TF-Luna sensor with the serial interface. -# +This repository is a fork of [tfluna-python](https://github.com/makerportal/tfluna-python), and is a rewrite of the driver to a class-based structure. +The new code is also more careful when it comes to handling the serial interface: this driver is indeed intended to be used (only) as a Python resource, i.e. as follows (more details in the `example` folder): + +``` +import tfluna +import timeout_decorator + +with tfluna.TfLuna(baud_speed=115200, serial_name="/dev/serial0") as tfluna: + tfluna.get_version() + tfluna.set_samp_rate(10) + #tfluna.set_baudrate(57600) # can be used to change the baud_speed + distance,strength,temperature = tfluna.read_tfluna_data() +``` ### - TF-Luna + Raspberry Pi Wiring - @@ -13,16 +24,3 @@ The TF-Luna can be wired to the Raspberry Pi via the mini UART port: ![TF-Luna RPi Wiring](https://static1.squarespace.com/static/59b037304c0dbfb092fbe894/t/6009f277b8566661c36dfa67/1611264637375/TF_luna_RPi_wiring.png?format=1500w) ---- -### - TF-Luna Ranging Test - - -The script entitled 'tfluna_test_plot.py' outputs a plot similar to the following: - -![TF-Luna Ranging Test](./images/tfluna_test_plot_white.png) - ---- -### - Real-Time Ranging Visualization - - -The script entitled 'tfluna_test_realtime.py' outputs a real-time output of distance and signal strength, similar to the following: - -![TF-Luna Real-Time Ranging](./images/tfluna_realtime_plot_white.png) diff --git a/examples/tfluna_realtime.py b/examples/tfluna_realtime.py new file mode 100644 index 0000000..e170cad --- /dev/null +++ b/examples/tfluna_realtime.py @@ -0,0 +1,93 @@ +###################################################### +# Copyright (c) 2021 Maker Portal LLC +# Author: Joshua Hrisko +# Code refactoring (to classes): Clément Nussbaumer, April 2021 +###################################################### +# +# TF-Luna Mini LiDAR wired to a Raspberry Pi via UART +# --- Real-time ranging with signal strength indicator +# +# +###################################################### +# + +import tfluna + +import time +import numpy as np +import matplotlib.pyplot as plt + +# +############################################## +# Plotting functions +############################################## +# +def plotter(): + ################################################ + # ---- start real-time ranging and strength bar + ################################################ + # + plt.style.use('ggplot') # plot formatting + fig,axs = plt.subplots(1,2,figsize=(12,8), + gridspec_kw={'width_ratios': [5,1]}) # create figure + fig.canvas.set_window_title('TF-Luna Real-Time Ranging') + fig.subplots_adjust(wspace=0.05) + # ranging axis formatting + axs[0].set_xlabel('Sample',fontsize=16) + axs[0].set_ylabel('Amplitude',fontsize=16) # amplitude label + axs[0].set_xlim([0.0,plot_pts]) + axs[0].set_ylim([0.0,8.0]) # set ranging limits + # signal strength axis formatting + axs[1].set_xlim([-1.0,1.0]) # strength bar width + axs[1].set_xticks([]) # remove x-ticks + axs[1].set_ylim([1.0,2**16]) # set signal strength limits + axs[1].yaxis.tick_right() # move strength ticks to right + axs[1].yaxis.set_label_position('right') # label to right + axs[1].set_ylabel('Signal Strength',fontsize=16,labelpad=6.0) + axs[1].set_yscale('log') # log scale for better visual + # draw and background specification + fig.canvas.draw() # draw initial plot + ax1_bgnd = fig.canvas.copy_from_bbox(axs[0].bbox) # get background + ax2_bgnd = fig.canvas.copy_from_bbox(axs[1].bbox) # get background + line1, = axs[0].plot(np.zeros((plot_pts,)),linewidth=3.0, + color=plt.cm.Set1(1)) # dummy initial ranging data (zeros) + bar1, = axs[1].bar(0.0,1.0,width=1.0,color=plt.cm.Set1(2)) + fig.show() # show plot + return fig,axs,ax1_bgnd,ax2_bgnd,line1,bar1 + +def plot_updater(): + ########################################## + # ---- time series + fig.canvas.restore_region(ax1_bgnd) # restore background 1 (for speed) + fig.canvas.restore_region(ax2_bgnd) # restore background 2 + line1.set_ydata(dist_array) # update channel data + bar1.set_height(strength) # update signal strength + if strength<100.0 or strength>30000.0: + bar1.set_color(plt.cm.Set1(0)) # if invalid strength, make bar red + else: + bar1.set_color(plt.cm.Set1(2)) # green bar + axs[0].draw_artist(line1) # draw line + axs[1].draw_artist(bar1) # draw signal strength bar + fig.canvas.blit(axs[0].bbox) # blitting (for speed) + fig.canvas.blit(axs[1].bbox) # blitting + fig.canvas.flush_events() # required for blitting + return line1,bar1 +# +############################ +# Real-Time Plotter Loop +############################ +# +with tfluna.TfLuna(baud_speed=115200) as tfluna: + tfluna.get_version() + + plot_pts = 100 # points for sample rate test + fig,axs,ax1_bgnd,ax2_bgnd,line1,bar1 = plotter() # instantiate figure and plot + dist_array = [] # for updating values + print('Starting Ranging...') + while True: + distance,strength,temperature = tfluna.read_tfluna_data() # read values + dist_array.append(distance) # append to array + if len(dist_array)>plot_pts: + dist_array = dist_array[1:] # drop first point (maintain array size) + line1,bar1 = plot_updater() # update plot + diff --git a/examples/tfluna_simple_read.py b/examples/tfluna_simple_read.py new file mode 100644 index 0000000..b9c0b2d --- /dev/null +++ b/examples/tfluna_simple_read.py @@ -0,0 +1,33 @@ +###################################################### +# Copyright (c) 2021 Maker Portal LLC +# Author: Joshua Hrisko +# Author of the refactoring (to classes): Clément Nussbaumer, April 2021 +###################################################### +# +# TF-Luna Mini LiDAR wired to a Raspberry Pi via UART +# --- testing the distance measurement from the TF-Luna +# +###################################################### +# +import time +import numpy as np + +import tfluna +import timeout_decorator + +with tfluna.TfLuna(baud_speed=115200) as tfluna: + try: + tfluna.get_version() + tfluna.set_samp_rate(10) + #tfluna.set_baudrate(57600) + #tfluna.set_baudrate(115200) + + for i in range(10): + distance,strength,temperature = tfluna.read_tfluna_data() # read values + print( + f"Distance: {distance:2.2f} m, " + f"Strength: {strength:2.0f} / 65535 (16-bit), " + f"Chip Temperature: {temperature:2.1f} C") # print sample data + + except timeout_decorator.TimeoutError: + print(f"Timeout while communicating with the Tf Luna sensor, exiting") \ No newline at end of file diff --git a/examples/tfluna_test_plot.py b/examples/tfluna_test_plot.py new file mode 100644 index 0000000..a41746b --- /dev/null +++ b/examples/tfluna_test_plot.py @@ -0,0 +1,48 @@ +###################################################### +# Copyright (c) 2021 Maker Portal LLC +# Author: Joshua Hrisko +# Code refactoring (to classes): Clément Nussbaumer, April 2021 +###################################################### +# +# TF-Luna Mini LiDAR wired to a Raspberry Pi via UART +# --- test ranging plotter for TF-Luna +# +# +###################################################### +# +import time +import numpy as np + +import tfluna +# +############################ +# Testing the TF-Luna Output +############################ +# +with tfluna.TfLuna(baud_speed=115200) as tfluna: + + tot_pts = 100 # points for sample rate test + time_array,dist_array = [],[] # for storing values + print('Starting Ranging...') + while len(dist_array)=42", + "wheel" +] +build-backend = "setuptools.build_meta" \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..c9cf0b3 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +pyserial +timeout-decorator \ No newline at end of file diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..70b06eb --- /dev/null +++ b/setup.cfg @@ -0,0 +1,24 @@ +[metadata] +name = tfluna-driver +version = 0.1.0 +author = Clément Nussbaumer +author_email = clement@astutus.org +description = Code to read measurements from a Tf-Luna LiDAR sensor. +long_description = file: README.md +long_description_content_type = text/markdown +url = https://github.com/clementnuss/tfluna-python +project_urls = + Bug Tracker = https://github.com/clementnuss/tfluna-python +classifiers = + Programming Language :: Python :: 3 + License :: OSI Approved :: MIT License + Operating System :: OS Independent + +[options] +package_dir = + = src +packages = find: +python_requires = >=3.6 + +[options.packages.find] +where = src \ No newline at end of file diff --git a/src/tfluna/__init__.py b/src/tfluna/__init__.py new file mode 100644 index 0000000..724a971 --- /dev/null +++ b/src/tfluna/__init__.py @@ -0,0 +1 @@ +from .tfluna import TfLuna diff --git a/src/tfluna/tfluna.py b/src/tfluna/tfluna.py new file mode 100644 index 0000000..3e93322 --- /dev/null +++ b/src/tfluna/tfluna.py @@ -0,0 +1,141 @@ +###################################################### +# Copyright (c) 2021 Maker Portal LLC +# Author: Joshua Hrisko +# Code refactoring (to classes): Clément Nussbaumer, April 2021 +# Reference manual for the sensor: https://github.com/May-DFRobot/DFRobot/blob/master/TF-Luna%20LiDAR%EF%BC%888m%EF%BC%89Product%20Manual.pdf +###################################################### +# +# TF-Luna Mini LiDAR wired to a Raspberry Pi via UART +# --- Configuring the TF-Luna's baudrate, sample rate, +# --- and printing out the device version info +# +###################################################### +# +import serial,time +import timeout_decorator +from .util import raise_if_outside_context + + +class TfLuna(): + + baud_config = { + 9600: [0x80,0x25,0x00], # 9600 + 19200: [0x00,0x4b,0x00], # 19200 + 38400: [0x00,0x96,0x00], # 38400 + 57600: [0x00,0xe1,0x00], # 57600 + 115200: [0x00,0xc2,0x01], # 115200 + 230400: [0x00,0x84,0x03], # 230400 + 460800: [0x00,0x08,0x07], # 460800 + 921600: [0x00,0x10,0x0e] # 921600 + } + + def __init__(self, serial_name = "/dev/serial0", baud_speed = 115200): + if baud_speed not in self.baud_config: + raise Exception(f"Invalid baud_speed setting used: {baud_speed}\n" + "available baud speeds: 9600,19200,38400,57600,115200,230400,460800,921600") + self.serial_name = serial_name + self.baud_speed = baud_speed + self.inside_context = False # set to False so long as we haven't used the with statement. + + def __enter__(self): + self.ser = serial.Serial(self.serial_name, self.baud_speed, timeout = 1) # mini UART serial device + self.inside_context = True # now that we are in a context, we set this to true and open the serial device + return self + + def __exit__(self, exception_type, exception_value, exception_traceback): + self.inside_context = False + self.ser.close() + print(f"Correctly closed the TfLuna Object and the serial port") + + + @raise_if_outside_context + @timeout_decorator.timeout(5, use_signals=False) + def read_tfluna_data(self): + while True: + counter = self.ser.in_waiting # count the number of bytes of the serial port + bytes_to_read = 9 + if counter > bytes_to_read-1: + bytes_serial = self.ser.read(bytes_to_read) # read 9 bytes + self.ser.reset_input_buffer() # reset buffer + + if bytes_serial[0] == 0x59 and bytes_serial[1] == 0x59: # check first two bytes + distance = bytes_serial[2] + bytes_serial[3]*256 # distance in next two bytes + strength = bytes_serial[4] + bytes_serial[5]*256 # signal strength in next two bytes + temperature = bytes_serial[6] + bytes_serial[7]*256 # temp in next two bytes + temperature = (temperature/8) - 256 # temp scaling and offset + return distance/100.0,strength,temperature + + @raise_if_outside_context + def set_samp_rate(self, samp_rate=100): + ########################## + # change the sample rate + samp_rate_packet = [0x5a,0x06,0x03,samp_rate,00,00] # sample rate byte array + self.ser.write(samp_rate_packet) # send sample rate instruction + time.sleep(0.1) # wait for change to take effect + return + + @raise_if_outside_context + @timeout_decorator.timeout(5, use_signals=False) + def get_version(self): + ########################## + # get version info + info_packet = [0x5a,0x04,0x14,0x00] + + self.ser.write(info_packet) + time.sleep(0.1) + bytes_to_read = 30 + while True: # timeout handled by the timeout decorator + counter = self.ser.in_waiting + if counter > bytes_to_read: + bytes_data = self.ser.read(bytes_to_read) + self.ser.reset_input_buffer() + if bytes_data[0] == 0x5a: + try: + version = bytes_data[3:-1].decode('utf-8') + print('Version -'+version) + except: + continue + return + else: + self.ser.write(info_packet) + time.sleep(0.1) + + @timeout_decorator.timeout(5, use_signals=False) + @raise_if_outside_context + def set_baudrate(self, baud_rate=115200): + if baud_rate not in self.baud_config: + raise Exception(f"Invalid baud_speed setting used: {baud_rate}\n" + "available baud speeds: 9600,19200,38400,57600,115200,230400,460800,921600") + + info_packet = [0x5a,0x08,0x06, + self.baud_config[baud_rate][0], + self.baud_config[baud_rate][1], + self.baud_config[baud_rate][2], + 0x00,0x00] # instruction packet + + self.ser.write(info_packet) # change the baud rate + time.sleep(0.1) # wait to settle + self.ser.close() + self.ser.baudrate = baud_rate + self.ser.open() + time.sleep(0.1) # wait to settle + bytes_to_read = 8 + while True: + counter = self.ser.in_waiting + if counter > bytes_to_read: + bytes_data = self.ser.read(bytes_to_read) + self.ser.reset_input_buffer() + if bytes_data[0] == 0x5a: + for spd in self.baud_config: + match = True + match &= self.baud_config[spd][0] == bytes_data[3] + match &= self.baud_config[spd][1] == bytes_data[4] + match &= self.baud_config[spd][2] == bytes_data[5] + if match: + print(f"Baud Rate = {spd}") + return + time.sleep(0.1) + else: + self.ser.write(info_packet) # try again if wrong data received + time.sleep(0.1) # wait 100ms + continue diff --git a/src/tfluna/util.py b/src/tfluna/util.py new file mode 100644 index 0000000..994bf76 --- /dev/null +++ b/src/tfluna/util.py @@ -0,0 +1,8 @@ + +# source: https://stackoverflow.com/a/54514410 +def raise_if_outside_context(method): + def decorator(self, *args, **kwargs): + if not self.inside_context: + raise Exception("This method should be called from inside context.") + return method(self, *args, **kwargs) + return decorator \ No newline at end of file diff --git a/tfluna_config.py b/tfluna_config.py deleted file mode 100644 index 6c0fbcd..0000000 --- a/tfluna_config.py +++ /dev/null @@ -1,137 +0,0 @@ -###################################################### -# Copyright (c) 2021 Maker Portal LLC -# Author: Joshua Hrisko -###################################################### -# -# TF-Luna Mini LiDAR wired to a Raspberry Pi via UART -# --- Configuring the TF-Luna's baudrate, sample rate, -# --- and printing out the device version info -# -# -###################################################### -# -import serial,time -import numpy as np -# -############################ -# Serial Functions -############################ -# -def read_tfluna_data(): - while True: - counter = ser.in_waiting # count the number of bytes of the serial port - bytes_to_read = 9 - if counter > bytes_to_read-1: - bytes_serial = ser.read(bytes_to_read) # read 9 bytes - ser.reset_input_buffer() # reset buffer - - if bytes_serial[0] == 0x59 and bytes_serial[1] == 0x59: # check first two bytes - distance = bytes_serial[2] + bytes_serial[3]*256 # distance in next two bytes - strength = bytes_serial[4] + bytes_serial[5]*256 # signal strength in next two bytes - temperature = bytes_serial[6] + bytes_serial[7]*256 # temp in next two bytes - temperature = (temperature/8) - 256 # temp scaling and offset - return distance/100.0,strength,temperature - -def set_samp_rate(samp_rate=100): - ########################## - # change the sample rate - samp_rate_packet = [0x5a,0x06,0x03,samp_rate,00,00] # sample rate byte array - ser.write(samp_rate_packet) # send sample rate instruction - time.sleep(0.1) # wait for change to take effect - return - -def get_version(): - ########################## - # get version info - info_packet = [0x5a,0x04,0x14,0x00] - - ser.write(info_packet) - time.sleep(0.1) - bytes_to_read = 30 - t0 = time.time() - while (time.time()-t0)<5: - counter = ser.in_waiting - if counter > bytes_to_read: - bytes_data = ser.read(bytes_to_read) - ser.reset_input_buffer() - if bytes_data[0] == 0x5a: - version = bytes_data[3:-1].decode('utf-8') - print('Version -'+version) - return - else: - ser.write(info_packet) - time.sleep(0.1) - -def set_baudrate(baud_indx=4): - ########################## - # get version info - baud_hex = [[0x80,0x25,0x00], # 9600 - [0x00,0x4b,0x00], # 19200 - [0x00,0x96,0x00], # 38400 - [0x00,0xe1,0x00], # 57600 - [0x00,0xc2,0x01], # 115200 - [0x00,0x84,0x03], # 230400 - [0x00,0x08,0x07], # 460800 - [0x00,0x10,0x0e]] # 921600 - info_packet = [0x5a,0x08,0x06,baud_hex[baud_indx][0],baud_hex[baud_indx][1], - baud_hex[baud_indx][2],0x00,0x00] # instruction packet - - prev_ser.write(info_packet) # change the baud rate - time.sleep(0.1) # wait to settle - prev_ser.close() # close old serial port - time.sleep(0.1) # wait to settle - ser_new =serial.Serial("/dev/serial0", baudrates[baud_indx],timeout=0) # new serial device - if ser_new.isOpen() == False: - ser_new.open() # open serial port if not open - bytes_to_read = 8 - t0 = time.time() - while (time.time()-t0)<5: - counter = ser_new.in_waiting - if counter > bytes_to_read: - bytes_data = ser_new.read(bytes_to_read) - ser_new.reset_input_buffer() - if bytes_data[0] == 0x5a: - indx = [ii for ii in range(0,len(baud_hex)) if \ - baud_hex[ii][0]==bytes_data[3] and - baud_hex[ii][1]==bytes_data[4] and - baud_hex[ii][2]==bytes_data[5]] - print('Baud Rate = {0:1d}'.format(baudrates[indx[0]])) - time.sleep(0.1) - return ser_new - else: - ser_new.write(info_packet) # try again if wrong data received - time.sleep(0.1) # wait 100ms - continue - -# -############################ -# Configurations -############################ -# -baudrates = [9600,19200,38400,57600,115200,230400,460800,921600] # baud rates -prev_indx = 4 # previous baud rate index (current TF-Luna baudrate) -prev_ser = serial.Serial("/dev/serial0", baudrates[prev_indx],timeout=0) # mini UART serial device -if prev_ser.isOpen() == False: - prev_ser.open() # open serial port if not open -baud_indx = 4 # baud rate to be changed to (new baudrate for TF-Luna) -ser = set_baudrate(baud_indx) # set baudrate, get new serial at new baudrate -set_samp_rate(100) # set sample rate 1-250 -get_version() # print version info for TF-Luna -time.sleep(0.1) # wait 100ms to settle - -# -############################ -# Testing the TF-Luna Output -############################ -# -tot_pts = 100 # points for sample rate test -t0 = time.time() # for timing -dist_array = [] # for storing values -while len(dist_array) bytes_to_read-1: - bytes_serial = ser.read(bytes_to_read) # read 9 bytes - ser.reset_input_buffer() # reset buffer - - if bytes_serial[0] == 0x59 and bytes_serial[1] == 0x59: # check first two bytes - distance = bytes_serial[2] + bytes_serial[3]*256 # distance in next two bytes - strength = bytes_serial[4] + bytes_serial[5]*256 # signal strength in next two bytes - temperature = bytes_serial[6] + bytes_serial[7]*256 # temp in next two bytes - temperature = (temperature/8) - 256 # temp scaling and offset - return distance/100.0,strength,temperature - -def set_samp_rate(samp_rate=100): - ########################## - # change the sample rate - samp_rate_packet = [0x5a,0x06,0x03,samp_rate,00,00] # sample rate byte array - ser.write(samp_rate_packet) # send sample rate instruction - return - -def get_version(): - ########################## - # get version info - info_packet = [0x5a,0x04,0x14,0x00] - - ser.write(info_packet) # write packet - time.sleep(0.1) # wait to read - bytes_to_read = 30 # prescribed in the product manual - t0 = time.time() - while (time.time()-t0)<5: - counter = ser.in_waiting - if counter > bytes_to_read: - bytes_data = ser.read(bytes_to_read) - ser.reset_input_buffer() - if bytes_data[0] == 0x5a: - version = bytes_data[3:-1].decode('utf-8') - print('Version -'+version) # print version details - return - else: - ser.write(info_packet) # if fails, re-write packet - time.sleep(0.1) # wait - -def set_baudrate(baud_indx=4): - ########################## - # get version info - baud_hex = [[0x80,0x25,0x00], # 9600 - [0x00,0x4b,0x00], # 19200 - [0x00,0x96,0x00], # 38400 - [0x00,0xe1,0x00], # 57600 - [0x00,0xc2,0x01], # 115200 - [0x00,0x84,0x03], # 230400 - [0x00,0x08,0x07], # 460800 - [0x00,0x10,0x0e]] # 921600 - info_packet = [0x5a,0x08,0x06,baud_hex[baud_indx][0],baud_hex[baud_indx][1], - baud_hex[baud_indx][2],0x00,0x00] # instruction packet - - prev_ser.write(info_packet) # change the baud rate - time.sleep(0.1) # wait to settle - prev_ser.close() # close old serial port - time.sleep(0.1) # wait to settle - ser_new =serial.Serial("/dev/serial0", baudrates[baud_indx],timeout=0) # new serial device - if ser_new.isOpen() == False: - ser_new.open() # open serial port if not open - bytes_to_read = 8 - t0 = time.time() - while (time.time()-t0)<5: - counter = ser_new.in_waiting - if counter > bytes_to_read: - bytes_data = ser_new.read(bytes_to_read) - ser_new.reset_input_buffer() - if bytes_data[0] == 0x5a: - indx = [ii for ii in range(0,len(baud_hex)) if \ - baud_hex[ii][0]==bytes_data[3] and - baud_hex[ii][1]==bytes_data[4] and - baud_hex[ii][2]==bytes_data[5]] - print('Set Baud Rate = {0:1d}'.format(baudrates[indx[0]])) - time.sleep(0.1) - return ser_new - else: - ser_new.write(info_packet) # try again if wrong data received - time.sleep(0.1) # wait 100ms - continue - -# -############################ -# Configurations -############################ -# -baudrates = [9600,19200,38400,57600,115200,230400,460800,921600] # baud rates -prev_indx = 4 # previous baud rate index (current TF-Luna baudrate) -prev_ser = serial.Serial("/dev/serial0", baudrates[prev_indx],timeout=0) # mini UART serial device -if prev_ser.isOpen() == False: - prev_ser.open() # open serial port if not open -baud_indx = 4 # baud rate to be changed to (new baudrate for TF-Luna) -ser = set_baudrate(baud_indx) # set baudrate, get new serial at new baudrate -set_samp_rate(100) # set sample rate 1-250 -get_version() # print version info for TF-Luna -# -############################################## -# Plotting functions -############################################## -# -def plotter(): - ################################################ - # ---- start real-time ranging and strength bar - ################################################ - # - plt.style.use('ggplot') # plot formatting - fig,axs = plt.subplots(1,2,figsize=(12,8), - gridspec_kw={'width_ratios': [5,1]}) # create figure - fig.canvas.set_window_title('TF-Luna Real-Time Ranging') - fig.subplots_adjust(wspace=0.05) - # ranging axis formatting - axs[0].set_xlabel('Sample',fontsize=16) - axs[0].set_ylabel('Amplitude',fontsize=16) # amplitude label - axs[0].set_xlim([0.0,plot_pts]) - axs[0].set_ylim([0.0,8.0]) # set ranging limits - # signal strength axis formatting - axs[1].set_xlim([-1.0,1.0]) # strength bar width - axs[1].set_xticks([]) # remove x-ticks - axs[1].set_ylim([1.0,2**16]) # set signal strength limits - axs[1].yaxis.tick_right() # move strength ticks to right - axs[1].yaxis.set_label_position('right') # label to right - axs[1].set_ylabel('Signal Strength',fontsize=16,labelpad=6.0) - axs[1].set_yscale('log') # log scale for better visual - # draw and background specification - fig.canvas.draw() # draw initial plot - ax1_bgnd = fig.canvas.copy_from_bbox(axs[0].bbox) # get background - ax2_bgnd = fig.canvas.copy_from_bbox(axs[1].bbox) # get background - line1, = axs[0].plot(np.zeros((plot_pts,)),linewidth=3.0, - color=plt.cm.Set1(1)) # dummy initial ranging data (zeros) - bar1, = axs[1].bar(0.0,1.0,width=1.0,color=plt.cm.Set1(2)) - fig.show() # show plot - return fig,axs,ax1_bgnd,ax2_bgnd,line1,bar1 - -def plot_updater(): - ########################################## - # ---- time series - fig.canvas.restore_region(ax1_bgnd) # restore background 1 (for speed) - fig.canvas.restore_region(ax2_bgnd) # restore background 2 - line1.set_ydata(dist_array) # update channel data - bar1.set_height(strength) # update signal strength - if strength<100.0 or strength>30000.0: - bar1.set_color(plt.cm.Set1(0)) # if invalid strength, make bar red - else: - bar1.set_color(plt.cm.Set1(2)) # green bar - axs[0].draw_artist(line1) # draw line - axs[1].draw_artist(bar1) # draw signal strength bar - fig.canvas.blit(axs[0].bbox) # blitting (for speed) - fig.canvas.blit(axs[1].bbox) # blitting - fig.canvas.flush_events() # required for blitting - return line1,bar1 -# -############################ -# Real-Time Plotter Loop -############################ -# -plot_pts = 100 # points for sample rate test -fig,axs,ax1_bgnd,ax2_bgnd,line1,bar1 = plotter() # instantiate figure and plot -dist_array = [] # for updating values -print('Starting Ranging...') -while True: - distance,strength,temperature = read_tfluna_data() # read values - dist_array.append(distance) # append to array - if len(dist_array)>plot_pts: - dist_array = dist_array[1:] # drop first point (maintain array size) - line1,bar1 = plot_updater() # update plot -ser.close() # close serial port - diff --git a/tfluna_test.py b/tfluna_test.py deleted file mode 100644 index 22612db..0000000 --- a/tfluna_test.py +++ /dev/null @@ -1,45 +0,0 @@ -###################################################### -# Copyright (c) 2021 Maker Portal LLC -# Author: Joshua Hrisko -###################################################### -# -# TF-Luna Mini LiDAR wired to a Raspberry Pi via UART -# --- testing the distance measurement from the TF-Luna -# -# -###################################################### -# -import serial,time -import numpy as np -# -########################## -# TFLuna Lidar -########################## -# -ser = serial.Serial("/dev/serial0", 115200,timeout=0) # mini UART serial device -# -############################ -# read ToF data from TF-Luna -############################ -# -def read_tfluna_data(): - while True: - counter = ser.in_waiting # count the number of bytes of the serial port - if counter > 8: - bytes_serial = ser.read(9) # read 9 bytes - ser.reset_input_buffer() # reset buffer - - if bytes_serial[0] == 0x59 and bytes_serial[1] == 0x59: # check first two bytes - distance = bytes_serial[2] + bytes_serial[3]*256 # distance in next two bytes - strength = bytes_serial[4] + bytes_serial[5]*256 # signal strength in next two bytes - temperature = bytes_serial[6] + bytes_serial[7]*256 # temp in next two bytes - temperature = (temperature/8.0) - 256.0 # temp scaling and offset - return distance/100.0,strength,temperature - -if ser.isOpen() == False: - ser.open() # open serial port if not open - -distance,strength,temperature = read_tfluna_data() # read values -print('Distance: {0:2.2f} m, Strength: {1:2.0f} / 65535 (16-bit), Chip Temperature: {2:2.1f} C'.\ - format(distance,strength,temperature)) # print sample data -ser.close() # close serial port diff --git a/tfluna_test_plot.py b/tfluna_test_plot.py deleted file mode 100644 index 8e730c5..0000000 --- a/tfluna_test_plot.py +++ /dev/null @@ -1,148 +0,0 @@ -###################################################### -# Copyright (c) 2021 Maker Portal LLC -# Author: Joshua Hrisko -###################################################### -# -# TF-Luna Mini LiDAR wired to a Raspberry Pi via UART -# --- test ranging plotter for TF-Luna -# -# -###################################################### -# -import serial,time -import numpy as np -import matplotlib.pyplot as plt -# -############################ -# Serial Functions -############################ -# -def read_tfluna_data(): - while True: - counter = ser.in_waiting # count the number of bytes of the serial port - bytes_to_read = 9 - if counter > bytes_to_read-1: - bytes_serial = ser.read(bytes_to_read) # read 9 bytes - ser.reset_input_buffer() # reset buffer - - if bytes_serial[0] == 0x59 and bytes_serial[1] == 0x59: # check first two bytes - distance = bytes_serial[2] + bytes_serial[3]*256 # distance in next two bytes - strength = bytes_serial[4] + bytes_serial[5]*256 # signal strength in next two bytes - temperature = bytes_serial[6] + bytes_serial[7]*256 # temp in next two bytes - temperature = (temperature/8) - 256 # temp scaling and offset - return distance/100.0,strength,temperature - -def set_samp_rate(samp_rate=100): - ########################## - # change the sample rate - samp_rate_packet = [0x5a,0x06,0x03,samp_rate,00,00] # sample rate byte array - ser.write(samp_rate_packet) # send sample rate instruction - return - -def get_version(): - ########################## - # get version info - info_packet = [0x5a,0x04,0x14,0x00] - - ser.write(info_packet) - time.sleep(0.1) - bytes_to_read = 30 - t0 = time.time() - while (time.time()-t0)<5: - counter = ser.in_waiting - if counter > bytes_to_read: - bytes_data = ser.read(bytes_to_read) - ser.reset_input_buffer() - if bytes_data[0] == 0x5a: - version = bytes_data[3:-1].decode('utf-8') - print('Version -'+version) - return - else: - ser.write(info_packet) - time.sleep(0.1) - -def set_baudrate(baud_indx=4): - ########################## - # get version info - baud_hex = [[0x80,0x25,0x00], # 9600 - [0x00,0x4b,0x00], # 19200 - [0x00,0x96,0x00], # 38400 - [0x00,0xe1,0x00], # 57600 - [0x00,0xc2,0x01], # 115200 - [0x00,0x84,0x03], # 230400 - [0x00,0x08,0x07], # 460800 - [0x00,0x10,0x0e]] # 921600 - info_packet = [0x5a,0x08,0x06,baud_hex[baud_indx][0],baud_hex[baud_indx][1], - baud_hex[baud_indx][2],0x00,0x00] # instruction packet - - prev_ser.write(info_packet) # change the baud rate - time.sleep(0.1) # wait to settle - prev_ser.close() # close old serial port - time.sleep(0.1) # wait to settle - ser_new =serial.Serial("/dev/serial0", baudrates[baud_indx],timeout=0) # new serial device - if ser_new.isOpen() == False: - ser_new.open() # open serial port if not open - bytes_to_read = 8 - t0 = time.time() - while (time.time()-t0)<5: - counter = ser_new.in_waiting - if counter > bytes_to_read: - bytes_data = ser_new.read(bytes_to_read) - ser_new.reset_input_buffer() - if bytes_data[0] == 0x5a: - indx = [ii for ii in range(0,len(baud_hex)) if \ - baud_hex[ii][0]==bytes_data[3] and - baud_hex[ii][1]==bytes_data[4] and - baud_hex[ii][2]==bytes_data[5]] - print('Set Baud Rate = {0:1d}'.format(baudrates[indx[0]])) - time.sleep(0.1) - return ser_new - else: - ser_new.write(info_packet) # try again if wrong data received - time.sleep(0.1) # wait 100ms - continue - -# -############################ -# Configurations -############################ -# -baudrates = [9600,19200,38400,57600,115200,230400,460800,921600] # baud rates -prev_indx = 4 # previous baud rate index (current TF-Luna baudrate) -prev_ser = serial.Serial("/dev/serial0", baudrates[prev_indx],timeout=0) # mini UART serial device -if prev_ser.isOpen() == False: - prev_ser.open() # open serial port if not open -baud_indx = 4 # baud rate to be changed to (new baudrate for TF-Luna) -ser = set_baudrate(baud_indx) # set baudrate, get new serial at new baudrate -set_samp_rate(100) # set sample rate 1-250 -get_version() # print version info for TF-Luna - -# -############################ -# Testing the TF-Luna Output -############################ -# -tot_pts = 100 # points for sample rate test -time_array,dist_array = [],[] # for storing values -print('Starting Ranging...') -while len(dist_array)