element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Experimenting with Current Sense Amplifiers
  • Challenges & Projects
  • Design Challenges
  • Experimenting with Current Sense Amplifiers
  • More
  • Cancel
Experimenting with Current Sense Amplifiers
Challenge Blog Safer 3D Printer - Blog #5 - It Vorks!
  • Blog
  • Forum
  • Documents
  • Files
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: aspork42
  • Date Created: 8 Jun 2022 2:30 AM Date Created
  • Views 1669 views
  • Likes 8 likes
  • Comments 7 comments
  • 3d printer
  • Current 6 Click
  • current sense amplifier
  • MAX40080
  • Experimenting with Current Sense Amplifiers
Related
Recommended

Safer 3D Printer - Blog #5 - It Vorks!

aspork42
aspork42
8 Jun 2022
Safer 3D Printer - Blog #5 - It Vorks!

In my final post for this build, I'll share my working project and some thoughts I've had along the way.

What did I build?

imageUsing the Current6Click current monitoring board mounted on a Pi3 Click Shield, and mounted on a RaspberryPi, I was able to build something which can detect wiring faults. The Current6Click board uses a MAX40080 current sense chip and comes as a ready-to-go expansion board with shunt resistor and other supporting circuitry. The goals were to be able to detect intermittent opens in the wires going to the hot end and heated bed on a 3D printer. Opens and Shorts can also be detected. 

You can read my progress in these posts:

  1. Blog #1 Introduction and goals
  2. Blog #2 Getting started with the Current6Click
  3. Blog #3 Troubles resolved talking to chip, but lots more hurdles
  4. Blog #4 Nearly functionally complete

How does it work?

The MAX40080 can measure both current and voltage at the same time. A 3D printer cycles power on and off to the hot parts to maintain a target temperature. This means that whenever there is voltage available, current should be flowing. My code first sees if there is voltage; then it reads the ADC at about 500 times/second and monitors the current. On the hot end of my printer, we should have about 12 volts and flow about 2.75 amps. If there is a fatigued or damaged wire, there would be a very intermittent open circuit where the MAX40080 can see 12V but current drops to zero. In the case of a short, the current would spike very high very quickly; still at about the 12v level. An open circuit would look the same as the intermittent, but last longer. Most printers these days come with 'thermal runaway monitoring' in software, but some don't; and some aren't turned on by default leaving it up to the user to know and enable the feature. That feature however works by monitoring the temperature feedback and the software's own output to run the heaters. If the thermocouple shows the nozzle getting colder and not heating up when the controller is trying to heat it, this causes the alarm.

However, in the case of a fatigued wire or loose connection, this would never be caught. Unfortunately, these bad connections are a potential fire risk as more current has to flow through the few remaining strands of copper or the little bit of connector that is touching a terminal. This causes excessive heat buildup which can cause lots of other issues. Short of adding a thermal camera, there really isn't a way to directly look for poor connections. Imaging a printer that's been in service for a few years and 1000's of hours. There could be certain parts of the travel that stress the wires just that little bit more and break it down.

I've had this idea rolling around in my head to detect a wiring fault on these large current-carrying wires in a printer for a while. I had originally though of doing it via discrete components - a traditional op-amp & shunt resistor; running the voltage through a comparator and AND'ing with the 12V signal. When the voltage rises above the level set in the comparator, it would open a relay to signal a fault. This MAX40080 can read very fast and still seems to do the trick just fine, and I found that it was pretty easy in software to tweak values and setpoints and add other integration like MQTT.

The latest updates to get this puppy running

My previous post showed the system nearly complete. The RaspberryPi was talking to the Click board and getting measurements. I was able to detect shorts, opens, and broken wires. I was using an external relay on an Arduino to cycle ON/OFF the 12V feeding into my project to simulate a printer cycling the hot end; plus using a DC load to pull current. I still wanted to add MQTT support and that wasn't done yet. The major issue I had run into was that about 5% of the time, when the Arduino relay clicked off, my system would detect a "fault" because the current would drop to zero somewhere around 50ms before the voltage would drop out.

In this latest post, I was able to overcome that. I put a check in the code to flag these bad readings and start a timer.

            if(myA < myMinCurrent and myV> myTurnOnVoltage):
                if (0==NCCount):
                    NCTime =time.time()
                NCCount += 1

Then, if 12V drops out within 0.05 seconds then we're OK. If 12V stays present after that, throw a fault.

            # If we've seen no current for longer than a set time, disable relay
            if(NCCount >0 and time.time() > NCTime + 0.05 and myV > myTurnOnVoltage):
                print("Yo dude - fix ya wires! I'm undercurrent")
                print("Readings during fault: V:", myV, " A:", myA, "read/s:", readCount, "NC Count:", NCCount)
                disableRelay()
                NCCount = 0
                time.sleep(.2)
                running = False 

Adding in MQTT support was pretty straight-forward and only took about an hour from start to finish. I just needed some additional code tweaks to enable-disable the relay from MQTT and not freak out the rest of my program. I was able to add handlers to play with the Overvoltage/Overcurrent setpoints; then run my power supply up and down but alas was never able to get reliable results from it. I would do a write, then do a read back and verify that the correct setpoint actually stuck in memory.

(This code snipped was posted in my blog #4 buried somewhere in the larger code)

def setOverCurrentThreshold(ampsVal):
#     memory address is 7 bits; 0-127; ranged from 0A - Max (either 1 or 5 depending on setting)
#     Default value = 0x30
    global InputRangeHigh
    
    myval = i2cbus.read_byte_data(current6ClickAddress, 0x04) 
    print('Starting Overcurrent Threshold: ', hex(myval))    
    
#     multFactor = 0.007874
#     if InputRangeHigh: multFactor = 0.03937
#     ampsVal = ampsVal / multFactor *100
#     
    newVal = round(ampsVal*127)
    print(newVal)
    i2cbus.write_byte_data(current6ClickAddress, 0x04, newVal) 
    
    myval = i2cbus.read_byte_data(current6ClickAddress, 0x04)
    myval = round(myval/127, 2)
    if InputRangeHigh: myval = myval * 5
    
    print('Overcurrent Threshold: ', myval)

I had already wrote code to capture and handle all the different interrupts. This section had been in the code for a while; and I only ever saw just a few random interrupts OTHER than the Fifo overflow.

def readStatus():
    global activeInterrupt
    myval = i2cbus.read_word_data(current6ClickAddress, 0x02) 
    print('Interrupt Alert Status: ', hex(myval))
    if(myval & 0x01):
        print("Wake up alert")
    if(myval & 0x02):
        print("Conversion ready")        
    if(myval & 0x04):
        print("Overflow Current")
    if(myval & 0x08):
        print("Overflow Voltage")
        global hiVolt
        hiVolt = True
    if(myval & 0x10):
        print("Underflow Voltage")
        hiVolt = False
    if(myval & 0x20):
        print("I2C Timeout")
    if(myval & 0x40):
        print("FIFO Alarm")
    if(myval & 0x80):
        print("FIFO Overflow")
    
#     print("Clearing alert")
    i2cbus.write_word_data(current6ClickAddress,0x02, myval) # clear alert
#     print("Cleared")
    activeInterrupt = False

I also had fun with using bitwise operations to get my settings dialed in. When I had a 'multiple choice' option, I would write out the different options on a line using btiwise OR, then I could easily turn on/off the settings without having to go back to the datasheet.

# Confgure digital averaging
    myval = myval | 0x0000 #no average
#     myval = myval | 0x1000 #average 8
#     myval = myval | 0x2000 #average 16
#     myval = myval | 0x3000 #average 32
#     myval = myval | 0x4000 #average 64
#     myval = myval | 0x5000 #average 128
 
    i2cbus.write_word_data(current6ClickAddress, 0x00, myval)

This snip below is my main code loop that reads as fast as possible (about 500Hz) and writes snapshots to the console & MQTT every two seconds.

 while True:
        if(time.time() > lastPrint+2):
            print("Not running")
            lastPrint = time.time()

        while(running):

#     #         while (readVoltage() > myTurnOnVoltage):

            SamplesToAverage = 1
            myV = 0
            for x in range(SamplesToAverage):
    #                 readCount += 1
                myV += readVoltage()
            myV = round(myV/SamplesToAverage,2)
            myA = 0
            for x in range(SamplesToAverage):
                myA += readAmps()
            myA = round(myA/SamplesToAverage,2)
            
            readCount += 1
            
            if(myA > myMaxCurrent):
                print("!! Overcurrent Alert!! Shorted wires?")
                print("Readings during fault: V:", myV, " A:", myA, "read/s:", readCount)
                disableRelay()
                time.sleep(.1)
                break
                    
            if(myA < myMinCurrent and myV> myTurnOnVoltage):
                if (0==NCCount):
                    NCTime =time.time()
                NCCount += 1
            
            # If we've seen no current for longer than a set time, disable relay
            if(NCCount >0 and time.time() > NCTime + 0.05 and myV > myTurnOnVoltage):
                print("Yo dude - fix ya wires! I'm undercurrent")
                print("Readings during fault: V:", myV, " A:", myA, "read/s:", readCount, "NC Count:", NCCount)
                disableRelay()
                NCCount = 0
                time.sleep(.2)
                running = False 
#                 break

            if(time.time() > lastPrint+2):
                print("V:", myV, " A:", myA, "read/s:", readCount/2)
                publish(client, "current/volt", myV)
                publish(client, "current/amps", myA)
                publish(client, "current/readspeed", readCount/2)
                lastPrint = time.time()
                readCount = 0

            if(activeInterrupt):
                readStatus()
                    
            if(readVoltage() < myTurnOffVoltage):
                NCCount = 0
                NCTime =time.time()

Installing on a real 3D Printer

imageAs I was working through this project, I really wasn't sure if I could get it stable enough to actually work. On single bad reading from the ADC and it would cut power to the hot end. But as I worked through the code, I got more and more confidence and finally hooked it up and ran a print job.

There were some issues when I went to hook it and and finally power it on. I found out that my printer switches the ground side of the hot end; not the positive. I was set up for doing high-side sensing, so had to stop and think for a minute to get the wiring in correctly. Then there was the cycle rate of the hot end. In watching the temperature graphs, I was anticipating in the 2-3 second cycle range for on/off cycles. It seems that the hot end is actually more on a PWM setup at something like 5-10 times/second. I'm really glad I did my troubleshooting with the relay first because it would have been a real *** to diagnose the issues at this speed. I used 2-3 second cycles in my testing with the Arduino. 

When watching the video linked below, there is a little blue light that flashes showing the cycling on the hot end. 

imageOne issue I found with the dev board is that the terminal strips are super tiny. I had to use my smallest ferrules to get them to go into the connectors. Pushing 5 amps through wire small enough for these ferrules would be something. I did monitor it with my thermal camera and there really wasn't any extra heat on the Current6Click board or wires at 2.75 amps. The RaspberryPi was roasting though, and my relay was also getting warm from its coils. 

I probably had another hour or two of test & tune before I let an entire print run. I was dialing in all the setpoints like current - in testing I had it capped at 2Amps, and it took me like five minutes to realize that my system was cutting off power because actual (read: normal) current draw on this system was more like 2.75 amps.

I also managed to confuse myself with dialing in the MQTT settings to enable/disable the relay 'at will' - I would re-enable it and my program would find low current and cut the relay right back off. Turned out, everything was working as it should because I had left the Wago lever nut loose and I really did have bad wiring. 

What did I learn?

I certainly lost a lot of time on this project because the lack of a library. I did have to break down and peek at other peoples code to get hints. I do enjoy doing this type of thing but for whatever reason this project was really kicking my butt in my expectations of how the chip operates and my abilities to get the most out of it. I got better at doing bitwise/hex/binary type conversions. I also have wanted to do more in Python and this was a good chance to do more of that. I found it annoying how Python claims to be a 'typeless' language but constantly complains when you pass the wrong variable type into a function. I use Thonny for a code editor. It comes built-in on Raspbian OS. It was definitely a step down from using VSCode or Pycharm like I'm used to. But since I couldn't get Pycharm to run on the Pi, it still did the trick. I was able to do 100% of my coding on the Pi in Thonny.

As with all of the E14 projects and contests, this once again was able to push me to try new things and experiment. And also I've loved seeing the huge amount of variety in what others have come up with. 

Here is my complete spaghetti-code for those brave enough!

import RPi.GPIO as GPIO
# import board
# import busio
# i2c = busio.I2C(board.SCL, board.SCA)
from smbus import SMBus
#from PyCRC.CRCCCITT import CRCCCITT
from paho.mqtt import client as mqtt_client
import random
# import crc8

import time

activeInterrupt = False # to handle interrupt pin

InputRangeHigh = True # True for 5Amp limit. False for 1Amp limit

current6ClickAddress = 0x21
CurrentSenseEnablePin = 8
OvercurrentAlertPin = 6
RelayPin = 26

running = True #If we should run the main loop

myMaxCurrent = 3.5
myMinCurrent = 0.3
myTurnOnVoltage = 10  # when to start assuming that the system is running
myTurnOffVoltage = 2

GPIO.setmode(GPIO.BCM)

GPIO.setup(CurrentSenseEnablePin, GPIO.OUT)
GPIO.setup(RelayPin, GPIO.OUT)
GPIO.setup(OvercurrentAlertPin, GPIO.IN)


#Create Instance of SMBus to talk to device
i2cbus = SMBus(1)

#Mqtt setup
broker = '1.2.3.4' #use your broker
port = 1883
client_id =f'CurrentSense-{random.randint(0,1000)}'
username = 'myuser' #use your username
password = 'mypass' #use your password
# client =''

#enable relay
def enableRelay():
    GPIO.output(RelayPin, GPIO.HIGH)
    
def disableRelay():
    GPIO.output(RelayPin, GPIO.LOW)

def connect_mqtt():
    
    def on_connect(client, userdata, flags, rc):
        if rc == 0:
            print("Connected to MQTT Broker")
        else:
            print("Failed to connect to MQTT Broker")
        
    client = mqtt_client.Client(client_id)
    client.username_pw_set(username, password)
    client.on_connect = on_connect
    client.connect(broker, port)
    return client

def publish(client, topic, payload):
    msg_count =0
    result=client.publish(topic, payload)
    return result

def subscribe(client: mqtt_client):
    global running
    
    def on_message(client, userdata, msg):
        print(f"got '{msg.payload.decode()}' from '{msg.topic}' topic")
        if(msg.topic == "current/OCThresh"):
            myval = float(str(msg.payload.decode()))
            setOverCurrentThreshold(myval)
            print("New OC Thresh of ", myval)
            
        if(msg.topic == "current/OVThresh"):
            myval = float(str(msg.payload.decode()))
            setOverVoltageThreshold(myval)
            print("New Voltage Thresh of ", str(myval))
            
        if(msg.topic == "current/enable"):
            global running
            if(msg.payload.decode() == "on"):
                enableRelay()
                time.sleep(0.2)
                running = True
                print("re-enable relay from MQTT")
            if(msg.payload.decode() == "off"):
                disableRelay()
                running = False
                print("disable relay from MQTT")            

    client.subscribe("current/OCThresh")
    client.subscribe("current/OVThresh")
    client.subscribe("current/enable")
    client.on_message = on_message

def setConfig():
    global InputRangeHigh
    
    myval = i2cbus.read_word_data(current6ClickAddress, 0x00)
    print("Starting Config: ", myval)
    myval = 0x00 # disable Packet Error Checking (PEC); leave all other values at default.
    
    i2cbus.write_i2c_block_data(current6ClickAddress, 0x00, [myval, 0x00, 0xB7]) # Disable PEC
    
    #i2cbus.write_i2c_block_data(current6ClickAddress, 0x00, [0x7e, 0x00, 0xc3])
    
    # Configuration register
    myval = myval | 0b00000011 # enable Active mode with bits 0,1.
#     myval = myval | 0b00001000 # disable I2C Timeout
    myval = myval | 0b00010000 # Alert response time. 0=unfiltered. 1= four consec. readings
#     myval = myval | 0b00100000 # PEC
    if not InputRangeHigh:
#         print("Disable High Current Range")
        myval = myval | 0b01000000 # Input Range - write 1 for Low (5Amps max)

#     myval = myval | 0b10000000 # Stay HS Mode

    print("proposed config: ", hex(myval))

#     Digital averaging - makes erratic faults and readings :(
    myval = myval | 0x0000 #no average
#     myval = myval | 0x1000 #average 8
#     myval = myval | 0x2000 #average 16
#     myval = myval | 0x3000 #average 32
#     myval = myval | 0x4000 #average 64
#     myval = myval | 0x5000 #average 128

#     print("proposed config: ", hex(myval))
    
    i2cbus.write_word_data(current6ClickAddress, 0x00, myval)
#     i2cbus.write_byte_data(current6ClickAddress, 0x00, myval)
    
#     myval = i2cbus.read_word_data(current6ClickAddress, 0x00)
#     print("Config now in chip: ", hex(myval))
    
    #Fifo settings
#     myFifo = i2cbus.read_word_data(current6ClickAddress, 0x0A)
#     print("Startup Fifo config: ", hex(myFifo))
    
    myFifo = 0x0000
    #myFifo = myFifo | 0x8000 # flush
    #myFifo = myFifo | 0x0003 # disable fifo
    myFifo = myFifo | 0x0002 # fifo for V & C
    myFifo = myFifo | 0x4000 # enable rollover of Fifo
    
    i2cbus.write_word_data(current6ClickAddress,0x0A, myFifo)
    
#     myInts = i2cbus.read_byte_data(current6ClickAddress, 0x14)
#     print("Interrupts currently set: ", myInts)
    
    # configure interrupts
    myInts = 0x0 
    myInts = myInts | 0b00000001 # wake-up enable
    myInts = myInts | 0b00000010 # Conversion ready
    myInts = myInts | 0b00000100 # Overflow current
    myInts = myInts | 0b00001000 # overflow Volts
    myInts = myInts | 0b00010000 # Underflow Volts
    myInts = myInts | 0b00100000 # I2C Timeout
    myInts = myInts | 0b01000000 # Alarm overflow 
#     myInts = myInts | 0b10000000 # Overflow Mask **Need to disable this to avoid overflow interrups
#     print("Proposed Interrupts: ", myInts)
    i2cbus.write_byte_data(current6ClickAddress, 0x14, myInts)
# 
#     myInts = i2cbus.read_byte_data(current6ClickAddress, 0x14)
#     print("Interrupts currently set: ", myInts)
    
#     myFifo = i2cbus.read_word_data(current6ClickAddress, 0x0A)
#     print("New fifo on chip memory: ", hex(myFifo))
 
#     time.sleep(0.1)
#     mynewval = i2cbus.read_word_data(current6ClickAddress, 0x00)
#     print('current config: ', hex(mynewval))

hiVolt = False # if we've got power going to printer nozzle

def readStatus():
    global activeInterrupt
    myval = i2cbus.read_word_data(current6ClickAddress, 0x02) 
    print('Interrupt Alert Status: ', hex(myval))
    if(myval & 0x01):
        print("Wake up alert")
    if(myval & 0x02):
        print("Conversion ready")        
    if(myval & 0x04):
        print("Overflow Current")
    if(myval & 0x08):
        print("Overflow Voltage")
        global hiVolt
        hiVolt = True
    if(myval & 0x10):
        print("Underflow Voltage")
        hiVolt = False
    if(myval & 0x20):
        print("I2C Timeout")
    if(myval & 0x40):
        print("FIFO Alarm")
    if(myval & 0x80):
        print("FIFO Overflow")
    
#     print("Clearing alert")
    i2cbus.write_word_data(current6ClickAddress,0x02, myval) # clear alert
#     print("Cleared")
    activeInterrupt = False
    
def readOverCurrentThreshold():
    myval = i2cbus.read_byte_data(current6ClickAddress, 0x04) 
    print('Overcurrent Threshold: ', hex(myval))
    
def readVoltage():
    fifod = i2cbus.read_i2c_block_data(current6ClickAddress,0x0E,2)[::-1]
    val = 0
    for x in range(0,2):
        val = val << 8 | fifod[x]
#     print(fifod)
    dvalid = val & 0x00008000
    dsign = val & 0x00001000
    dvalue = val & 0x00000FFF
#     print("Voltage raw: ", dvalue)
    if dsign != 0 :
        dvalue = dvalue - 4096
    if dvalid != 0 :
        dvalue = dvalue / 4095.0 * 36.0
    dvalue = round(dvalue, 2)
#     print("V:", dvalue)
#     i2cbus.write_word_data(current6ClickAddress,0x0A, 0x8000) # flush FIFO

    return dvalue

def readAmps():
    global InputRangeHigh
    fifod = i2cbus.read_i2c_block_data(current6ClickAddress,0x0c,2)[::-1]
    val = 0
    for x in range(0,2):
        val = val << 8 | fifod[x]
    dvalid = val & 0x00008000
    dsign = val & 0x00001000
    dvalue = val & 0x00000FFF
    if dsign != 0 :
        dvalue = dvalue - 4096
    if dvalid != 0 :
        dvalue = dvalue / 4095
    if InputRangeHigh: dvalue = dvalue*5 #correct for high-current mode
    dvalue = round(dvalue, 3)
#     print("A:", dvalue)
    return dvalue

def setOverCurrentThreshold(ampsVal):
#     memory address is 7 bits; 0-127; ranged from 0A - Max (either 1 or 5 depending on setting)
#     Default value = 0x30
    global InputRangeHigh
    
    myval = i2cbus.read_byte_data(current6ClickAddress, 0x04) 
    print('Starting Overcurrent Threshold: ', hex(myval))    
    
#     multFactor = 0.007874
#     if InputRangeHigh: multFactor = 0.03937
#     ampsVal = ampsVal / multFactor *100
#     
    newVal = round(ampsVal*127)
    print(newVal)
    i2cbus.write_byte_data(current6ClickAddress, 0x04, newVal) 
    
    myval = i2cbus.read_byte_data(current6ClickAddress, 0x04)
    myval = round(myval/127, 2)
    if InputRangeHigh: myval = myval * 5
    
    print('Overcurrent Threshold: ', myval)

def setOverVoltageThreshold(VoltsVal):
#     memory address is 6 bits; 0-63; ranged from 0-36v
#     print("Setting Overvoltage Threshold to: ", VoltsVal)
    myval = int(round(VoltsVal / 0.5625, 0))
#     print(myval)
    i2cbus.write_byte_data(current6ClickAddress, 0x05, myval) 
    
    myval = i2cbus.read_byte_data(current6ClickAddress, 0x05) 
    print('Overvoltage Threshold now in chips memory: ', myval)

def setUnderVoltageThreshold(VoltsVal):
#     memory address is 6 bits; 0-63; ranged from 0-36v
#     print("Setting Overvoltage Threshold to: ", VoltsVal)
    myval = int(round(VoltsVal / 0.5625, 0))
#     print(myval)
    i2cbus.write_byte_data(current6ClickAddress, 0x06, myval) 
    
    myval = i2cbus.read_byte_data(current6ClickAddress, 0x06) 
    print('Undervoltage Threshold now in chips memory: ', myval)

def AlertPinCallback(myfault):
    global activeInterrupt
    activeInterrupt = True
    print("**Alert Pin Went High**")

GPIO.add_event_detect(OvercurrentAlertPin, GPIO.RISING)
GPIO.add_event_callback(OvercurrentAlertPin, AlertPinCallback)


def setup():
    global activeInterrupt
    
    global myMaxCurrent
    global myMinCurrent
    global myTurnOnVoltage 
    global myTurnOffVoltage
    
    global client
    client = connect_mqtt()
    client.loop_start()
    subscribe(client)
    
#     print("active alert status: ", activeInterrupt)
    enableRelay()
    #enable the current sense pin on Current6Click
    GPIO.output(CurrentSenseEnablePin, GPIO.HIGH)
#     time.sleep(0.5)
#     time.sleep(3)
    setConfig()
 
#     readOverCurrentThreshold()
    setOverCurrentThreshold(.1) # Amps
#     setOverVoltageThreshold(3) # set over-voltage limit (Volts)
#     setUnderVoltageThreshold(5) # set under-voltage level
#     print("active alert status: ", activeInterrupt)
    

def main():
    lastPrint = time.time()
    global activeInterrupt
    
    global myMaxCurrent
    global myMinCurrent
    global myTurnOnVoltage 
    global myTurnOffVoltage
    
    global client
    
    print("Program starting")
    global running
    running = True
    readCount = 0
    NCCount = 0 # NoCurrent Count
    NCTime = time.time()
    while True:
        if(time.time() > lastPrint+2):
            print("Not running")
            lastPrint = time.time()

        while(running):

#     #         while (readVoltage() > myTurnOnVoltage):

            SamplesToAverage = 1
            myV = 0
            for x in range(SamplesToAverage):
    #                 readCount += 1
                myV += readVoltage()
            myV = round(myV/SamplesToAverage,2)
            myA = 0
            for x in range(SamplesToAverage):
                myA += readAmps()
            myA = round(myA/SamplesToAverage,2)
            
            readCount += 1
            
            if(myA > myMaxCurrent):
                print("!! Overcurrent Alert!! Shorted wires?")
                print("Readings during fault: V:", myV, " A:", myA, "read/s:", readCount)
                disableRelay()
                time.sleep(.1)
                break
                    
            if(myA < myMinCurrent and myV> myTurnOnVoltage):
                if (0==NCCount):
                    NCTime =time.time()
                NCCount += 1
            
            # If we've seen no current for longer than a set time, disable relay
            if(NCCount >0 and time.time() > NCTime + 0.05 and myV > myTurnOnVoltage):
                print("Yo dude - fix ya wires! I'm undercurrent")
                print("Readings during fault: V:", myV, " A:", myA, "read/s:", readCount, "NC Count:", NCCount)
                disableRelay()
                NCCount = 0
                time.sleep(.2)
                running = False 
#                 break

            if(time.time() > lastPrint+2):
                print("V:", myV, " A:", myA, "read/s:", readCount/2)
                publish(client, "current/volt", myV)
                publish(client, "current/amps", myA)
                publish(client, "current/readspeed", readCount/2)
                lastPrint = time.time()
                readCount = 0

            if(activeInterrupt):
                readStatus()
                    
            if(readVoltage() < myTurnOffVoltage):
                NCCount = 0
                NCTime =time.time()
#                 running = False
#                 print("Voltage below limit")
#                 break

            
            
#     time.sleep(1)
#     print("Paused")
#     running = True
        

try:
    if __name__ =="__main__":
        setup()
        main()

except KeyboardInterrupt:
    print("Keyboard interrupt detected")
    #catch any Cntl+C exits
    pass

except Exception as e:
    print("Exception")
    print(e)
    pass

finally:
    print("cleaning up")
    GPIO.cleanup()
    

Wanna see it run???

I know I do! Here is a video of testing this late last night. Around 1:05, watch the little red LED next to the blue relay turn off when I open the Wago Lever nut.

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

Let me know what you think down in the dooblie-doo!

  • Sign in to reply
Parents
  • genebren
    genebren over 3 years ago

    Very cool!  This is a great test of the current monitoring device (MAX40080).  This is a project to go back to as a reference should I want to add some similar monitoring to my 3D printer.  Well done!

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
Comment
  • genebren
    genebren over 3 years ago

    Very cool!  This is a great test of the current monitoring device (MAX40080).  This is a project to go back to as a reference should I want to add some similar monitoring to my 3D printer.  Well done!

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
Children
  • aspork42
    aspork42 over 3 years ago in reply to genebren

    Thanks - it certainly did provide a feeling of "OMG it actually works!" despite the fact that I couldn't find any reason it shouldn't work Slight smile

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • aspork42
    aspork42 over 3 years ago in reply to genebren

    What's neat is that this method could work for lots of applications where you're interested in fatigued wires. The printer is a good one because we expect to have some fatiguing over time due to the moving parts; and we've got a (relatively) high-current element moving around. And some printers (mine in particular) have a bit of a reputation for fires. 

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube