diff --git a/as5600_tca9548a.py b/as5600_tca9548a.py new file mode 100644 index 0000000..0ef9261 --- /dev/null +++ b/as5600_tca9548a.py @@ -0,0 +1,144 @@ +#!/usr/bin/python3 +# Extended version of Matthias Wandel AS5600 example code: +# https://github.com/Matthias-Wandel/AS5600-Raspberry-Pi-Python/blob/master/as5600.py +# +# This extended version is for use with TCA9548A multiple(xer) AS5600 encoders +# https://www.ti.com/lit/ds/symlink/tca9548a.pdf +# https://www.mouser.com/pdfdocs/AMS_AS5600_Datasheet_EN.PDF +# +# Usage: python3 as5600_tca9548a.py or empty +# No given argument will disable TCA9548A switching and read from 0x36 directly +# channel is a number from 0 to 7, which will select the TCA9548A channel +# +# Very simple code to read AS5600 magnetic encoder with Python +# on raspberry pi +# +# Requires Python smbus module. Get it using: +# sudo apt-get install python3-smbus +# +# Make sure Pi's I2c is enabled using +# sudo raspi-config +# +# Connect Pi's ground to GND and DIR pins +# Connect Pi's 3.3 volts to VCC on AS5600 +# Connect Pi's I2c SCL (pin 5) to AS5600 SCL pin +# Connect Pi's I2c SDA (pin 5) to AS5600 SDA pin +# +# Watchout: use a level shifter if you are using 5V AS5600 +# ====================================================================== +# bash commands: +# +# read i2c-bus: sudo i2cdetect -y 1 +# set TCA9548A switching off: sudo i2cset -y 1 0x70 0x00 +# +# set TCA9548A channel-0: sudo i2cset -y 1 0x70 0x01 +# set TCA9548A channel-1: sudo i2cset -y 1 0x70 0x02 +# +# read AS5600 raw angle: sudo i2cget -y 1 0x36 0x0C +# read AS5600 magnitude: sudo i2cget -y 1 0x36 0x1B + +import smbus, time, sys, math + +DEVICE_TCA9548A = 0x70 # TCA9548A default address (0x70-0x77) +DEVICE_AS5600 = 0x36 # AS5600 fixed address, AS5600L version is changeable +bus = smbus.SMBus(1) + +# function TCA9548A channel switching +def SelectTCAChannel(channel): + if channel < 0 or channel > 7: + raise ValueError("channel must be between 0 and 7 ") + bus.write_byte(DEVICE_TCA9548A, 1 << channel) + +#===================================================================== +# Code to read AS5600. x lines of python is all it takes. +def ReadRawAngle(): # Read angle (0-360 represented as 0-4096) + read_bytes = bus.read_i2c_block_data(DEVICE_AS5600, 0x0C, 2) + return (read_bytes[0] << 8) | read_bytes[1] + +def ReadMagnitude(): # Read magnetism magnitude + read_bytes = bus.read_i2c_block_data(DEVICE_AS5600, 0x1B, 2) + return (read_bytes[0] << 8) | read_bytes[1] + +#===================================================================== +xcenter = 40 # Assume center of text screen is 80 across, 24 down. +ycenter = 12 # if your screen is 80x50, change to 40 and 25. + +def MoveCursor(x, y): + print("\033[%d;%dH" % (y, x), end="") + +# if there is a command line argument, it is the TCA9548A channel +# and the TCA9548A switching is activated +try: + if len(sys.argv) != 2: + print("no channel given, direct access to AS5600") + #DisableTCAChannels() + current_channel = None # no channel + else: + current_channel = int(sys.argv[1]) + if current_channel < 0 or current_channel > 7: + raise ValueError + SelectTCAChannel(current_channel) +except ValueError: + print("error: channel must be between 0 and 7") + sys.exit(1) + +# Clear screen +print("\033[2J", end="") + +# Draw x and y axis on screen +for a in range(-ycenter, ycenter): + MoveCursor(xcenter, ycenter + a) + print("|", end="") + +for a in range(-xcenter, xcenter): + MoveCursor(xcenter + a, ycenter) + print("-") + +histlen = 400 +hist_index = 0 +hist = [(0, 0)] * histlen + +# TCA9548A-channel switching +if current_channel is not None: + SelectTCAChannel(current_channel) + +while True: + # read + try: + raw_angle = ReadRawAngle() + magnitude = ReadMagnitude() + + MoveCursor(0, 0) + if current_channel is not None: + print("Multiplexer Channel: %d | Raw angle: %4d" % (current_channel, raw_angle), "m=%4d" % (magnitude), "%6.2f deg " % (raw_angle * 360.0 / 4096)) + else: + print("Direct Access. Raw angle: %4d" % (raw_angle), "m=%4d" % (magnitude), "%6.2f deg " % (raw_angle * 360.0 / 4096)) + + # X- und Y-Position berechnen und auf dem Bildschirm darstellen + xymag = magnitude / 1024.0 + cx = int(xcenter + xcenter * xymag * math.cos(raw_angle * math.pi / 2048)) + cy = int(ycenter + ycenter * xymag * math.sin(raw_angle * math.pi / 2048)) + + # Alte Markierung löschen (bis zu 400 auf dem Bildschirm) + oldpos = hist[hist_index] + MoveCursor(*oldpos) + if oldpos[0] == xcenter: + print("|", end="") + elif oldpos[1] == ycenter: + print("-", end="") + else: + print(" ", end="") + + # Save new mark positon in array + hist[hist_index] = (cx, cy) + hist_index += 1 + if hist_index >= histlen: + hist_index = 0 + + # Draw a '#' at the computed X,Y coordinate + MoveCursor(cx, cy) + print("#", end="") + + except Exception as e: + MoveCursor(0, 0) + print(f"error while reading: {e}", end="")