Skip to content

Commit

Permalink
update utils
Browse files Browse the repository at this point in the history
  • Loading branch information
anderssandstrom committed Sep 11, 2024
1 parent f251439 commit c4c9929
Show file tree
Hide file tree
Showing 4 changed files with 224 additions and 77 deletions.
66 changes: 65 additions & 1 deletion hugo/content/manual/troubleshooting/hardware.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The EL9221-5000 has one channel and can therefore only the top button is needed
#### el9227-5500
The EL9227-5500 is a 2 channel module and normally both channels needs to be enabled by pressing both the top and bottom long LED. if only one are pressed it could result in that the power to the communication is fine but the power to the i/o bus is lacking. This can result in starnge issues. Both EL9227-5500 and EL9221-5000 have dedicated panels whre status of the over current protection can be seen.

### el7041
### el7041 error/warning
If drive is in error or warning state, further information about the reason for the warning/error can be read from the drive terminal by using the ethercat command. See [command line interface](ethercatcli) for more info.

{{% notice info %}}
Expand Down Expand Up @@ -61,3 +61,67 @@ ethercat upload -m 0 -p 3 --type uint8 0xA010 0x8
# Misc error
ethercat upload -m 0 -p 3 --type uint8 0xA010 0x9
```

The ecmccfg/utils/read_el70xx_diag.sh tool can also be used for reading the diagnostics:
```bash
bash read_el70xx_diag.sh <master_id> <slave_id>
```

Example: master 0, slave 3, drive under voltage warning
```bash
bash read_el7041_diag.sh 0 3

#########################################################
Reading EL70xx status at master id 0 and slave id 3:

Saturated:
0x00 0
Over temperature:
0x00 0
Torque overload:
0x00 0
Under voltage:
0x01 1
Over voltage:
0x00 0
Short circuit A:
0x00 0
Short circuit B:
0x00 0
No control power:
0x00 0
Misc error:
0x00 0

#########################################################

```
Note: The tool ecmccfg/utils/PDO_read can also be used for reading the diagnostics.

#### under voltage
Under voltage could be that the drive voltage setting is 48V but the drive is only powered with 24V.

The nominal voltage setting can be changed by the U_NOM_MV macro when applying the component (ecmccomp).

Example: Set nominal voltage to 24V
```
${SCRIPTEXEC} ${ecmccfg_DIR}addSlave.cmd, "HW_DESC=EL7041-0052"
${SCRIPTEXEC} ${ecmccomp_DIR}applyComponent.cmd "COMP=Motor-Generic-2Phase-Stepper, MACROS='I_MAX_MA=1000, I_STDBY_MA=500, U_NOM_MV=24000, R_COIL_MOHM=1230'"
```

#### over voltage
Over voltage could be that the drive voltage setting is 24V but the drive is powered with 48V.

The nominal voltage setting can be changed by the U_NOM_MV macro when applying the component (ecmccomp).

Example: Set nominal voltage to 48V
```
${SCRIPTEXEC} ${ecmccfg_DIR}addSlave.cmd, "HW_DESC=EL7041-0052"
${SCRIPTEXEC} ${ecmccomp_DIR}applyComponent.cmd "COMP=Motor-Generic-2Phase-Stepper, MACROS='I_MAX_MA=1000, I_STDBY_MA=500, U_NOM_MV=48000, R_COIL_MOHM=1230'"
```

{{% notice info %}}
For the EL703x drives the nominal voltage must be set to 24V.
{{% /notice %}}
140 changes: 66 additions & 74 deletions utils/parse_ec_esi_xml.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@

# need system python for libxml2 support with xpath

#- Originally written by Dimaond Light EPICS EtherCAT support.

#- Copied and rewritten/edited by Anders Sandström for use with ecmc (generating hardware support)
#- Originally written for Dimaond light epics ethercat support:
#- Rewritten/edited by Anders Sandström for use with ecmc

import libxml2
import sys

reqs = set()
base = None
verbose = False
printedPDOHeader = False

def parseInt(text):
if text.startswith("#x") or text.startswith("0x"):
Expand Down Expand Up @@ -72,7 +70,7 @@ def getSDOBitSize(node):
bitlen= bitlen.replace(" ", "")
return int(bitlen)

def printEcmcAddEntry(vendor,product,pdo,entry,direction,updateInRT,outputfile):
def printEcmcAddEntry(vendor,product,pdo,entry,direction,updateInRT):
# <TxPdo Fixed="1" Sm="3">
sm = pdo.prop("Sm")
pdoName = getPdoName(pdo)
Expand All @@ -82,70 +80,79 @@ def printEcmcAddEntry(vendor,product,pdo,entry,direction,updateInRT,outputfile):
entrySubIndex = getEntrySubIndex(entry)
dt = getEntryDataType(entry)
dataLen = getEntryBitLen(entry)
print('ecmcConfigOrDie "Cfg.EcAddEntryDT(${ECMC_EC_SLAVE_NUM},0x%x,0x%x,%d,%d,0x%x,0x%x,0x%x,%s_%d,%s,%d)' % (vendor, product, int(direction), int(sm), pdoIndex, entryIndex, entrySubIndex, dt, int(dataLen), entryName ,int(updateInRT) ),file=outputfile)
print('ecmcConfigOrDie "Cfg.EcAddEntryDT(${ECMC_EC_SLAVE_NUM},0x%x,0x%x,%d,%d,0x%x,0x%x,0x%x,%s_%d,%s,%d)' % (vendor, product, int(direction), int(sm), pdoIndex, entryIndex, entrySubIndex, dt, int(dataLen), entryName ,int(updateInRT) ))

def printEcmcAddEntryEmpty(vendor,product,pdo,entry,direction,emptyIndex,outputfile):
def printEcmcAddEntryEmpty(vendor,product,pdo,entry,direction,emptyIndex):
# <TxPdo Fixed="1" Sm="3">
sm = int(pdo.prop("Sm"))
pdoName = getPdoName(pdo)
pdoIndex = getPdoIndex(pdo)
entryName = "ec${ECMC_EC_MASTER_ID}.s${ECMC_EC_SLAVE_NUM}.sm" + str(sm) + ".pdo" + str(pdo) + ".empty" + str(emptyIndex)
entryIndex = getEntryIndex(entry)
dataLen = getEntryBitLen(entry)
print(entry,file=outputfile)

def printPDOHeader(outputfile):
print("#- =================================== ",file=outputfile)
print("#- PDOs ",file=outputfile)
print("#-",file=outputfile)

def printSDOHeader(outputfile):
print("",file=outputfile)
print("#- =================================== ",file=outputfile)
print("#- SDOs ",file=outputfile)
print("#-",file=outputfile)

def printSDO(sdoObject,dtlist,outputfile):
sdoName = getEntryName(sdoObject)
sdoIndex = getEntryIndex(sdoObject)
datatype = getSDODataType(sdoObject)
dataLen = getSDOBitSize(sdoObject)
byteCount = dataLen/8
print(entry)

def printSDO(sdoObject,dtlist):
#print(sdoObject)
sdoName = getEntryName(sdoObject)
sdoIndex = getEntryIndex(sdoObject)
dt = getSDODataType(sdoObject)
dataLen = getSDOBitSize(sdoObject)
byteCount = dataLen/8
bitsExByte = dataLen-byteCount*8
print("#- SDO 0x%x, %s (%d.%d), %s" % (sdoIndex,datatype, byteCount, bitsExByte, sdoName),file=outputfile)
dtlist[datatype].printRecursive(" ",dtlist)
print("SDO 0x%x, %s (%d.%d), %s" % (sdoIndex,dt, byteCount, bitsExByte, sdoName))
# print recursive datatype
dtlist[dt].printRecursive(" ",dtlist)

class ecDataType:
def __init__(self,outputfile):
self.f = outputfile
class ecDataTypeSubItem:
def __init__(self):
self.name = ""
self.subIdx = -1
self.bits = -1
self.bitoffset = -1
self.type = ""
def print(self, indentStr):
self.bytes=self.bits/8
print("%s 0x%x, %s %d.%d %d: %s" % (indentStr,self.subIdx,self.type, self.bytes, self.bits-self.bytes*8,self.bitoffset,self.name))

# Loop until "native" type
def printRecursive(self, indentStr, datatypelist):
self.bytes=self.bits/8
indent=indentStr
while not isinstance(datatypelist[self.type],ecDataTypeItem):
datatypelist[self.type].print(indent)
indent = indent + " "
print("%s 0x%x, %s %d.%d %d: %s" % (indentStr,self.subIdx,self.type, self.bytes, self.bits-self.bytes*8,self.bitoffset,self.name))
#print("%s %s %d.%d: %s" % (indentStr,self.type,self.bytes, self.bits-self.bytes*8, self.name))

class ecDataTypeItem:
def __init__(self):
self.name = ""
self.bits = -1
self.subItems = []
self.bytes = -1

def print(self, indentStr):
self.bytes = self.bits/8
if len(self.subItems) == 0 and self.subIdx >= 0:
print("#- %s 0x%02x %20s %5d.%d (%3d): %s" % (indentStr,self.subIdx, self.type, self.bytes, self.bits-self.bytes*8, self.bitoffset, self.name),file=self.f)
self.bytes=self.bits/8
print("%s %d.%d: %s" % (indentStr,self.bytes, self.bits-self.bytes*8, self.name))
for subItem in self.subItems:
subItem.print(indentStr+ " ")

# Loop until "native" type
def printRecursive(self, indentStr, datatypelist):
self.bytes = self.bits/8
indent = indentStr
self.print(indent)
self.bytes=self.bits/8
print("%s %d.%d: %s" % (indentStr,self.bytes, self.bits-self.bytes*8, self.name))
for subItem in self.subItems:
subItem.printRecursive(indent + " ",datatypelist)
subItem.printRecursive(indentStr+ " ",datatypelist)

def parseDataType(dtnode,outputfilename):
dt = ecDataType(outputfilename)
def parseDataType(dtnode):
dt = ecDataTypeItem()
dt.name = dtnode.xpathEval("Name")[0].content
dt.bits = int(dtnode.xpathEval("BitSize")[0].content)
counter = 0
for subItemNode in dtnode.xpathEval("SubItem"):
subItem = ecDataType(outputfilename)
for subItemNode in dtnode.xpathEval("SubItem"):
#print ("subItemNode")
#print (subItemNode)

subItem = ecDataTypeSubItem()
subItem.subIdxNode = subItemNode.xpathEval("SubIdx")
if len(subItem.subIdxNode)>0:
subItem.subIdx= int(subItem.subIdxNode[0].content)
Expand All @@ -158,9 +165,9 @@ def parseDataType(dtnode,outputfilename):
dt.subItems.append(subItem)
counter = counter+1
return dt


def parseFile(filename, outputfile, list_devices, extraPdos):
printedPDOHeader = False
def parseFile(filename, output, list_devices, extraPdos):
doc = libxml2.parseFile(filename)
vendor = parseInt(doc.xpathEval("//Vendor/Id")[0].content)
for device in doc.xpathEval("//Device"):
Expand Down Expand Up @@ -205,16 +212,10 @@ def parseFile(filename, outputfile, list_devices, extraPdos):
ai.append(getPdoName(txpdo) + "." + getEntryName(entry) )
else:
longin.append(getPdoName(txpdo) + "." + getEntryName(entry) )
if not printedPDOHeader:
printPDOHeader(outputfile)
printedPDOHeader = True
printEcmcAddEntry(vendor,product,txpdo,entry,2,1,outputfile)
printEcmcAddEntry(vendor,product,txpdo,entry,2,1)
elif verbose or True:
if not printedPDOHeader:
printPDOHeader(outputfile)
printedPDOHeader = True
print("Ignoring entry in pdo %s" % getPdoName(txpdo),file=outputfile)
printEcmcAddEntryEmpty(vendor,product,txpdo,entry,2,emptyIndex,outputfile)
print("Ignoring entry in pdo %s" % getPdoName(txpdo))
printEcmcAddEntryEmpty(vendor,product,txpdo,entry,2,emptyIndex)
emptyIndex = emptyIndex + 1
emptyIndex = 0
for rxpdo in device.xpathEval("RxPdo"):
Expand All @@ -230,29 +231,23 @@ def parseFile(filename, outputfile, list_devices, extraPdos):
bo.append(getPdoName(rxpdo) + "." + getEntryName(entry) )
else:
longout.append(getPdoName(rxpdo) + "." + getEntryName(entry) )
if not printedPDOHeader:
printPDOHeader(outputfile)
printedPDOHeader = True

printEcmcAddEntry(vendor,product,rxpdo,entry,1,1,outputfile)
printEcmcAddEntry(vendor,product,rxpdo,entry,1,1)
elif verbose:
if not printedPDOHeader:
printPDOHeader(outputfile)
printedPDOHeader = True
print("Ignoring entry in pdo %s" % getPdoName(txpdo), file=outputfile)
printEcmcAddEntryEmpty(vendor,product,rxpdo,entry,1,emptyIndex,outputfile)
print("Ignoring entry in pdo %s" % getPdoName(txpdo))
printEcmcAddEntryEmpty(vendor,product,rxpdo,entry,1,emptyIndex)
emptyIndex = emptyIndex + 1

for dtnode in device.xpathEval("Profile/Dictionary/DataTypes/DataType"):
dt = parseDataType(dtnode,outputfile)
dt = parseDataType(dtnode)
dt.print(" ")

dataTypeList[dt.name] = dt

printSDOHeader(outputfile)
for sdoObject in device.xpathEval("Profile/Dictionary/Objects/Object"):
printSDO(sdoObject,dataTypeList,outputfile)
printSDO(sdoObject,dataTypeList)


#makeTemplate(ai, longin, longout, bi, bo, output, base, devtype, revision, extraPdos)

def usage(progname):
print("%s: Generate hardware support for ecmc " % progname)
Expand All @@ -261,9 +256,9 @@ def usage(progname):
print(" %s -b <xml-base-dir> -l Lists the devices in the database" % progname)
print("""
%s -b <xml-base-dir> -d <device-type> -r <rev-no> [-p comma-separated-pdo-list] -o output-file
Generates a ecmc hw support snippet in <output-file> for the given device and revision.
Generates a template in <output-file> for the given device and revision.
rev-no must be input as a hex number, e.g. 0x00100000
Use the -p argument to include additional pdos in the snippet
Use the -p argument to include additional pdos in the template
""" % progname)

def parsePdoassignments(s):
Expand Down Expand Up @@ -344,16 +339,13 @@ def parsePdoassignments(s):

assert(list_devices or len(reqs) == 1)
import os
outputfile = open(output, "w")
for f in os.listdir(base):
if f.endswith("xml"):
filename = os.path.join(base, f)
if verbose:
print("Parsing %s" % filename)
parseFile(filename, outputfile, list_devices,
parseFile(filename, output, list_devices,
parsePdoassignments(pdoassignment))
outputfile.close()



# loads chain description, outputs complete config file...
36 changes: 36 additions & 0 deletions utils/read_el70xx_diag.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
MID=$1
SID=$2

echo ""
echo "#########################################################"
echo "Reading EL70xx status at master id $MID and slave id $SID:"
echo ""
echo "Saturated:"
ethercat upload -m $MID -p $SID --type uint8 0xA010 0x1

echo "Over temperature:"
ethercat upload -m $MID -p $SID --type uint8 0xA010 0x2

echo "Torque overload:"
ethercat upload -m $MID -p $SID --type uint8 0xA010 0x3

echo "Under voltage:"
ethercat upload -m $MID -p $SID --type uint8 0xA010 0x4

echo "Over voltage:"
ethercat upload -m $MID -p $SID --type uint8 0xA010 0x5

echo "Short circuit A:"
ethercat upload -m $MID -p $SID --type uint8 0xA010 0x6

echo "Short circuit B:"
ethercat upload -m $MID -p $SID --type uint8 0xA010 0x7

echo "No control power:"
ethercat upload -m $MID -p $SID --type uint8 0xA010 0x8

echo "Misc error:"
ethercat upload -m $MID -p $SID --type uint8 0xA010 0x9
echo ""
echo "#########################################################"
echo ""
Loading

0 comments on commit c4c9929

Please sign in to comment.