├── img ├── schematic.jpg └── breadboard.jpg ├── readme.md ├── linear_position.py ├── as5600.py └── test_as5600.py /img/schematic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Matthias-Wandel/AS5600-Raspberry-Pi-Python/HEAD/img/schematic.jpg -------------------------------------------------------------------------------- /img/breadboard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Matthias-Wandel/AS5600-Raspberry-Pi-Python/HEAD/img/breadboard.jpg -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 |
7 | Rotating a magnet above the chip allows it to act as a rotary encoder. 8 |
9 |
10 | Talking to the AS5600 turns out to be simple, but I found no example code for
11 | this on the internet. I always prefer to start with a working example before
12 | changing any code.
13 |
14 | So I added this github repository as an example for others to find as a starting point. 15 |
16 |
17 | Physical wring to Raspberry Pi 40-pin GPIO header: 18 |
| Pi pin | Pi function | AS5600 board 20 | |
|---|---|---|
| 01 | 3.3V DC power | VCC 21 | |
| 03 | GPIO 02 / I2C SDA | SDA 22 | |
| 05 | GPIO 03 / I2C SCL | SCL 23 | |
| 09 | Ground | GROUND and DIR 24 | |
26 | The actual code to talk to the AS5600 chip is just 9 lines of python:
27 | 28 | import smbus 29 | DEVICE_AS5600 = 0x36 # Default device I2C address 30 | bus = smbus.SMBus(1) 31 | 32 | def ReadRawAngle(): # Read angle (0-360 represented as 0-4096) 33 | read_bytes = bus.read_i2c_block_data(DEVICE_AS5600, 0x0C, 2) 34 | return (read_bytes[0]<<8) | read_bytes[1]; 35 | 36 | def ReadMagnitude(): # Read magnetism magnitude 37 | read_bytes = bus.read_i2c_block_data(DEVICE_AS5600, 0x1B, 2) 38 | return (read_bytes[0]<<8) | read_bytes[1]; 39 |40 | 41 | This code is contained in several stand alone python programs in this 42 | repository which I used for testing the AS5600 chip. 43 |
44 | I used a stepper motor to rotate the magnet to check for accuracy. 45 |
46 | I found the AS5600 provided good 12 bit precision, with little jitter 47 | for the rotation angle, but absolute rotational accuracy depends on having 48 | the magnet exactly centered above the chip. Without a precision machined 49 | jig or 3d printed jig, It is unlikely that you will be able to position 50 | the magnet accurately enough to have less than 1 degree 51 | error variation over a full rotation. 52 | 53 | -------------------------------------------------------------------------------- /linear_position.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # Code I used to show linear position with my lego rack and pinion 3 | # to turn magnet against AS5600 chip. 4 | 5 | 6 | # Requires Python smbus module. Get it using: 7 | # sudo apt-get install python3-smbus 8 | # 9 | # Make sure Pi's I2c is enabled using 10 | # sudo raspi-config 11 | # 12 | # Connect Pi's ground to GND and DIR pins 13 | # Connect Pi's 3.3 volts to VCC on AS5600 14 | # Connect Pi's I2c SCL (pin 5) to AS5600 SCL pin 15 | # Connect Pi's I2c SDA (pin 5) to AS5600 SDA pin 16 | 17 | import smbus, time, sys, math 18 | 19 | #===================================================================== 20 | # Code to read AS5600. 9 lines of python is all it takes. 21 | import smbus 22 | DEVICE_AS5600 = 0x36 # Default device I2C address 23 | bus = smbus.SMBus(1) 24 | 25 | def ReadRawAngle(): # Read angle (0-360 represented as 0-4096) 26 | read_bytes = bus.read_i2c_block_data(DEVICE_AS5600, 0x0C, 2) 27 | return (read_bytes[0]<<8) | read_bytes[1]; 28 | 29 | def ReadMagnitude(): # Read magnetism magnitude 30 | read_bytes = bus.read_i2c_block_data(DEVICE_AS5600, 0x1B, 2) 31 | return (read_bytes[0]<<8) | read_bytes[1]; 32 | 33 | #===================================================================== 34 | def MoveCursor(x,y): 35 | print("\033[%d;%dH"%(y,x),end="") 36 | 37 | def ClearScreen(): 38 | print("\033[2J",end="") 39 | 40 | 41 | #ClearScreen() 42 | 43 | cx = 0 44 | ext_angle = 2048; 45 | while True: 46 | 47 | raw_angle = 4095-ReadRawAngle() 48 | magnitude = ReadMagnitude() 49 | 50 | # If the encoder values wraps around, don't jump back, just keep going linearly. 51 | delta = (raw_angle-ext_angle) %4095 52 | if delta > 2048: delta -= 4096 53 | ext_angle = ext_angle+delta 54 | 55 | ocx = cx 56 | cx = ext_angle*130/4096+1 57 | if cx < 1: cx = 1 58 | 59 | MoveCursor(0,50) 60 | print("Raw angle: %4d"%(raw_angle), "m=%4d"%(magnitude)) 61 | 62 | # Move a square across the screen to show position 63 | for l in range(0,8): 64 | # Erase at old position 65 | MoveCursor(ocx,l+52) 66 | print(" ", end="") 67 | 68 | # Draw at new position 69 | MoveCursor(cx,l+52) 70 | print("###########", end=""); 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /as5600.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # Very simple code to read AS5600 magnetic encoder with Python 3 | # on raspberry pi 4 | # 5 | # Requires Python smbus module. Get it using: 6 | # sudo apt-get install python3-smbus 7 | # 8 | # Make sure Pi's I2c is enabled using 9 | # sudo raspi-config 10 | # 11 | # Connect Pi's ground to GND and DIR pins 12 | # Connect Pi's 3.3 volts to VCC on AS5600 13 | # Connect Pi's I2c SCL (pin 5) to AS5600 SCL pin 14 | # Connect Pi's I2c SDA (pin 5) to AS5600 SDA pin 15 | 16 | import smbus, time, sys, math 17 | 18 | #===================================================================== 19 | # Code to read AS5600. 9 lines of python is all it takes. 20 | import smbus 21 | DEVICE_AS5600 = 0x36 # Default device I2C address 22 | bus = smbus.SMBus(1) 23 | 24 | def ReadRawAngle(): # Read angle (0-360 represented as 0-4096) 25 | read_bytes = bus.read_i2c_block_data(DEVICE_AS5600, 0x0C, 2) 26 | return (read_bytes[0]<<8) | read_bytes[1]; 27 | 28 | def ReadMagnitude(): # Read magnetism magnitude 29 | read_bytes = bus.read_i2c_block_data(DEVICE_AS5600, 0x1B, 2) 30 | return (read_bytes[0]<<8) | read_bytes[1]; 31 | 32 | #===================================================================== 33 | 34 | xcenter = 60 # Assume center of text screen is 60 across, 30 down. 35 | ycenter = 30 # if your screen is 80x50, change to 40 and 25. 36 | 37 | def MoveCursor(x,y): 38 | print("\033[%d;%dH"%(y,x),end="") 39 | 40 | # Clear screen 41 | print("\033[2J",end="") 42 | 43 | 44 | # Draw x and y axis on screen 45 | for a in range (-ycenter, ycenter): 46 | MoveCursor(xcenter, ycenter+a) 47 | print("|", end="") 48 | 49 | for a in range (-xcenter, xcenter): 50 | MoveCursor(xcenter+a, ycenter) 51 | print("-") 52 | 53 | 54 | 55 | histlen = 400 56 | hist_index = 0 57 | hist = [(0,0)] * histlen 58 | 59 | while True: 60 | raw_angle = ReadRawAngle() 61 | magnitude = ReadMagnitude() 62 | 63 | MoveCursor(0,0) 64 | print("Raw angle: %4d"%(raw_angle), "m=%4d"%(magnitude), "%6.2f deg "%(raw_angle*360.0/4096)) 65 | 66 | # Now plot X and Y position by graphing on the screen 67 | xymag = magnitude/1024.0 68 | cx = int(xcenter+xcenter*xymag*math.cos(raw_angle*math.pi/2048)) 69 | cy = int(ycenter+ycenter*xymag*math.sin(raw_angle*math.pi/2048)) 70 | 71 | # delete old mark (keep up to 400 on screen) 72 | oldpos = hist[hist_index] 73 | MoveCursor(*oldpos) 74 | if oldpos[0] == xcenter: 75 | print("|",end="") 76 | elif oldpos[1] == ycenter: 77 | print("-",end="") 78 | else: 79 | print(" ",end="") 80 | 81 | # Save new mark positon in array 82 | hist[hist_index] = (cx,cy) 83 | hist_index += 1; 84 | if hist_index >= histlen: hist_index = 0 85 | 86 | # Draw a '#' at the computed X,Y coordinate 87 | MoveCursor(cx,cy) 88 | print("#",end="") 89 | 90 | #time.sleep(0.02) 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /test_as5600.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # Code I used to test accuracy of AS5600 agaisnt stepper motor, and 3 | # stepper motor accuracy against AS4500 chip 4 | # 5 | # Requires Python smbus module. Get it using: 6 | # sudo apt-get install python3-smbus 7 | # 8 | # Make sure Pi's I2c is enabled using 9 | # sudo raspi-config 10 | # 11 | # Connect Pi's ground to GND and DIR pins 12 | # Connect Pi's 3.3 volts to VCC on AS5600 13 | # Connect Pi's I2c SCL (pin 5) to AS5600 SCL pin 14 | # Connect Pi's I2c SDA (pin 5) to AS5600 SDA pin 15 | 16 | import time, sys, math 17 | import RPi.GPIO as GPIO 18 | 19 | #=============================================================== 20 | # Code to read AS5600. 9 lines of python is all it takes. 21 | import smbus 22 | DEVICE_AS5600 = 0x36 # Default device I2C address 23 | bus = smbus.SMBus(1) 24 | 25 | def ReadRawAngle(): # Read angle (0-360 represented as 0-4096) 26 | read_bytes = bus.read_i2c_block_data(DEVICE_AS5600, 0x0C, 2) 27 | return (read_bytes[0]<<8) | read_bytes[1]; 28 | 29 | def ReadMagnitude(): # Read magnetism magnitude 30 | read_bytes = bus.read_i2c_block_data(DEVICE_AS5600, 0x1B, 2) 31 | return (read_bytes[0]<<8) | read_bytes[1]; 32 | 33 | #=============================================================== 34 | # Code to control stepper motor 35 | 36 | def init_motor(motor): 37 | global line_clock, line_dir, line_enable 38 | 39 | GPIO.setmode(GPIO.BCM) 40 | GPIO.setwarnings(False) 41 | 42 | if motor: 43 | line_clock = 23 44 | line_dir = 24 45 | line_enable = 25 46 | else: 47 | line_clock = 26 48 | line_dir = 19 49 | line_enable = 13 50 | 51 | GPIO.setup(line_enable, GPIO.OUT, initial=False) # Start enabled 52 | GPIO.setup(line_dir, GPIO.OUT, initial=False) 53 | GPIO.setup(line_clock, GPIO.OUT, initial=False) 54 | 55 | if motor == 0: time.sleep(0.5) # this one takes a while to wake up. 56 | 57 | def DoSteps(steps, delay = 1): 58 | global line_clock, line_dir, line_enable 59 | duse = delay/1000 60 | GPIO.output(line_enable, 0) # enable 61 | 62 | if steps < 0: 63 | steps = -steps 64 | GPIO.output(line_dir, False) 65 | else: 66 | GPIO.output(line_dir, True) 67 | 68 | for x in range (0,steps): 69 | GPIO.output(line_clock, True) 70 | #time.sleep(duse) 71 | GPIO.output(line_clock, False) 72 | time.sleep(duse) 73 | 74 | #=============================================================== 75 | # Code to move cursor 76 | 77 | def MoveCursor(x,y): 78 | print("\033[%d;%dH"%(y,x),end="") 79 | 80 | def ClearScreen(): 81 | print("\033[2J",end="") 82 | 83 | #=============================================================== 84 | init_motor(1) 85 | 86 | if 0: 87 | # check the motor 88 | print("do steps") 89 | DoSteps(200*8*5) # full turn. 90 | sys.exit() 91 | 92 | 93 | raw_angle_start = ReadRawAngle() 94 | StepCount = 0 95 | print("raw_angle_start = ",raw_angle_start); 96 | 97 | of = open("angles.csv","w"); 98 | 99 | while True: 100 | time.sleep(0.1) 101 | raw_angle = ReadRawAngle() 102 | magnitude = ReadMagnitude() 103 | 104 | SensorAngle = (raw_angle+4096-raw_angle_start) & 4095; 105 | SensorAngleDeg = (SensorAngle * 360.0)/4096; 106 | MotorAngleDeg = StepCount * 360.0 / (200*8) # 8x microstepping 107 | 108 | mag = magnitude/4096.0 109 | diff = SensorAngleDeg-MotorAngleDeg 110 | if diff >= 360: diff -= 360 111 | if diff <= -360: diff += 360 112 | print ("%6.2f,%6.2f, %5.3f d=%5.3f"%(MotorAngleDeg, SensorAngleDeg, mag, diff)) 113 | print ("%6.2f,%6.2f, %5.3f"%(MotorAngleDeg, SensorAngleDeg, mag), file=of) 114 | 115 | increment = 1 116 | DoSteps(increment) 117 | StepCount += increment 118 | if StepCount > 200*8: StepCount -= 200*8 119 | 120 | 121 | 122 | --------------------------------------------------------------------------------